1 | import LRU from '../core/LRU.js';
|
2 | import { extend, isGradientObject, isString, map } from '../core/util.js';
|
3 | var kCSSColorTable = {
|
4 | 'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],
|
5 | 'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],
|
6 | 'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],
|
7 | 'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],
|
8 | 'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],
|
9 | 'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],
|
10 | 'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],
|
11 | 'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],
|
12 | 'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],
|
13 | 'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],
|
14 | 'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],
|
15 | 'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],
|
16 | 'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],
|
17 | 'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],
|
18 | 'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],
|
19 | 'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],
|
20 | 'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],
|
21 | 'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],
|
22 | 'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],
|
23 | 'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],
|
24 | 'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],
|
25 | 'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],
|
26 | 'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],
|
27 | 'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],
|
28 | 'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],
|
29 | 'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],
|
30 | 'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],
|
31 | 'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],
|
32 | 'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],
|
33 | 'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],
|
34 | 'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],
|
35 | 'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],
|
36 | 'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],
|
37 | 'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],
|
38 | 'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],
|
39 | 'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],
|
40 | 'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],
|
41 | 'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],
|
42 | 'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],
|
43 | 'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],
|
44 | 'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],
|
45 | 'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],
|
46 | 'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],
|
47 | 'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],
|
48 | 'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],
|
49 | 'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],
|
50 | 'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],
|
51 | 'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],
|
52 | 'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],
|
53 | 'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],
|
54 | 'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],
|
55 | 'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],
|
56 | 'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],
|
57 | 'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],
|
58 | 'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],
|
59 | 'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],
|
60 | 'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],
|
61 | 'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],
|
62 | 'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],
|
63 | 'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],
|
64 | 'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],
|
65 | 'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],
|
66 | 'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],
|
67 | 'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],
|
68 | 'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],
|
69 | 'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],
|
70 | 'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],
|
71 | 'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],
|
72 | 'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],
|
73 | 'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],
|
74 | 'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],
|
75 | 'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],
|
76 | 'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],
|
77 | 'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]
|
78 | };
|
79 | function clampCssByte(i) {
|
80 | i = Math.round(i);
|
81 | return i < 0 ? 0 : i > 255 ? 255 : i;
|
82 | }
|
83 | function clampCssAngle(i) {
|
84 | i = Math.round(i);
|
85 | return i < 0 ? 0 : i > 360 ? 360 : i;
|
86 | }
|
87 | function clampCssFloat(f) {
|
88 | return f < 0 ? 0 : f > 1 ? 1 : f;
|
89 | }
|
90 | function parseCssInt(val) {
|
91 | var str = val;
|
92 | if (str.length && str.charAt(str.length - 1) === '%') {
|
93 | return clampCssByte(parseFloat(str) / 100 * 255);
|
94 | }
|
95 | return clampCssByte(parseInt(str, 10));
|
96 | }
|
97 | function parseCssFloat(val) {
|
98 | var str = val;
|
99 | if (str.length && str.charAt(str.length - 1) === '%') {
|
100 | return clampCssFloat(parseFloat(str) / 100);
|
101 | }
|
102 | return clampCssFloat(parseFloat(str));
|
103 | }
|
104 | function cssHueToRgb(m1, m2, h) {
|
105 | if (h < 0) {
|
106 | h += 1;
|
107 | }
|
108 | else if (h > 1) {
|
109 | h -= 1;
|
110 | }
|
111 | if (h * 6 < 1) {
|
112 | return m1 + (m2 - m1) * h * 6;
|
113 | }
|
114 | if (h * 2 < 1) {
|
115 | return m2;
|
116 | }
|
117 | if (h * 3 < 2) {
|
118 | return m1 + (m2 - m1) * (2 / 3 - h) * 6;
|
119 | }
|
120 | return m1;
|
121 | }
|
122 | function lerpNumber(a, b, p) {
|
123 | return a + (b - a) * p;
|
124 | }
|
125 | function setRgba(out, r, g, b, a) {
|
126 | out[0] = r;
|
127 | out[1] = g;
|
128 | out[2] = b;
|
129 | out[3] = a;
|
130 | return out;
|
131 | }
|
132 | function copyRgba(out, a) {
|
133 | out[0] = a[0];
|
134 | out[1] = a[1];
|
135 | out[2] = a[2];
|
136 | out[3] = a[3];
|
137 | return out;
|
138 | }
|
139 | var colorCache = new LRU(20);
|
140 | var lastRemovedArr = null;
|
141 | function putToCache(colorStr, rgbaArr) {
|
142 | if (lastRemovedArr) {
|
143 | copyRgba(lastRemovedArr, rgbaArr);
|
144 | }
|
145 | lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));
|
146 | }
|
147 | export function parse(colorStr, rgbaArr) {
|
148 | if (!colorStr) {
|
149 | return;
|
150 | }
|
151 | rgbaArr = rgbaArr || [];
|
152 | var cached = colorCache.get(colorStr);
|
153 | if (cached) {
|
154 | return copyRgba(rgbaArr, cached);
|
155 | }
|
156 | colorStr = colorStr + '';
|
157 | var str = colorStr.replace(/ /g, '').toLowerCase();
|
158 | if (str in kCSSColorTable) {
|
159 | copyRgba(rgbaArr, kCSSColorTable[str]);
|
160 | putToCache(colorStr, rgbaArr);
|
161 | return rgbaArr;
|
162 | }
|
163 | var strLen = str.length;
|
164 | if (str.charAt(0) === '#') {
|
165 | if (strLen === 4 || strLen === 5) {
|
166 | var iv = parseInt(str.slice(1, 4), 16);
|
167 | if (!(iv >= 0 && iv <= 0xfff)) {
|
168 | setRgba(rgbaArr, 0, 0, 0, 1);
|
169 | return;
|
170 | }
|
171 | setRgba(rgbaArr, ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), (iv & 0xf0) | ((iv & 0xf0) >> 4), (iv & 0xf) | ((iv & 0xf) << 4), strLen === 5 ? parseInt(str.slice(4), 16) / 0xf : 1);
|
172 | putToCache(colorStr, rgbaArr);
|
173 | return rgbaArr;
|
174 | }
|
175 | else if (strLen === 7 || strLen === 9) {
|
176 | var iv = parseInt(str.slice(1, 7), 16);
|
177 | if (!(iv >= 0 && iv <= 0xffffff)) {
|
178 | setRgba(rgbaArr, 0, 0, 0, 1);
|
179 | return;
|
180 | }
|
181 | setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, strLen === 9 ? parseInt(str.slice(7), 16) / 0xff : 1);
|
182 | putToCache(colorStr, rgbaArr);
|
183 | return rgbaArr;
|
184 | }
|
185 | return;
|
186 | }
|
187 | var op = str.indexOf('(');
|
188 | var ep = str.indexOf(')');
|
189 | if (op !== -1 && ep + 1 === strLen) {
|
190 | var fname = str.substr(0, op);
|
191 | var params = str.substr(op + 1, ep - (op + 1)).split(',');
|
192 | var alpha = 1;
|
193 | switch (fname) {
|
194 | case 'rgba':
|
195 | if (params.length !== 4) {
|
196 | return params.length === 3
|
197 | ? setRgba(rgbaArr, +params[0], +params[1], +params[2], 1)
|
198 | : setRgba(rgbaArr, 0, 0, 0, 1);
|
199 | }
|
200 | alpha = parseCssFloat(params.pop());
|
201 | case 'rgb':
|
202 | if (params.length >= 3) {
|
203 | setRgba(rgbaArr, parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), params.length === 3 ? alpha : parseCssFloat(params[3]));
|
204 | putToCache(colorStr, rgbaArr);
|
205 | return rgbaArr;
|
206 | }
|
207 | else {
|
208 | setRgba(rgbaArr, 0, 0, 0, 1);
|
209 | return;
|
210 | }
|
211 | case 'hsla':
|
212 | if (params.length !== 4) {
|
213 | setRgba(rgbaArr, 0, 0, 0, 1);
|
214 | return;
|
215 | }
|
216 | params[3] = parseCssFloat(params[3]);
|
217 | hsla2rgba(params, rgbaArr);
|
218 | putToCache(colorStr, rgbaArr);
|
219 | return rgbaArr;
|
220 | case 'hsl':
|
221 | if (params.length !== 3) {
|
222 | setRgba(rgbaArr, 0, 0, 0, 1);
|
223 | return;
|
224 | }
|
225 | hsla2rgba(params, rgbaArr);
|
226 | putToCache(colorStr, rgbaArr);
|
227 | return rgbaArr;
|
228 | default:
|
229 | return;
|
230 | }
|
231 | }
|
232 | setRgba(rgbaArr, 0, 0, 0, 1);
|
233 | return;
|
234 | }
|
235 | function hsla2rgba(hsla, rgba) {
|
236 | var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;
|
237 | var s = parseCssFloat(hsla[1]);
|
238 | var l = parseCssFloat(hsla[2]);
|
239 | var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
|
240 | var m1 = l * 2 - m2;
|
241 | rgba = rgba || [];
|
242 | setRgba(rgba, clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), clampCssByte(cssHueToRgb(m1, m2, h) * 255), clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), 1);
|
243 | if (hsla.length === 4) {
|
244 | rgba[3] = hsla[3];
|
245 | }
|
246 | return rgba;
|
247 | }
|
248 | function rgba2hsla(rgba) {
|
249 | if (!rgba) {
|
250 | return;
|
251 | }
|
252 | var R = rgba[0] / 255;
|
253 | var G = rgba[1] / 255;
|
254 | var B = rgba[2] / 255;
|
255 | var vMin = Math.min(R, G, B);
|
256 | var vMax = Math.max(R, G, B);
|
257 | var delta = vMax - vMin;
|
258 | var L = (vMax + vMin) / 2;
|
259 | var H;
|
260 | var S;
|
261 | if (delta === 0) {
|
262 | H = 0;
|
263 | S = 0;
|
264 | }
|
265 | else {
|
266 | if (L < 0.5) {
|
267 | S = delta / (vMax + vMin);
|
268 | }
|
269 | else {
|
270 | S = delta / (2 - vMax - vMin);
|
271 | }
|
272 | var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;
|
273 | var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;
|
274 | var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;
|
275 | if (R === vMax) {
|
276 | H = deltaB - deltaG;
|
277 | }
|
278 | else if (G === vMax) {
|
279 | H = (1 / 3) + deltaR - deltaB;
|
280 | }
|
281 | else if (B === vMax) {
|
282 | H = (2 / 3) + deltaG - deltaR;
|
283 | }
|
284 | if (H < 0) {
|
285 | H += 1;
|
286 | }
|
287 | if (H > 1) {
|
288 | H -= 1;
|
289 | }
|
290 | }
|
291 | var hsla = [H * 360, S, L];
|
292 | if (rgba[3] != null) {
|
293 | hsla.push(rgba[3]);
|
294 | }
|
295 | return hsla;
|
296 | }
|
297 | export function lift(color, level) {
|
298 | var colorArr = parse(color);
|
299 | if (colorArr) {
|
300 | for (var i = 0; i < 3; i++) {
|
301 | if (level < 0) {
|
302 | colorArr[i] = colorArr[i] * (1 - level) | 0;
|
303 | }
|
304 | else {
|
305 | colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;
|
306 | }
|
307 | if (colorArr[i] > 255) {
|
308 | colorArr[i] = 255;
|
309 | }
|
310 | else if (colorArr[i] < 0) {
|
311 | colorArr[i] = 0;
|
312 | }
|
313 | }
|
314 | return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
|
315 | }
|
316 | }
|
317 | export function toHex(color) {
|
318 | var colorArr = parse(color);
|
319 | if (colorArr) {
|
320 | return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);
|
321 | }
|
322 | }
|
323 | export function fastLerp(normalizedValue, colors, out) {
|
324 | if (!(colors && colors.length)
|
325 | || !(normalizedValue >= 0 && normalizedValue <= 1)) {
|
326 | return;
|
327 | }
|
328 | out = out || [];
|
329 | var value = normalizedValue * (colors.length - 1);
|
330 | var leftIndex = Math.floor(value);
|
331 | var rightIndex = Math.ceil(value);
|
332 | var leftColor = colors[leftIndex];
|
333 | var rightColor = colors[rightIndex];
|
334 | var dv = value - leftIndex;
|
335 | out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));
|
336 | out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));
|
337 | out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));
|
338 | out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));
|
339 | return out;
|
340 | }
|
341 | export var fastMapToColor = fastLerp;
|
342 | export function lerp(normalizedValue, colors, fullOutput) {
|
343 | if (!(colors && colors.length)
|
344 | || !(normalizedValue >= 0 && normalizedValue <= 1)) {
|
345 | return;
|
346 | }
|
347 | var value = normalizedValue * (colors.length - 1);
|
348 | var leftIndex = Math.floor(value);
|
349 | var rightIndex = Math.ceil(value);
|
350 | var leftColor = parse(colors[leftIndex]);
|
351 | var rightColor = parse(colors[rightIndex]);
|
352 | var dv = value - leftIndex;
|
353 | var color = stringify([
|
354 | clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),
|
355 | clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),
|
356 | clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),
|
357 | clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))
|
358 | ], 'rgba');
|
359 | return fullOutput
|
360 | ? {
|
361 | color: color,
|
362 | leftIndex: leftIndex,
|
363 | rightIndex: rightIndex,
|
364 | value: value
|
365 | }
|
366 | : color;
|
367 | }
|
368 | export var mapToColor = lerp;
|
369 | export function modifyHSL(color, h, s, l) {
|
370 | var colorArr = parse(color);
|
371 | if (color) {
|
372 | colorArr = rgba2hsla(colorArr);
|
373 | h != null && (colorArr[0] = clampCssAngle(h));
|
374 | s != null && (colorArr[1] = parseCssFloat(s));
|
375 | l != null && (colorArr[2] = parseCssFloat(l));
|
376 | return stringify(hsla2rgba(colorArr), 'rgba');
|
377 | }
|
378 | }
|
379 | export function modifyAlpha(color, alpha) {
|
380 | var colorArr = parse(color);
|
381 | if (colorArr && alpha != null) {
|
382 | colorArr[3] = clampCssFloat(alpha);
|
383 | return stringify(colorArr, 'rgba');
|
384 | }
|
385 | }
|
386 | export function stringify(arrColor, type) {
|
387 | if (!arrColor || !arrColor.length) {
|
388 | return;
|
389 | }
|
390 | var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];
|
391 | if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
|
392 | colorStr += ',' + arrColor[3];
|
393 | }
|
394 | return type + '(' + colorStr + ')';
|
395 | }
|
396 | export function lum(color, backgroundLum) {
|
397 | var arr = parse(color);
|
398 | return arr
|
399 | ? (0.299 * arr[0] + 0.587 * arr[1] + 0.114 * arr[2]) * arr[3] / 255
|
400 | + (1 - arr[3]) * backgroundLum
|
401 | : 0;
|
402 | }
|
403 | export function random() {
|
404 | return stringify([
|
405 | Math.round(Math.random() * 255),
|
406 | Math.round(Math.random() * 255),
|
407 | Math.round(Math.random() * 255)
|
408 | ], 'rgb');
|
409 | }
|
410 | var liftedColorCache = new LRU(100);
|
411 | export function liftColor(color) {
|
412 | if (isString(color)) {
|
413 | var liftedColor = liftedColorCache.get(color);
|
414 | if (!liftedColor) {
|
415 | liftedColor = lift(color, -0.1);
|
416 | liftedColorCache.put(color, liftedColor);
|
417 | }
|
418 | return liftedColor;
|
419 | }
|
420 | else if (isGradientObject(color)) {
|
421 | var ret = extend({}, color);
|
422 | ret.colorStops = map(color.colorStops, function (stop) { return ({
|
423 | offset: stop.offset,
|
424 | color: lift(stop.color, -0.1)
|
425 | }); });
|
426 | return ret;
|
427 | }
|
428 | return color;
|
429 | }
|