UNPKG

36.6 kBtext/lessView Raw
1/* stylelint-disable declaration-bang-space-before,no-duplicate-selectors */
2.tinyColorMixin() {
3@functions: ~`(function() {
4// TinyColor v1.4.1
5// https://github.com/bgrins/TinyColor
6// 2016-07-07, Brian Grinstead, MIT License
7var trimLeft = /^\s+/,
8 trimRight = /\s+$/,
9 tinyCounter = 0,
10 mathRound = Math.round,
11 mathMin = Math.min,
12 mathMax = Math.max,
13 mathRandom = Math.random;
14
15function tinycolor (color, opts) {
16
17 color = (color) ? color : '';
18 opts = opts || { };
19
20 // If input is already a tinycolor, return itself
21 if (color instanceof tinycolor) {
22 return color;
23 }
24 // If we are called as a function, call using new instead
25 if (!(this instanceof tinycolor)) {
26 return new tinycolor(color, opts);
27 }
28
29 var rgb = inputToRGB(color);
30 this._originalInput = color,
31 this._r = rgb.r,
32 this._g = rgb.g,
33 this._b = rgb.b,
34 this._a = rgb.a,
35 this._roundA = mathRound(100*this._a) / 100,
36 this._format = opts.format || rgb.format;
37 this._gradientType = opts.gradientType;
38
39 // Don't let the range of [0,255] come back in [0,1].
40 // Potentially lose a little bit of precision here, but will fix issues where
41 // .5 gets interpreted as half of the total, instead of half of 1
42 // If it was supposed to be 128, this was already taken care of by inputToRgb
43 if (this._r < 1) { this._r = mathRound(this._r); }
44 if (this._g < 1) { this._g = mathRound(this._g); }
45 if (this._b < 1) { this._b = mathRound(this._b); }
46
47 this._ok = rgb.ok;
48 this._tc_id = tinyCounter++;
49}
50
51tinycolor.prototype = {
52 isDark: function() {
53 return this.getBrightness() < 128;
54 },
55 isLight: function() {
56 return !this.isDark();
57 },
58 isValid: function() {
59 return this._ok;
60 },
61 getOriginalInput: function() {
62 return this._originalInput;
63 },
64 getFormat: function() {
65 return this._format;
66 },
67 getAlpha: function() {
68 return this._a;
69 },
70 getBrightness: function() {
71 //http://www.w3.org/TR/AERT#color-contrast
72 var rgb = this.toRgb();
73 return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
74 },
75 getLuminance: function() {
76 //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
77 var rgb = this.toRgb();
78 var RsRGB, GsRGB, BsRGB, R, G, B;
79 RsRGB = rgb.r/255;
80 GsRGB = rgb.g/255;
81 BsRGB = rgb.b/255;
82
83 if (RsRGB <= 0.03928) {R = RsRGB / 12.92;} else {R = Math.pow(((RsRGB + 0.055) / 1.055), 2.4);}
84 if (GsRGB <= 0.03928) {G = GsRGB / 12.92;} else {G = Math.pow(((GsRGB + 0.055) / 1.055), 2.4);}
85 if (BsRGB <= 0.03928) {B = BsRGB / 12.92;} else {B = Math.pow(((BsRGB + 0.055) / 1.055), 2.4);}
86 return (0.2126 * R) + (0.7152 * G) + (0.0722 * B);
87 },
88 setAlpha: function(value) {
89 this._a = boundAlpha(value);
90 this._roundA = mathRound(100*this._a) / 100;
91 return this;
92 },
93 toHsv: function() {
94 var hsv = rgbToHsv(this._r, this._g, this._b);
95 return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
96 },
97 toHsvString: function() {
98 var hsv = rgbToHsv(this._r, this._g, this._b);
99 var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
100 return (this._a == 1) ?
101 "hsv(" + h + ", " + s + "%, " + v + "%)" :
102 "hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")";
103 },
104 toHsl: function() {
105 var hsl = rgbToHsl(this._r, this._g, this._b);
106 return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
107 },
108 toHslString: function() {
109 var hsl = rgbToHsl(this._r, this._g, this._b);
110 var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
111 return (this._a == 1) ?
112 "hsl(" + h + ", " + s + "%, " + l + "%)" :
113 "hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")";
114 },
115 toHex: function(allow3Char) {
116 return rgbToHex(this._r, this._g, this._b, allow3Char);
117 },
118 toHexString: function(allow3Char) {
119 return '#' + this.toHex(allow3Char);
120 },
121 toHex8: function(allow4Char) {
122 return rgbaToHex(this._r, this._g, this._b, this._a, allow4Char);
123 },
124 toHex8String: function(allow4Char) {
125 return '#' + this.toHex8(allow4Char);
126 },
127 toRgb: function() {
128 return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
129 },
130 toRgbString: function() {
131 return (this._a == 1) ?
132 "rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" :
133 "rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")";
134 },
135 toPercentageRgb: function() {
136 return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a };
137 },
138 toPercentageRgbString: function() {
139 return (this._a == 1) ?
140 "rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" :
141 "rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")";
142 },
143 toName: function() {
144 if (this._a === 0) {
145 return "transparent";
146 }
147
148 if (this._a < 1) {
149 return false;
150 }
151
152 return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
153 },
154 toFilter: function(secondColor) {
155 var hex8String = '#' + rgbaToArgbHex(this._r, this._g, this._b, this._a);
156 var secondHex8String = hex8String;
157 var gradientType = this._gradientType ? "GradientType = 1, " : "";
158
159 if (secondColor) {
160 var s = tinycolor(secondColor);
161 secondHex8String = '#' + rgbaToArgbHex(s._r, s._g, s._b, s._a);
162 }
163
164 return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")";
165 },
166 toString: function(format) {
167 var formatSet = !!format;
168 format = format || this._format;
169
170 var formattedString = false;
171 var hasAlpha = this._a < 1 && this._a >= 0;
172 var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "hex4" || format === "hex8" || format === "name");
173
174 if (needsAlphaFormat) {
175 // Special case for "transparent", all other non-alpha formats
176 // will return rgba when there is transparency.
177 if (format === "name" && this._a === 0) {
178 return this.toName();
179 }
180 return this.toRgbString();
181 }
182 if (format === "rgb") {
183 formattedString = this.toRgbString();
184 }
185 if (format === "prgb") {
186 formattedString = this.toPercentageRgbString();
187 }
188 if (format === "hex" || format === "hex6") {
189 formattedString = this.toHexString();
190 }
191 if (format === "hex3") {
192 formattedString = this.toHexString(true);
193 }
194 if (format === "hex4") {
195 formattedString = this.toHex8String(true);
196 }
197 if (format === "hex8") {
198 formattedString = this.toHex8String();
199 }
200 if (format === "name") {
201 formattedString = this.toName();
202 }
203 if (format === "hsl") {
204 formattedString = this.toHslString();
205 }
206 if (format === "hsv") {
207 formattedString = this.toHsvString();
208 }
209
210 return formattedString || this.toHexString();
211 },
212 clone: function() {
213 return tinycolor(this.toString());
214 },
215
216 _applyModification: function(fn, args) {
217 var color = fn.apply(null, [this].concat([].slice.call(args)));
218 this._r = color._r;
219 this._g = color._g;
220 this._b = color._b;
221 this.setAlpha(color._a);
222 return this;
223 },
224 lighten: function() {
225 return this._applyModification(lighten, arguments);
226 },
227 brighten: function() {
228 return this._applyModification(brighten, arguments);
229 },
230 darken: function() {
231 return this._applyModification(darken, arguments);
232 },
233 desaturate: function() {
234 return this._applyModification(desaturate, arguments);
235 },
236 saturate: function() {
237 return this._applyModification(saturate, arguments);
238 },
239 greyscale: function() {
240 return this._applyModification(greyscale, arguments);
241 },
242 spin: function() {
243 return this._applyModification(spin, arguments);
244 },
245
246 _applyCombination: function(fn, args) {
247 return fn.apply(null, [this].concat([].slice.call(args)));
248 },
249 analogous: function() {
250 return this._applyCombination(analogous, arguments);
251 },
252 complement: function() {
253 return this._applyCombination(complement, arguments);
254 },
255 monochromatic: function() {
256 return this._applyCombination(monochromatic, arguments);
257 },
258 splitcomplement: function() {
259 return this._applyCombination(splitcomplement, arguments);
260 },
261 triad: function() {
262 return this._applyCombination(triad, arguments);
263 },
264 tetrad: function() {
265 return this._applyCombination(tetrad, arguments);
266 }
267};
268
269// If input is an object, force 1 into "1.0" to handle ratios properly
270// String input requires "1.0" as input, so 1 will be treated as 1
271tinycolor.fromRatio = function(color, opts) {
272 if (typeof color == "object") {
273 var newColor = {};
274 for (var i in color) {
275 if (color.hasOwnProperty(i)) {
276 if (i === "a") {
277 newColor[i] = color[i];
278 }
279 else {
280 newColor[i] = convertToPercentage(color[i]);
281 }
282 }
283 }
284 color = newColor;
285 }
286
287 return tinycolor(color, opts);
288};
289
290// Given a string or object, convert that input to RGB
291// Possible string inputs:
292//
293// "red"
294// "#f00" or "f00"
295// "#ff0000" or "ff0000"
296// "#ff000000" or "ff000000"
297// "rgb 255 0 0" or "rgb (255, 0, 0)"
298// "rgb 1.0 0 0" or "rgb (1, 0, 0)"
299// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
300// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
301// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
302// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
303// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
304//
305function inputToRGB(color) {
306
307 var rgb = { r: 0, g: 0, b: 0 };
308 var a = 1;
309 var s = null;
310 var v = null;
311 var l = null;
312 var ok = false;
313 var format = false;
314
315 if (typeof color == "string") {
316 color = stringInputToObject(color);
317 }
318
319 if (typeof color == "object") {
320 if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
321 rgb = rgbToRgb(color.r, color.g, color.b);
322 ok = true;
323 format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
324 }
325 else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
326 s = convertToPercentage(color.s);
327 v = convertToPercentage(color.v);
328 rgb = hsvToRgb(color.h, s, v);
329 ok = true;
330 format = "hsv";
331 }
332 else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
333 s = convertToPercentage(color.s);
334 l = convertToPercentage(color.l);
335 rgb = hslToRgb(color.h, s, l);
336 ok = true;
337 format = "hsl";
338 }
339
340 if (color.hasOwnProperty("a")) {
341 a = color.a;
342 }
343 }
344
345 a = boundAlpha(a);
346
347 return {
348 ok: ok,
349 format: color.format || format,
350 r: mathMin(255, mathMax(rgb.r, 0)),
351 g: mathMin(255, mathMax(rgb.g, 0)),
352 b: mathMin(255, mathMax(rgb.b, 0)),
353 a: a
354 };
355}
356
357// Conversion Functions
358// --------------------
359
360// rgbToHsl, rgbToHsv, hslToRgb, hsvToRgb modified from:
361// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
362
363// rgbToRgb
364// Handle bounds / percentage checking to conform to CSS color spec
365// <http://www.w3.org/TR/css3-color/>
366// *Assumes:* r, g, b in [0, 255] or [0, 1]
367// *Returns:* { r, g, b } in [0, 255]
368function rgbToRgb(r, g, b){
369 return {
370 r: bound01(r, 255) * 255,
371 g: bound01(g, 255) * 255,
372 b: bound01(b, 255) * 255
373 };
374}
375
376// rgbToHsl
377// Converts an RGB color value to HSL.
378// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
379// *Returns:* { h, s, l } in [0,1]
380function rgbToHsl(r, g, b) {
381
382 r = bound01(r, 255);
383 g = bound01(g, 255);
384 b = bound01(b, 255);
385
386 var max = mathMax(r, g, b), min = mathMin(r, g, b);
387 var h, s, l = (max + min) / 2;
388
389 if(max == min) {
390 h = s = 0; // achromatic
391 }
392 else {
393 var d = max - min;
394 s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
395 switch(max) {
396 case r: h = (g - b) / d + (g < b ? 6 : 0); break;
397 case g: h = (b - r) / d + 2; break;
398 case b: h = (r - g) / d + 4; break;
399 }
400
401 h /= 6;
402 }
403
404 return { h: h, s: s, l: l };
405}
406
407// hslToRgb
408// Converts an HSL color value to RGB.
409// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
410// *Returns:* { r, g, b } in the set [0, 255]
411function hslToRgb(h, s, l) {
412 var r, g, b;
413
414 h = bound01(h, 360);
415 s = bound01(s, 100);
416 l = bound01(l, 100);
417
418 function hue2rgb(p, q, t) {
419 if(t < 0) t += 1;
420 if(t > 1) t -= 1;
421 if(t < 1/6) return p + (q - p) * 6 * t;
422 if(t < 1/2) return q;
423 if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
424 return p;
425 }
426
427 if(s === 0) {
428 r = g = b = l; // achromatic
429 }
430 else {
431 var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
432 var p = 2 * l - q;
433 r = hue2rgb(p, q, h + 1/3);
434 g = hue2rgb(p, q, h);
435 b = hue2rgb(p, q, h - 1/3);
436 }
437
438 return { r: r * 255, g: g * 255, b: b * 255 };
439}
440
441// rgbToHsv
442// Converts an RGB color value to HSV
443// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
444// *Returns:* { h, s, v } in [0,1]
445function rgbToHsv(r, g, b) {
446
447 r = bound01(r, 255);
448 g = bound01(g, 255);
449 b = bound01(b, 255);
450
451 var max = mathMax(r, g, b), min = mathMin(r, g, b);
452 var h, s, v = max;
453
454 var d = max - min;
455 s = max === 0 ? 0 : d / max;
456
457 if(max == min) {
458 h = 0; // achromatic
459 }
460 else {
461 switch(max) {
462 case r: h = (g - b) / d + (g < b ? 6 : 0); break;
463 case g: h = (b - r) / d + 2; break;
464 case b: h = (r - g) / d + 4; break;
465 }
466 h /= 6;
467 }
468 return { h: h, s: s, v: v };
469}
470
471// hsvToRgb
472// Converts an HSV color value to RGB.
473// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
474// *Returns:* { r, g, b } in the set [0, 255]
475 function hsvToRgb(h, s, v) {
476
477 h = bound01(h, 360) * 6;
478 s = bound01(s, 100);
479 v = bound01(v, 100);
480
481 var i = Math.floor(h),
482 f = h - i,
483 p = v * (1 - s),
484 q = v * (1 - f * s),
485 t = v * (1 - (1 - f) * s),
486 mod = i % 6,
487 r = [v, q, p, p, t, v][mod],
488 g = [t, v, v, q, p, p][mod],
489 b = [p, p, t, v, v, q][mod];
490
491 return { r: r * 255, g: g * 255, b: b * 255 };
492}
493
494// rgbToHex
495// Converts an RGB color to hex
496// Assumes r, g, and b are contained in the set [0, 255]
497// Returns a 3 or 6 character hex
498function rgbToHex(r, g, b, allow3Char) {
499
500 var hex = [
501 pad2(mathRound(r).toString(16)),
502 pad2(mathRound(g).toString(16)),
503 pad2(mathRound(b).toString(16))
504 ];
505
506 // Return a 3 character hex if possible
507 if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
508 return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
509 }
510
511 return hex.join("");
512}
513
514// rgbaToHex
515// Converts an RGBA color plus alpha transparency to hex
516// Assumes r, g, b are contained in the set [0, 255] and
517// a in [0, 1]. Returns a 4 or 8 character rgba hex
518function rgbaToHex(r, g, b, a, allow4Char) {
519
520 var hex = [
521 pad2(mathRound(r).toString(16)),
522 pad2(mathRound(g).toString(16)),
523 pad2(mathRound(b).toString(16)),
524 pad2(convertDecimalToHex(a))
525 ];
526
527 // Return a 4 character hex if possible
528 if (allow4Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1) && hex[3].charAt(0) == hex[3].charAt(1)) {
529 return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
530 }
531
532 return hex.join("");
533}
534
535// rgbaToArgbHex
536// Converts an RGBA color to an ARGB Hex8 string
537// Rarely used, but required for "toFilter()"
538function rgbaToArgbHex(r, g, b, a) {
539
540 var hex = [
541 pad2(convertDecimalToHex(a)),
542 pad2(mathRound(r).toString(16)),
543 pad2(mathRound(g).toString(16)),
544 pad2(mathRound(b).toString(16))
545 ];
546
547 return hex.join("");
548}
549
550// equals
551// Can be called with any tinycolor input
552tinycolor.equals = function (color1, color2) {
553 if (!color1 || !color2) { return false; }
554 return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
555};
556
557tinycolor.random = function() {
558 return tinycolor.fromRatio({
559 r: mathRandom(),
560 g: mathRandom(),
561 b: mathRandom()
562 });
563};
564
565// Modification Functions
566// ----------------------
567// Thanks to less.js for some of the basics here
568// <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
569
570function desaturate(color, amount) {
571 amount = (amount === 0) ? 0 : (amount || 10);
572 var hsl = tinycolor(color).toHsl();
573 hsl.s -= amount / 100;
574 hsl.s = clamp01(hsl.s);
575 return tinycolor(hsl);
576}
577
578function saturate(color, amount) {
579 amount = (amount === 0) ? 0 : (amount || 10);
580 var hsl = tinycolor(color).toHsl();
581 hsl.s += amount / 100;
582 hsl.s = clamp01(hsl.s);
583 return tinycolor(hsl);
584}
585
586function greyscale(color) {
587 return tinycolor(color).desaturate(100);
588}
589
590function lighten (color, amount) {
591 amount = (amount === 0) ? 0 : (amount || 10);
592 var hsl = tinycolor(color).toHsl();
593 hsl.l += amount / 100;
594 hsl.l = clamp01(hsl.l);
595 return tinycolor(hsl);
596}
597
598function brighten(color, amount) {
599 amount = (amount === 0) ? 0 : (amount || 10);
600 var rgb = tinycolor(color).toRgb();
601 rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));
602 rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));
603 rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));
604 return tinycolor(rgb);
605}
606
607function darken (color, amount) {
608 amount = (amount === 0) ? 0 : (amount || 10);
609 var hsl = tinycolor(color).toHsl();
610 hsl.l -= amount / 100;
611 hsl.l = clamp01(hsl.l);
612 return tinycolor(hsl);
613}
614
615// Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
616// Values outside of this range will be wrapped into this range.
617function spin(color, amount) {
618 var hsl = tinycolor(color).toHsl();
619 var hue = (hsl.h + amount) % 360;
620 hsl.h = hue < 0 ? 360 + hue : hue;
621 return tinycolor(hsl);
622}
623
624// Combination Functions
625// ---------------------
626// Thanks to jQuery xColor for some of the ideas behind these
627// <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
628
629function complement(color) {
630 var hsl = tinycolor(color).toHsl();
631 hsl.h = (hsl.h + 180) % 360;
632 return tinycolor(hsl);
633}
634
635function triad(color) {
636 var hsl = tinycolor(color).toHsl();
637 var h = hsl.h;
638 return [
639 tinycolor(color),
640 tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
641 tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
642 ];
643}
644
645function tetrad(color) {
646 var hsl = tinycolor(color).toHsl();
647 var h = hsl.h;
648 return [
649 tinycolor(color),
650 tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
651 tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
652 tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
653 ];
654}
655
656function splitcomplement(color) {
657 var hsl = tinycolor(color).toHsl();
658 var h = hsl.h;
659 return [
660 tinycolor(color),
661 tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}),
662 tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l})
663 ];
664}
665
666function analogous(color, results, slices) {
667 results = results || 6;
668 slices = slices || 30;
669
670 var hsl = tinycolor(color).toHsl();
671 var part = 360 / slices;
672 var ret = [tinycolor(color)];
673
674 for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
675 hsl.h = (hsl.h + part) % 360;
676 ret.push(tinycolor(hsl));
677 }
678 return ret;
679}
680
681function monochromatic(color, results) {
682 results = results || 6;
683 var hsv = tinycolor(color).toHsv();
684 var h = hsv.h, s = hsv.s, v = hsv.v;
685 var ret = [];
686 var modification = 1 / results;
687
688 while (results--) {
689 ret.push(tinycolor({ h: h, s: s, v: v}));
690 v = (v + modification) % 1;
691 }
692
693 return ret;
694}
695
696// Utility Functions
697// ---------------------
698
699tinycolor.mix = function(color1, color2, amount) {
700 amount = (amount === 0) ? 0 : (amount || 50);
701
702 var rgb1 = tinycolor(color1).toRgb();
703 var rgb2 = tinycolor(color2).toRgb();
704
705 var p = amount / 100;
706
707 var rgba = {
708 r: ((rgb2.r - rgb1.r) * p) + rgb1.r,
709 g: ((rgb2.g - rgb1.g) * p) + rgb1.g,
710 b: ((rgb2.b - rgb1.b) * p) + rgb1.b,
711 a: ((rgb2.a - rgb1.a) * p) + rgb1.a
712 };
713
714 return tinycolor(rgba);
715};
716
717// Readability Functions
718// ---------------------
719// <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
720
721// contrast
722// Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2)
723tinycolor.readability = function(color1, color2) {
724 var c1 = tinycolor(color1);
725 var c2 = tinycolor(color2);
726 return (Math.max(c1.getLuminance(),c2.getLuminance())+0.05) / (Math.min(c1.getLuminance(),c2.getLuminance())+0.05);
727};
728
729// isReadable
730// Ensure that foreground and background color combinations meet WCAG2 guidelines.
731// The third argument is an optional Object.
732// the 'level' property states 'AA' or 'AAA' - if missing or invalid, it defaults to 'AA';
733// the 'size' property states 'large' or 'small' - if missing or invalid, it defaults to 'small'.
734// If the entire object is absent, isReadable defaults to {level:"AA",size:"small"}.
735
736// *Example*
737// tinycolor.isReadable("#000", "#111") => false
738// tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false
739tinycolor.isReadable = function(color1, color2, wcag2) {
740 var readability = tinycolor.readability(color1, color2);
741 var wcag2Parms, out;
742
743 out = false;
744
745 wcag2Parms = validateWCAG2Parms(wcag2);
746 switch (wcag2Parms.level + wcag2Parms.size) {
747 case "AAsmall":
748 case "AAAlarge":
749 out = readability >= 4.5;
750 break;
751 case "AAlarge":
752 out = readability >= 3;
753 break;
754 case "AAAsmall":
755 out = readability >= 7;
756 break;
757 }
758 return out;
759
760};
761
762// mostReadable
763// Given a base color and a list of possible foreground or background
764// colors for that base, returns the most readable color.
765// Optionally returns Black or White if the most readable color is unreadable.
766// *Example*
767// tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255"
768// tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff"
769// tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3"
770// tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff"
771tinycolor.mostReadable = function(baseColor, colorList, args) {
772 var bestColor = null;
773 var bestScore = 0;
774 var readability;
775 var includeFallbackColors, level, size ;
776 args = args || {};
777 includeFallbackColors = args.includeFallbackColors ;
778 level = args.level;
779 size = args.size;
780
781 for (var i= 0; i < colorList.length ; i++) {
782 readability = tinycolor.readability(baseColor, colorList[i]);
783 if (readability > bestScore) {
784 bestScore = readability;
785 bestColor = tinycolor(colorList[i]);
786 }
787 }
788
789 if (tinycolor.isReadable(baseColor, bestColor, {"level":level,"size":size}) || !includeFallbackColors) {
790 return bestColor;
791 }
792 else {
793 args.includeFallbackColors=false;
794 return tinycolor.mostReadable(baseColor,["#fff", "#000"],args);
795 }
796};
797
798// Big List of Colors
799// ------------------
800// <http://www.w3.org/TR/css3-color/#svg-color>
801var names = tinycolor.names = {
802 aliceblue: "f0f8ff",
803 antiquewhite: "faebd7",
804 aqua: "0ff",
805 aquamarine: "7fffd4",
806 azure: "f0ffff",
807 beige: "f5f5dc",
808 bisque: "ffe4c4",
809 black: "000",
810 blanchedalmond: "ffebcd",
811 blue: "00f",
812 blueviolet: "8a2be2",
813 brown: "a52a2a",
814 burlywood: "deb887",
815 burntsienna: "ea7e5d",
816 cadetblue: "5f9ea0",
817 chartreuse: "7fff00",
818 chocolate: "d2691e",
819 coral: "ff7f50",
820 cornflowerblue: "6495ed",
821 cornsilk: "fff8dc",
822 crimson: "dc143c",
823 cyan: "0ff",
824 darkblue: "00008b",
825 darkcyan: "008b8b",
826 darkgoldenrod: "b8860b",
827 darkgray: "a9a9a9",
828 darkgreen: "006400",
829 darkgrey: "a9a9a9",
830 darkkhaki: "bdb76b",
831 darkmagenta: "8b008b",
832 darkolivegreen: "556b2f",
833 darkorange: "ff8c00",
834 darkorchid: "9932cc",
835 darkred: "8b0000",
836 darksalmon: "e9967a",
837 darkseagreen: "8fbc8f",
838 darkslateblue: "483d8b",
839 darkslategray: "2f4f4f",
840 darkslategrey: "2f4f4f",
841 darkturquoise: "00ced1",
842 darkviolet: "9400d3",
843 deeppink: "ff1493",
844 deepskyblue: "00bfff",
845 dimgray: "696969",
846 dimgrey: "696969",
847 dodgerblue: "1e90ff",
848 firebrick: "b22222",
849 floralwhite: "fffaf0",
850 forestgreen: "228b22",
851 fuchsia: "f0f",
852 gainsboro: "dcdcdc",
853 ghostwhite: "f8f8ff",
854 gold: "ffd700",
855 goldenrod: "daa520",
856 gray: "808080",
857 green: "008000",
858 greenyellow: "adff2f",
859 grey: "808080",
860 honeydew: "f0fff0",
861 hotpink: "ff69b4",
862 indianred: "cd5c5c",
863 indigo: "4b0082",
864 ivory: "fffff0",
865 khaki: "f0e68c",
866 lavender: "e6e6fa",
867 lavenderblush: "fff0f5",
868 lawngreen: "7cfc00",
869 lemonchiffon: "fffacd",
870 lightblue: "add8e6",
871 lightcoral: "f08080",
872 lightcyan: "e0ffff",
873 lightgoldenrodyellow: "fafad2",
874 lightgray: "d3d3d3",
875 lightgreen: "90ee90",
876 lightgrey: "d3d3d3",
877 lightpink: "ffb6c1",
878 lightsalmon: "ffa07a",
879 lightseagreen: "20b2aa",
880 lightskyblue: "87cefa",
881 lightslategray: "789",
882 lightslategrey: "789",
883 lightsteelblue: "b0c4de",
884 lightyellow: "ffffe0",
885 lime: "0f0",
886 limegreen: "32cd32",
887 linen: "faf0e6",
888 magenta: "f0f",
889 maroon: "800000",
890 mediumaquamarine: "66cdaa",
891 mediumblue: "0000cd",
892 mediumorchid: "ba55d3",
893 mediumpurple: "9370db",
894 mediumseagreen: "3cb371",
895 mediumslateblue: "7b68ee",
896 mediumspringgreen: "00fa9a",
897 mediumturquoise: "48d1cc",
898 mediumvioletred: "c71585",
899 midnightblue: "191970",
900 mintcream: "f5fffa",
901 mistyrose: "ffe4e1",
902 moccasin: "ffe4b5",
903 navajowhite: "ffdead",
904 navy: "000080",
905 oldlace: "fdf5e6",
906 olive: "808000",
907 olivedrab: "6b8e23",
908 orange: "ffa500",
909 orangered: "ff4500",
910 orchid: "da70d6",
911 palegoldenrod: "eee8aa",
912 palegreen: "98fb98",
913 paleturquoise: "afeeee",
914 palevioletred: "db7093",
915 papayawhip: "ffefd5",
916 peachpuff: "ffdab9",
917 peru: "cd853f",
918 pink: "ffc0cb",
919 plum: "dda0dd",
920 powderblue: "b0e0e6",
921 purple: "800080",
922 rebeccapurple: "663399",
923 red: "f00",
924 rosybrown: "bc8f8f",
925 royalblue: "4169e1",
926 saddlebrown: "8b4513",
927 salmon: "fa8072",
928 sandybrown: "f4a460",
929 seagreen: "2e8b57",
930 seashell: "fff5ee",
931 sienna: "a0522d",
932 silver: "c0c0c0",
933 skyblue: "87ceeb",
934 slateblue: "6a5acd",
935 slategray: "708090",
936 slategrey: "708090",
937 snow: "fffafa",
938 springgreen: "00ff7f",
939 steelblue: "4682b4",
940 tan: "d2b48c",
941 teal: "008080",
942 thistle: "d8bfd8",
943 tomato: "ff6347",
944 turquoise: "40e0d0",
945 violet: "ee82ee",
946 wheat: "f5deb3",
947 white: "fff",
948 whitesmoke: "f5f5f5",
949 yellow: "ff0",
950 yellowgreen: "9acd32"
951};
952
953// Make it easy to access colors via hexNames[hex]
954var hexNames = tinycolor.hexNames = flip(names);
955
956// Utilities
957// ---------
958
959// { 'name1': 'val1' } becomes { 'val1': 'name1' }
960function flip(o) {
961 var flipped = { };
962 for (var i in o) {
963 if (o.hasOwnProperty(i)) {
964 flipped[o[i]] = i;
965 }
966 }
967 return flipped;
968}
969
970// Return a valid alpha value [0,1] with all invalid values being set to 1
971function boundAlpha(a) {
972 a = parseFloat(a);
973
974 if (isNaN(a) || a < 0 || a > 1) {
975 a = 1;
976 }
977
978 return a;
979}
980
981// Take input from [0, n] and return it as [0, 1]
982function bound01(n, max) {
983 if (isOnePointZero(n)) { n = "100%"; }
984
985 var processPercent = isPercentage(n);
986 n = mathMin(max, mathMax(0, parseFloat(n)));
987
988 // Automatically convert percentage into number
989 if (processPercent) {
990 n = parseInt(n * max, 10) / 100;
991 }
992
993 // Handle floating point rounding errors
994 if ((Math.abs(n - max) < 0.000001)) {
995 return 1;
996 }
997
998 // Convert into [0, 1] range if it isn't already
999 return (n % max) / parseFloat(max);
1000}
1001
1002// Force a number between 0 and 1
1003function clamp01(val) {
1004 return mathMin(1, mathMax(0, val));
1005}
1006
1007// Parse a base-16 hex value into a base-10 integer
1008function parseIntFromHex(val) {
1009 return parseInt(val, 16);
1010}
1011
1012// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
1013// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
1014function isOnePointZero(n) {
1015 return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
1016}
1017
1018// Check to see if string passed in is a percentage
1019function isPercentage(n) {
1020 return typeof n === "string" && n.indexOf('%') != -1;
1021}
1022
1023// Force a hex value to have 2 characters
1024function pad2(c) {
1025 return c.length == 1 ? '0' + c : '' + c;
1026}
1027
1028// Replace a decimal with it's percentage value
1029function convertToPercentage(n) {
1030 if (n <= 1) {
1031 n = (n * 100) + "%";
1032 }
1033
1034 return n;
1035}
1036
1037// Converts a decimal to a hex value
1038function convertDecimalToHex(d) {
1039 return Math.round(parseFloat(d) * 255).toString(16);
1040}
1041// Converts a hex value to a decimal
1042function convertHexToDecimal(h) {
1043 return (parseIntFromHex(h) / 255);
1044}
1045
1046var matchers = (function() {
1047
1048 // <http://www.w3.org/TR/css3-values/#integers>
1049 var CSS_INTEGER = "[-\\+]?\\d+%?";
1050
1051 // <http://www.w3.org/TR/css3-values/#number-value>
1052 var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
1053
1054 // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
1055 var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
1056
1057 // Actual matching.
1058 // Parentheses and commas are optional, but not required.
1059 // Whitespace can take the place of commas or opening paren
1060 var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
1061 var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
1062
1063 return {
1064 CSS_UNIT: new RegExp(CSS_UNIT),
1065 rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
1066 rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
1067 hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
1068 hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
1069 hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
1070 hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
1071 hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
1072 hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
1073 hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
1074 hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
1075 };
1076})();
1077
1078// isValidCSSUnit
1079// Take in a single string / number and check to see if it looks like a CSS unit
1080// (see matchers above for definition).
1081function isValidCSSUnit(color) {
1082 return !!matchers.CSS_UNIT.exec(color);
1083}
1084
1085// stringInputToObject
1086// Permissive string parsing. Take in a number of formats, and output an object
1087// based on detected format. Returns { r, g, b } or { h, s, l } or { h, s, v}
1088function stringInputToObject(color) {
1089
1090 color = color.replace(trimLeft, '').replace(trimRight, '').toLowerCase();
1091 var named = false;
1092 if (names[color]) {
1093 color = names[color];
1094 named = true;
1095 }
1096 else if (color == 'transparent') {
1097 return { r: 0, g: 0, b: 0, a: 0, format: "name" };
1098 }
1099
1100 // Try to match string input using regular expressions.
1101 // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
1102 // Just return an object and let the conversion functions handle that.
1103 // This way the result will be the same whether the tinycolor is initialized with string or object.
1104 var match;
1105 if ((match = matchers.rgb.exec(color))) {
1106 return { r: match[1], g: match[2], b: match[3] };
1107 }
1108 if ((match = matchers.rgba.exec(color))) {
1109 return { r: match[1], g: match[2], b: match[3], a: match[4] };
1110 }
1111 if ((match = matchers.hsl.exec(color))) {
1112 return { h: match[1], s: match[2], l: match[3] };
1113 }
1114 if ((match = matchers.hsla.exec(color))) {
1115 return { h: match[1], s: match[2], l: match[3], a: match[4] };
1116 }
1117 if ((match = matchers.hsv.exec(color))) {
1118 return { h: match[1], s: match[2], v: match[3] };
1119 }
1120 if ((match = matchers.hsva.exec(color))) {
1121 return { h: match[1], s: match[2], v: match[3], a: match[4] };
1122 }
1123 if ((match = matchers.hex8.exec(color))) {
1124 return {
1125 r: parseIntFromHex(match[1]),
1126 g: parseIntFromHex(match[2]),
1127 b: parseIntFromHex(match[3]),
1128 a: convertHexToDecimal(match[4]),
1129 format: named ? "name" : "hex8"
1130 };
1131 }
1132 if ((match = matchers.hex6.exec(color))) {
1133 return {
1134 r: parseIntFromHex(match[1]),
1135 g: parseIntFromHex(match[2]),
1136 b: parseIntFromHex(match[3]),
1137 format: named ? "name" : "hex"
1138 };
1139 }
1140 if ((match = matchers.hex4.exec(color))) {
1141 return {
1142 r: parseIntFromHex(match[1] + '' + match[1]),
1143 g: parseIntFromHex(match[2] + '' + match[2]),
1144 b: parseIntFromHex(match[3] + '' + match[3]),
1145 a: convertHexToDecimal(match[4] + '' + match[4]),
1146 format: named ? "name" : "hex8"
1147 };
1148 }
1149 if ((match = matchers.hex3.exec(color))) {
1150 return {
1151 r: parseIntFromHex(match[1] + '' + match[1]),
1152 g: parseIntFromHex(match[2] + '' + match[2]),
1153 b: parseIntFromHex(match[3] + '' + match[3]),
1154 format: named ? "name" : "hex"
1155 };
1156 }
1157
1158 return false;
1159}
1160
1161function validateWCAG2Parms(parms) {
1162 // return valid WCAG2 parms for isReadable.
1163 // If input parms are invalid, return {"level":"AA", "size":"small"}
1164 var level, size;
1165 parms = parms || {"level":"AA", "size":"small"};
1166 level = (parms.level || "AA").toUpperCase();
1167 size = (parms.size || "small").toLowerCase();
1168 if (level !== "AA" && level !== "AAA") {
1169 level = "AA";
1170 }
1171 if (size !== "small" && size !== "large") {
1172 size = "small";
1173 }
1174 return {"level":level, "size":size};
1175}
1176
1177this.tinycolor = tinycolor;
1178
1179})()`;
1180}
1181// It is hacky way to make this function will be compiled preferentially by less
1182// resolve error: `ReferenceError: colorPalette is not defined`
1183.tinyColorMixin();