潘志宝
2024-09-18 6d9c089cebac440c78573e9fa95190ee9ead674c
提交 | 用户 | 时间
820397 1 /**
H 2  * 判断是否 十六进制颜色值.
3  * 输入形式可为 #fff000 #f00
4  *
5  * @param   String  color   十六进制颜色值
6  * @return  Boolean
7  */
8 export const isHexColor = (color: string) => {
9   const reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-f]{6})$/
10   return reg.test(color)
11 }
12
13 /**
14  * RGB 颜色值转换为 十六进制颜色值.
15  * r, g, 和 b 需要在 [0, 255] 范围内
16  *
17  * @return  String          类似#ff00ff
18  * @param r
19  * @param g
20  * @param b
21  */
22 export const rgbToHex = (r: number, g: number, b: number) => {
23   // tslint:disable-next-line:no-bitwise
24   const hex = ((r << 16) | (g << 8) | b).toString(16)
25   return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex
26 }
27
28 /**
29  * Transform a HEX color to its RGB representation
30  * @param {string} hex The color to transform
31  * @returns The RGB representation of the passed color
32  */
33 export const hexToRGB = (hex: string, opacity?: number) => {
34   let sHex = hex.toLowerCase()
35   if (isHexColor(hex)) {
36     if (sHex.length === 4) {
37       let sColorNew = '#'
38       for (let i = 1; i < 4; i += 1) {
39         sColorNew += sHex.slice(i, i + 1).concat(sHex.slice(i, i + 1))
40       }
41       sHex = sColorNew
42     }
43     const sColorChange: number[] = []
44     for (let i = 1; i < 7; i += 2) {
45       sColorChange.push(parseInt('0x' + sHex.slice(i, i + 2)))
46     }
47     return opacity
48       ? 'RGBA(' + sColorChange.join(',') + ',' + opacity + ')'
49       : 'RGB(' + sColorChange.join(',') + ')'
50   }
51   return sHex
52 }
53
54 export const colorIsDark = (color: string) => {
55   if (!isHexColor(color)) return
56   const [r, g, b] = hexToRGB(color)
57     .replace(/(?:\(|\)|rgb|RGB)*/g, '')
58     .split(',')
59     .map((item) => Number(item))
60   return r * 0.299 + g * 0.578 + b * 0.114 < 192
61 }
62
63 /**
64  * Darkens a HEX color given the passed percentage
65  * @param {string} color The color to process
66  * @param {number} amount The amount to change the color by
67  * @returns {string} The HEX representation of the processed color
68  */
69 export const darken = (color: string, amount: number) => {
70   color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color
71   amount = Math.trunc((255 * amount) / 100)
72   return `#${subtractLight(color.substring(0, 2), amount)}${subtractLight(
73     color.substring(2, 4),
74     amount
75   )}${subtractLight(color.substring(4, 6), amount)}`
76 }
77
78 /**
79  * Lightens a 6 char HEX color according to the passed percentage
80  * @param {string} color The color to change
81  * @param {number} amount The amount to change the color by
82  * @returns {string} The processed color represented as HEX
83  */
84 export const lighten = (color: string, amount: number) => {
85   color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color
86   amount = Math.trunc((255 * amount) / 100)
87   return `#${addLight(color.substring(0, 2), amount)}${addLight(
88     color.substring(2, 4),
89     amount
90   )}${addLight(color.substring(4, 6), amount)}`
91 }
92
93 /* Suma el porcentaje indicado a un color (RR, GG o BB) hexadecimal para aclararlo */
94 /**
95  * Sums the passed percentage to the R, G or B of a HEX color
96  * @param {string} color The color to change
97  * @param {number} amount The amount to change the color by
98  * @returns {string} The processed part of the color
99  */
100 const addLight = (color: string, amount: number) => {
101   const cc = parseInt(color, 16) + amount
102   const c = cc > 255 ? 255 : cc
103   return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
104 }
105
106 /**
107  * Calculates luminance of an rgb color
108  * @param {number} r red
109  * @param {number} g green
110  * @param {number} b blue
111  */
112 const luminanace = (r: number, g: number, b: number) => {
113   const a = [r, g, b].map((v) => {
114     v /= 255
115     return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4)
116   })
117   return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722
118 }
119
120 /**
121  * Calculates contrast between two rgb colors
122  * @param {string} rgb1 rgb color 1
123  * @param {string} rgb2 rgb color 2
124  */
125 const contrast = (rgb1: string[], rgb2: number[]) => {
126   return (
127     (luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) /
128     (luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05)
129   )
130 }
131
132 /**
133  * Determines what the best text color is (black or white) based con the contrast with the background
134  * @param hexColor - Last selected color by the user
135  */
136 export const calculateBestTextColor = (hexColor: string) => {
137   const rgbColor = hexToRGB(hexColor.substring(1))
138   const contrastWithBlack = contrast(rgbColor.split(','), [0, 0, 0])
139
140   return contrastWithBlack >= 12 ? '#000000' : '#FFFFFF'
141 }
142
143 /**
144  * Subtracts the indicated percentage to the R, G or B of a HEX color
145  * @param {string} color The color to change
146  * @param {number} amount The amount to change the color by
147  * @returns {string} The processed part of the color
148  */
149 const subtractLight = (color: string, amount: number) => {
150   const cc = parseInt(color, 16) - amount
151   const c = cc < 0 ? 0 : cc
152   return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
153 }
154
155 // 预设颜色
156 export const PREDEFINE_COLORS = [
157   '#ff4500',
158   '#ff8c00',
159   '#ffd700',
160   '#90ee90',
161   '#00ced1',
162   '#1e90ff',
163   '#c71585',
164   '#409EFF',
165   '#909399',
166   '#C0C4CC',
167   '#b7390b',
168   '#ff7800',
169   '#fad400',
170   '#5b8c5f',
171   '#00babd',
172   '#1f73c3',
173   '#711f57'
174 ]