: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// https://github.com/bgrins/TinyColor
// 2013-08-10, Brian Grinstead, MIT License
var trimLeft = /^[\s,#]+/,
mathRandom = math.random;
function tinycolor (color, opts) {
color = (color) ? color : '';
// If input is already a tinycolor, return itself
if (typeof color == "object" && color.hasOwnProperty("_tc_id")) {
var rgb = inputToRGB(color);
roundA = mathRound(100*a) / 100,
format = opts.format || rgb.format;
// Don't let the range of [0,255] come back in [0,1].
// Potentially lose a little bit of precision here, but will fix issues where
// .5 gets interpreted as half of the total, instead of half of 1
// If it was supposed to be 128, this was already taken care of by `inputToRgb`
if (r < 1) { r = mathRound(r); }
if (g < 1) { g = mathRound(g); }
if (b < 1) { b = mathRound(b); }
setAlpha: function(value) {
roundA = mathRound(100*a) / 100;
var hsv = rgbToHsv(r, g, b);
return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a };
toHsvString: function() {
var hsv = rgbToHsv(r, g, b);
var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
"hsv(" + h + ", " + s + "%, " + v + "%)" :
"hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")";
var hsl = rgbToHsl(r, g, b);
return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a };
toHslString: function() {
var hsl = rgbToHsl(r, g, b);
var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
"hsl(" + h + ", " + s + "%, " + l + "%)" :
"hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")";
toHex: function(allow3Char) {
return rgbToHex(r, g, b, allow3Char);
toHexString: function(allow3Char) {
return '#' + rgbToHex(r, g, b, allow3Char);
return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a };
toRgbString: function() {
"rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" :
"rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")";
toPercentageRgb: function() {
return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a };
toPercentageRgbString: function() {
"rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" :
"rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")";
return hexNames[rgbToHex(r, g, b, true)] || false;
toFilter: function(secondColor) {
var hex = rgbToHex(r, g, b);
var alphaHex = Math.round(parseFloat(a) * 255).toString(16);
var secondAlphaHex = alphaHex;
var gradientType = opts && opts.gradientType ? "GradientType = 1, " : "";
var s = tinycolor(secondColor);
secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16);
return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")";
toString: function(format) {
var formatSet = !!format;
format = format || this.format;
var formattedString = false;
var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0;
var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name");
formattedString = this.toRgbString();
formattedString = this.toPercentageRgbString();
if (format === "hex" || format === "hex6") {
formattedString = this.toHexString();
formattedString = this.toHexString(true);
formattedString = this.toName();
formattedString = this.toHslString();
formattedString = this.toHsvString();
return this.toRgbString();
return formattedString || this.toHexString();
// If input is an object, force 1 into "1.0" to handle ratios properly
// String input requires "1.0" as input, so 1 will be treated as 1
tinycolor.fromRatio = function(color, opts) {
if (typeof color == "object") {
if (color.hasOwnProperty(i)) {
newColor[i] = convertToPercentage(color[i]);
return tinycolor(color, opts);
// Given a string or object, convert that input to RGB
// Possible string inputs:
// "rgb 255 0 0" or "rgb (255, 0, 0)"
// "rgb 1.0 0 0" or "rgb (1, 0, 0)"
// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
function inputToRGB(color) {
var rgb = { r: 0, g: 0, b: 0 };
if (typeof color == "string") {
color = stringInputToObject(color);
if (typeof color == "object") {
if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
rgb = rgbToRgb(color.r, color.g, color.b);
format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
color.s = convertToPercentage(color.s);
color.v = convertToPercentage(color.v);
rgb = hsvToRgb(color.h, color.s, color.v);
else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
color.s = convertToPercentage(color.s);
color.l = convertToPercentage(color.l);
rgb = hslToRgb(color.h, color.s, color.l);
if (color.hasOwnProperty("a")) {
format: color.format || format,
r: mathMin(255, mathMax(rgb.r, 0)),
g: mathMin(255, mathMax(rgb.g, 0)),
b: mathMin(255, mathMax(rgb.b, 0)),
// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
// Handle bounds / percentage checking to conform to CSS color spec
// <http://www.w3.org/TR/css3-color/>
// *Assumes:* r, g, b in [0, 255] or [0, 1]
// *Returns:* { r, g, b } in [0, 255]
function rgbToRgb(r, g, b){
r: bound01(r, 255) * 255,
g: bound01(g, 255) * 255,
// Converts an RGB color value to HSL.
// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
// *Returns:* { h, s, l } in [0,1]
function rgbToHsl(r, g, b) {
var max = mathMax(r, g, b), min = mathMin(r, g, b);
var h, s, l = (max + min) / 2;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
return { h: h, s: s, l: l };
// Converts an HSL color value to RGB.
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
// *Returns:* { r, g, b } in the set [0, 255]
function hslToRgb(h, s, l) {
function hue2rgb(p, q, t) {
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
r = g = b = l; // achromatic
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
r = hue2rgb(p, q, h + 1/3);
b = hue2rgb(p, q, h - 1/3);
return { r: r * 255, g: g * 255, b: b * 255 };
// Converts an RGB color value to HSV
// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
// *Returns:* { h, s, v } in [0,1]
function rgbToHsv(r, g, b) {
var max = mathMax(r, g, b), min = mathMin(r, g, b);
s = max === 0 ? 0 : d / max;
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
return { h: h, s: s, v: v };
// Converts an HSV color value to RGB.
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
// *Returns:* { r, g, b } in the set [0, 255]
function hsvToRgb(h, s, v) {
t = v * (1 - (1 - f) * s),
r = [v, q, p, p, t, v][mod],
g = [t, v, v, q, p, p][mod],
b = [p, p, t, v, v, q][mod];
return { r: r * 255, g: g * 255, b: b * 255 };
// Converts an RGB color to hex
// Assumes r, g, and b are contained in the set [0, 255]
// Returns a 3 or 6 character hex
function rgbToHex(r, g, b, allow3Char) {
pad2(mathRound(r).toString(16)),
pad2(mathRound(g).toString(16)),
pad2(mathRound(b).toString(16))
// Return a 3 character hex if possible
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)) {
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
// Can be called with any tinycolor input
tinycolor.equals = function (color1, color2) {
if (!color1 || !color2) { return false; }
return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
tinycolor.random = function() {
return tinycolor.fromRatio({
// Modification Functions
// ----------------------
// Thanks to less.js for some of the basics here
// <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
tinycolor.desaturate = function (color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
tinycolor.saturate = function (color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
tinycolor.greyscale = function(color) {
return tinycolor.desaturate(color, 100);
tinycolor.lighten = function(color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
tinycolor.darken = function (color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
tinycolor.complement = function(color) {
var hsl = tinycolor(color).toHsl();
hsl.h = (hsl.h + 180) % 360;
// Thanks to jQuery xColor for some of the ideas behind these
// <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
tinycolor.triad = function(color) {
var hsl = tinycolor(color).toHsl();
tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
tinycolor.tetrad = function(color) {
var hsl = tinycolor(color).toHsl();
tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
tinycolor.splitcomplement = function(color) {
var hsl = tinycolor(color).toHsl();
tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}),
tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l})
tinycolor.analogous = function(color, results, slices) {
var hsl = tinycolor(color).toHsl();
var ret = [tinycolor(color)];
for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {