@fr0st/color
Version:
FrostColor is a free, open-source color manipulation library for JavaScript.
1,366 lines (1,222 loc) • 39.2 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Color = factory());
})(this, (function () { 'use strict';
/**
* Color Helpers
*/
/**
* Clamp a value between a min and max.
* @param {number} val The value to clamp.
* @param {number} [min=0] The minimum value of the clamped range.
* @param {number} [max=1] The maximum value of the clamped range.
* @return {number} The clamped value.
*/
const clamp = (val, min = 0, max = 100) => {
return Math.max(
min,
Math.min(max, val),
);
};
/**
* Linear interpolation from one value to another.
* @param {number} a The starting value.
* @param {number} b The ending value.
* @param {number} amount The amount to interpolate.
* @return {number} The interpolated value.
*/
const lerp = (a, b, amount) => {
const value = a * (1 - amount) + b * amount;
return round(value);
};
/**
* Round a number to a specified precision.
* @param {number} num The number to round.
* @param {number} [precision=2] The precision to use.
* @return {number} The rounded number.
*/
const round = (num, precision = 2) => {
return parseFloat(parseFloat(num).toFixed(precision));
};
/**
* Shorten a hex string (if possible).
* @param {string} hex The hex string.
* @return {string} The hex string.
*/
const toHex = (hex) => {
if (hex.length === 9 &&
hex[1] === hex[2] &&
hex[3] === hex[4] &&
hex[5] === hex[6] &&
hex[7] === hex[8]) {
return `#${hex[1]}${hex[3]}${hex[5]}${hex[7]}`;
}
if (hex.length === 7 &&
hex[1] === hex[2] &&
hex[3] === hex[4] &&
hex[5] === hex[6]) {
return `#${hex[1]}${hex[3]}${hex[5]}`;
}
return hex;
};
/**
* Color class
* @class
*/
class Color {
/**
* New Color constructor.
* @param {number} [r=0] The red value, or the brightness value.
* @param {number} [g=1] The green value or the alpha value.
* @param {null|number} [b=null] The blue value.
* @param {number} [a=1] The alpha value.
*/
constructor(r = 0, g = 1, b = null, a = 1) {
if (b === null) {
a = g;
b = g = r = round(r * 2.55);
}
this._r = clamp(r, 0, 255);
this._g = clamp(g, 0, 255);
this._b = clamp(b, 0, 255);
this._a = clamp(a, 0, 1);
}
/**
* Return the luminance value of the color.
* @return {number} The luminance value. (0, 1)
*/
valueOf() {
return this.luma();
}
/**
* Return a primitive value of the color.
* @param {string} hint The type hint.
* @return {string|number} The HTML color string, or the luminance value.
*/
[Symbol.toPrimitive](hint) {
return hint === 'number' ?
this.valueOf() :
this.toString();
}
/**
* Get the alpha value of the color.
* @return {number} The alpha value. (0, 1)
*/
get a() {
return this._a;
}
/**
* Get the blue value of the color.
* @return {number} The blue value. (0, 255)
*/
get b() {
return this._b;
}
/**
* Get the green value of the color.
* @return {number} The green value. (0, 255)
*/
get g() {
return this._g;
}
/**
* Get the red value of the color.
* @return {number} The red value. (0, 255)
*/
get r() {
return this._r;
}
}
/**
* Color Names
*/
// HTML color names
const colors = {
aliceblue: '#f0f8ff',
antiquewhite: '#faebd7',
aqua: '#00ffff',
aquamarine: '#7fffd4',
azure: '#f0ffff',
beige: '#f5f5dc',
bisque: '#ffe4c4',
black: '#000000',
blanchedalmond: '#ffebcd',
blue: '#0000ff',
blueviolet: '#8a2be2',
brown: '#a52a2a',
burlywood: '#deb887',
cadetblue: '#5f9ea0',
chartreuse: '#7fff00',
chocolate: '#d2691e',
coral: '#ff7f50',
cornflowerblue: '#6495ed',
cornsilk: '#fff8dc',
crimson: '#dc143c',
cyan: '#00ffff',
darkblue: '#00008b',
darkcyan: '#008b8b',
darkgoldenrod: '#b8860b',
darkgray: '#a9a9a9',
darkgrey: '#a9a9a9',
darkgreen: '#006400',
darkkhaki: '#bdb76b',
darkmagenta: '#8b008b',
darkolivegreen: '#556b2f',
darkorange: '#ff8c00',
darkorchid: '#9932cc',
darkred: '#8b0000',
darksalmon: '#e9967a',
darkseagreen: '#8fbc8f',
darkslateblue: '#483d8b',
darkslategray: '#2f4f4f',
darkslategrey: '#2f4f4f',
darkturquoise: '#00ced1',
darkviolet: '#9400d3',
deeppink: '#ff1493',
deepskyblue: '#00bfff',
dimgray: '#696969',
dimgrey: '#696969',
dodgerblue: '#1e90ff',
firebrick: '#b22222',
floralwhite: '#fffaf0',
forestgreen: '#228b22',
fuchsia: '#ff00ff',
gainsboro: '#dcdcdc',
ghostwhite: '#f8f8ff',
gold: '#ffd700',
goldenrod: '#daa520',
gray: '#808080',
grey: '#808080',
green: '#008000',
greenyellow: '#adff2f',
honeydew: '#f0fff0',
hotpink: '#ff69b4',
indianred: '#cd5c5c',
indigo: '#4b0082',
ivory: '#fffff0',
khaki: '#f0e68c',
lavender: '#e6e6fa',
lavenderblush: '#fff0f5',
lawngreen: '#7cfc00',
lemonchiffon: '#fffacd',
lightblue: '#add8e6',
lightcoral: '#f08080',
lightcyan: '#e0ffff',
lightgoldenrodyellow: '#fafad2',
lightgray: '#d3d3d3',
lightgrey: '#d3d3d3',
lightgreen: '#90ee90',
lightpink: '#ffb6c1',
lightsalmon: '#ffa07a',
lightseagreen: '#20b2aa',
lightskyblue: '#87cefa',
lightslategray: '#778899',
lightslategrey: '#778899',
lightsteelblue: '#b0c4de',
lightyellow: '#ffffe0',
lime: '#00ff00',
limegreen: '#32cd32',
linen: '#faf0e6',
magenta: '#ff00ff',
maroon: '#800000',
mediumaquamarine: '#66cdaa',
mediumblue: '#0000cd',
mediumorchid: '#ba55d3',
mediumpurple: '#9370db',
mediumseagreen: '#3cb371',
mediumslateblue: '#7b68ee',
mediumspringgreen: '#00fa9a',
mediumturquoise: '#48d1cc',
mediumvioletred: '#c71585',
midnightblue: '#191970',
mintcream: '#f5fffa',
mistyrose: '#ffe4e1',
moccasin: '#ffe4b5',
navajowhite: '#ffdead',
navy: '#000080',
oldlace: '#fdf5e6',
olive: '#808000',
olivedrab: '#6b8e23',
orange: '#ffa500',
orangered: '#ff4500',
orchid: '#da70d6',
palegoldenrod: '#eee8aa',
palegreen: '#98fb98',
paleturquoise: '#afeeee',
palevioletred: '#db7093',
papayawhip: '#ffefd5',
peachpuff: '#ffdab9',
peru: '#cd853f',
pink: '#ffc0cb',
plum: '#dda0dd',
powderblue: '#b0e0e6',
purple: '#800080',
rebeccapurple: '#663399',
red: '#ff0000',
rosybrown: '#bc8f8f',
royalblue: '#4169e1',
saddlebrown: '#8b4513',
salmon: '#fa8072',
sandybrown: '#f4a460',
seagreen: '#2e8b57',
seashell: '#fff5ee',
sienna: '#a0522d',
silver: '#c0c0c0',
skyblue: '#87ceeb',
slateblue: '#6a5acd',
slategray: '#708090',
slategrey: '#708090',
snow: '#fffafa',
springgreen: '#00ff7f',
steelblue: '#4682b4',
tan: '#d2b48c',
teal: '#008080',
thistle: '#d8bfd8',
tomato: '#ff6347',
turquoise: '#40e0d0',
violet: '#ee82ee',
wheat: '#f5deb3',
white: '#ffffff',
whitesmoke: '#f5f5f5',
yellow: '#ffff00',
yellowgreen: '#9acd32',
};
const hexLookup = Object.fromEntries(
Object.entries(colors)
.map(([key, value]) => [value, key]),
);
/**
* Color Conversions
*/
/**
* Convert CMY color values to RGB.
* @param {number} c The cyan value. (0, 100)
* @param {number} m The magenta value. (0, 100)
* @param {number} y The yellow value. (0, 100)
* @return {number[]} An array containing the RGB values.
*/
const cmy2rgb = (c, m, y) => {
return [
round((1 - c / 100) * 255),
round((1 - m / 100) * 255),
round((1 - y / 100) * 255),
];
};
/**
* Convert CMYK color values to CMY.
* @param {number} c The cyan value. (0, 100)
* @param {number} m The magenta value. (0, 100)
* @param {number} y The yellow value. (0, 100)
* @param {number} k The key value. (0, 100)
* @return {number[]} An array containing the CMY values.
*/
const cmyk2cmy = (c, m, y, k) => {
k /= 100;
return [
round((c / 100 * (1 - k) + k) * 100),
round((m / 100 * (1 - k) + k) * 100),
round((y / 100 * (1 - k) + k) * 100),
];
};
/**
* Calculate the R, G or B value of a hue.
* @param {number} v1 The first value.
* @param {number} v2 The second value.
* @param {number} vH The hue value.
* @return {number} The R, G or B value.
*/
const rgbHue = (v1, v2, vH) => {
vH = (vH + 1) % 1;
if (6 * vH < 1) {
return v1 + (v2 - v1) * 6 * vH;
}
if (2 * vH < 1) {
return v2;
}
if (3 * vH < 2) {
return v1 + (v2 - v1) * ((2 / 3) - vH) * 6;
}
return v1;
};
/**
* Convert HSL color values to RGB.
* @param {number} h The hue value. (0, 360)
* @param {number} s The saturation value. (0, 100)
* @param {number} l The lightness value. (0, 100)
* @return {number[]} An array containing the RGB values.
*/
const hsl2rgb = (h, s, l) => {
if (!l) {
return [0, 0, 0];
}
h /= 360;
s /= 100;
l /= 100;
const v2 = l < .5 ?
l * (1 + s) :
(l + s) - (s * l);
const v1 = 2 * l - v2;
const r = rgbHue(v1, v2, h + (1 / 3));
const g = rgbHue(v1, v2, h);
const b = rgbHue(v1, v2, h - (1 / 3));
return [
round(r * 255),
round(g * 255),
round(b * 255),
];
};
/**
* Convert HSV color values to RGB.
* @param {number} h The hue value. (0, 360)
* @param {number} s The saturation value. (0, 100)
* @param {number} v The brightness value (0, 100)
* @return {number[]} An array containing the RGB values.
*/
const hsv2rgb = (h, s, v) => {
v /= 100;
if (!s) {
return [
round(v * 255),
round(v * 255),
round(v * 255),
];
}
h = (h / 60) % 6;
s /= 100;
const vi = Math.floor(h);
const v1 = v * (1 - s);
const v2 = v * (1 - s * (h - vi));
const v3 = v * (1 - s * (1 - (h - vi)));
let r; let g; let b;
switch (vi) {
case 0:
r = v;
g = v3;
b = v1;
break;
case 1:
r = v2;
g = v;
b = v1;
break;
case 2:
r = v1;
g = v;
b = v3;
break;
case 3:
r = v1;
g = v2;
b = v;
break;
case 4:
r = v3;
g = v1;
b = v;
break;
default:
r = v;
g = v1;
b = v2;
break;
}
return [
round(r * 255),
round(g * 255),
round(b * 255),
];
};
/**
* Convert RGB color values to HSL.
* @param {number} r The red value. (0, 255)
* @param {number} g The green value. (0, 255)
* @param {number} b The blue value. (0, 255)
* @return {number[]} An array containing the HSL values.
*/
const rgb2hsl = (r, g, b) => {
r /= 255;
g /= 255;
b /= 255;
const min = Math.min(r, g, b);
const max = Math.max(r, g, b);
const diff = max - min;
const l = (max + min) / 2;
if (!diff) {
return [
0,
0,
round(l * 100),
];
}
const s = l < .5 ?
diff / (max + min) :
diff / (2 - max - min);
const deltaR = (((max - r) / 6) + (diff / 2)) / diff;
const deltaG = (((max - g) / 6) + (diff / 2)) / diff;
const deltaB = (((max - b) / 6) + (diff / 2)) / diff;
let h = 0;
switch (max) {
case r:
h = deltaB - deltaG;
break;
case g:
h = 1 / 3 + deltaR - deltaB;
break;
case b:
h = 2 / 3 + deltaG - deltaR;
break;
}
h = (h + 1) % 1;
return [
round(h * 360),
round(s * 100),
round(l * 100),
];
};
/**
* Convert RGB color values to HSV.
* @param {number} r The red value. (0, 255)
* @param {number} g The green value. (0, 255)
* @param {number} b The blue value. (0, 255)
* @return {number[]} An array containing the HSV values.
*/
const rgb2hsv = (r, g, b) => {
r /= 255;
g /= 255;
b /= 255;
const min = Math.min(r, g, b);
const max = Math.max(r, g, b);
const diff = max - min;
const v = max;
if (!diff) {
return [
0,
0,
round(v * 100),
];
}
const s = diff / max;
const deltaR = (((max - r) / 6) + (diff / 2)) / diff;
const deltaG = (((max - g) / 6) + (diff / 2)) / diff;
const deltaB = (((max - b) / 6) + (diff / 2)) / diff;
let h = 0;
switch (max) {
case r:
h = deltaB - deltaG;
break;
case g:
h = 1 / 3 + deltaR - deltaB;
break;
case b:
h = 2 / 3 + deltaG - deltaR;
break;
}
h = (h + 1) % 1;
return [
round(h * 360),
round(s * 100),
round(v * 100),
];
};
/**
* Convert RGBA color values to hex.
* @param {number} r The red value. (0, 255)
* @param {number} g The green value. (0, 255)
* @param {number} b The blue value. (0, 255)
* @param {number} a The alpha value. (0, 1)
* @return {string} The hex string.
*/
const rgba2hex = (r, g, b, a) => {
[r, g, b] = [r, g, b].map(
(value) => (Math.round(value) | 1 << 8)
.toString(16)
.slice(1),
);
const hex = `#${r}${g}${b}`;
if (a >= 1) {
return hex;
}
return hex +
(Math.round(a * 255) | 1 << 8)
.toString(16)
.slice(1);
};
/**
* Calculate the relative R, G or B value for luma calculation.
* @param {number} v The value.
* @return {number} The R, G or B value.
*/
const rgbLumaVlaue = (v) => {
v /= 255;
if (v <= .03928) {
return v / 12.92;
}
return Math.pow(((v + .055) / 1.055), 2.4);
};
/**
* Calculate the relative luminance of an RGB color.
* @param {number} r The red value. (0, 255)
* @param {number} g The green value. (0, 255)
* @param {number} b The blue value. (0, 255)
* @return {number} The relative luminance value.
*/
const rgbLuma = (r, g, b) => {
r = rgbLumaVlaue(r);
g = rgbLumaVlaue(g);
b = rgbLumaVlaue(b);
return (.2126 * r) + (.7152 * g) + (.0722 * b);
};
/**
* Color (Static) Creation
*/
/**
* Create a new Color from CMY values.
* @param {number} c The cyan value. (0, 100)
* @param {number} m The magenta value. (0, 100)
* @param {number} y The yellow value. (0, 100)
* @param {number} [a=1] The alpha value. (0, 1)
* @return {Color} A new Color object.
*/
function fromCMY(c, m, y, a = 1) {
const [r, g, b] = cmy2rgb(c, m, y);
return new Color(r, g, b, a);
}
/**
* Create a new Color from CMYK values.
* @param {number} c The cyan value. (0, 100)
* @param {number} m The magenta value. (0, 100)
* @param {number} y The yellow value. (0, 100)
* @param {number} k The key value. (0, 100)
* @param {number} [a=1] The alpha value. (0, 1)
* @return {Color} A new Color object.
*/
function fromCMYK(c, m, y, k, a = 1) {
[c, m, y] = cmyk2cmy(c, m, y, k);
return fromCMY(c, m, y, a);
}
/**
* Create a new Color from a hex color string.
* @param {string} string The hex color string.
* @return {Color} A new Color object.
*/
function fromHexString(string) {
string = string.trim();
const hexMatch = string.length > 6 ?
string.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i) :
string.match(/^#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f]?)$/i);
if (!hexMatch) {
throw new Error('Invalid hex string');
}
const rgb = hexMatch.slice(1, 5).map((value) =>
value ?
parseInt(
value.length == 2 ?
value :
value + value,
16,
) :
null,
);
return new Color(rgb[0],
rgb[1],
rgb[2],
rgb[3] ?
rgb[3] / 255 :
1,
);
}
/**
* Create a new Color from HSL values.
* @param {number} h The hue value. (0, 360)
* @param {number} s The saturation value. (0, 100)
* @param {number} l The lightness value. (0, 100)
* @param {number} [a=1] The alpha value. (0, 1)
* @return {Color} A new Color object.
*/
function fromHSL(h, s, l, a = 1) {
const [r, g, b] = hsl2rgb(h, s, l);
return new Color(r, g, b, a);
}
/**
* Create a new Color from a HSL color string.
* @param {string} string The HSL color string.
* @return {Color} A new Color object.
*/
function fromHSLString(string) {
string = string.trim();
const HSL2Match = string.match(/^hsl\(((?:\d*\.)?\d+)deg\s+((?:\d*\.)?\d+)\%\s+((?:\d*\.)?\d+)\%\)$/i);
if (HSL2Match) {
return fromHSL(HSL2Match[1], HSL2Match[2], HSL2Match[3]);
}
const HSLA2Match = string.match(/^hsl\(((?:\d*\.)?\d+)deg\s+((?:\d*\.)?\d+)\%\s+((?:\d*\.)?\d+)\%\s*\/\s*((?:\d*\.)?\d+)(\%?)\)$/i);
if (HSLA2Match) {
return fromHSL(
HSLA2Match[1],
HSLA2Match[2],
HSLA2Match[3],
HSLA2Match[5] ?
HSLA2Match[4] / 100 :
HSLA2Match[4],
);
}
const HSLMatch = string.match(/^hsl\(((?:\d*\.)?\d+),\s*((?:\d*\.)?\d+)\%,\s*((?:\d*\.)?\d+)\%\)$/i);
if (HSLMatch) {
return fromHSL(HSLMatch[1], HSLMatch[2], HSLMatch[3]);
}
const HSLAMatch = string.match(/^hsla\(((?:\d*\.)?\d+),\s*((?:\d*\.)?\d+)\%,\s*((?:\d*\.)?\d+)\%,\s*((?:\d*\.)?\d+)(\%?)\)$/i);
if (HSLAMatch) {
return fromHSL(
HSLAMatch[1],
HSLAMatch[2],
HSLAMatch[3],
HSLAMatch[5] ?
HSLAMatch[4] / 100 :
HSLAMatch[4],
);
}
throw new Error('Invalid HSL string');
}
/**
* Create a new Color from HSV values.
* @param {number} h The hue value. (0, 360)
* @param {number} s The saturation value. (0, 100)
* @param {number} v The brightness value. (0, 100)
* @param {number} [a=1] The alpha value. (0, 1)
* @return {Color} A new Color object.
*/
function fromHSV(h, s, v, a = 1) {
const [r, g, b] = hsv2rgb(h, s, v);
return new Color(r, g, b, a);
}
/**
* Create a new Color from RGB values.
* @param {number} r The red value. (0, 255)
* @param {number} g The green value. (0, 255)
* @param {number} b The blue value. (0, 255)
* @param {number} [a=1] The alpha value. (0, 1)
* @return {Color} A new Color object.
*/
function fromRGB(r, g, b, a = 1) {
return new Color(r, g, b, a);
}
/**
* Create a new Color from a RGB color string.
* @param {string} string The RGB color string.
* @return {Color} A new Color object.
*/
function fromRGBString(string) {
string = string.trim();
const RGB2Match = string.match(/^rgb\(((?:\d*\.)?\d+)\s+((?:\d*\.)?\d+)\s+((?:\d*\.)?\d+)\)$/i);
if (RGB2Match) {
return new Color(RGB2Match[1], RGB2Match[2], RGB2Match[3]);
}
const RGBA2Match = string.match(/^rgb\(((?:\d*\.)?\d+)\s+((?:\d*\.)?\d+)\s+((?:\d*\.)?\d+)\s*\/\s*((?:\d*\.)?\d+)(\%?)\)$/i);
if (RGBA2Match) {
return new Color(
RGBA2Match[1],
RGBA2Match[2],
RGBA2Match[3],
RGBA2Match[5] ?
RGBA2Match[4] / 100 :
RGBA2Match[4],
);
}
const RGBMatch = string.match(/^rgb\(((?:\d*\.)?\d+),\s*((?:\d*\.)?\d+),\s*((?:\d*\.)?\d+)\)$/i);
if (RGBMatch) {
return new Color(RGBMatch[1], RGBMatch[2], RGBMatch[3]);
}
const RGBAMatch = string.match(/^rgba\(((?:\d*\.)?\d+),\s*((?:\d*\.)?\d+),\s*((?:\d*\.)?\d+),\s*((?:\d*\.)?\d+)(\%?)\)$/i);
if (RGBAMatch) {
return new Color(
RGBAMatch[1],
RGBAMatch[2],
RGBAMatch[3],
RGBAMatch[5] ?
RGBAMatch[4] / 100 :
RGBAMatch[4],
);
}
throw new Error('Invalid RGB string');
}
/**
* Create a new Color from a HTML color string.
* @param {string} string The HTML color string.
* @return {Color} A new Color object.
*/
function fromString(string) {
string = string.toLowerCase().trim();
if (string === 'transparent') {
return new Color(0, 0, 0, 0);
}
if (string in colors) {
string = colors[string];
}
if (string.substring(0, 1) === '#') {
return fromHexString(string);
}
if (string.substring(0, 3).toLowerCase() === 'rgb') {
return fromRGBString(string);
}
if (string.substring(0, 3).toLowerCase() === 'hsl') {
return fromHSLString(string);
}
throw new Error('Invalid color string');
}
/**
* Color (Static) Utility
*/
/**
* Get the contrast value between two colors.
* @param {Color} color1 The first Color.
* @param {Color} color2 The second Color.
* @return {number} The contrast value. (1, 21)
*/
const contrast = (color1, color2) => {
const luma1 = color1.luma();
const luma2 = color2.luma();
return (Math.max(luma1, luma2) + .05) / (Math.min(luma1, luma2) + .05);
};
/**
* Calculate the distance between two colors.
* @param {Color} color1 The first Color.
* @param {Color} color2 The second Color.
* @return {number} The distance between the colors.
*/
const dist = (color1, color2) => {
return Math.hypot(color1.r - color2.r, color1.g - color2.g, color1.b - color2.b);
};
/**
* Find an optimally contrasting color for another color.
* @param {Color} color1 The first Color.
* @param {Color} [color2] The second Color.
* @param {object} [options] The options for finding the contrasting color.
* @param {number} [options.minContrast=4.5] The minimum contrast.
* @param {number} [options.stepSize=.01] The step size.
* @return {Color} The new Color.
*/
const findContrast = (color1, color2 = null, { minContrast = 4.5, stepSize = .01 } = {}) => {
if (!color2) {
color2 = color1;
}
if (contrast(color1, color2) >= minContrast) {
return color2;
}
const methods = ['tint', 'shade'];
for (let i = stepSize; i <= 1; i += stepSize) {
for (const method of methods) {
const tempColor = color2[method](i);
if (contrast(color1, tempColor) >= minContrast) {
return tempColor;
}
}
}
return null;
};
/**
* Create a new Color by mixing two colors together by a specified amount.
* @param {Color} color1 The first Color.
* @param {Color} color2 The second Color.
* @param {number} amount The amount to mix them by. (0, 1)
* @return {Color} A new Color object.
*/
function mix(color1, color2, amount) {
const r = lerp(color1.r, color2.r, amount);
const g = lerp(color1.g, color2.g, amount);
const b = lerp(color1.b, color2.b, amount);
return new Color(r, g, b);
}
/**
* Create a new Color by multiplying two colors together by a specified amount.
* @param {Color} color1 The first Color.
* @param {Color} color2 The second Color.
* @param {number} amount The amount to multiply them by. (0, 1)
* @return {Color} A new Color object.
*/
function multiply(color1, color2, amount) {
const r = lerp(color1.r, color1.r * color2.r / 255, amount);
const g = lerp(color1.g, color1.g * color2.g / 255, amount);
const b = lerp(color1.b, color1.b * color2.b / 255, amount);
return new Color(r, g, b);
}
/**
* Color Attributes
*/
/**
* Get the alpha value of the color.
* @return {number} The alpha value. (0, 1)
*/
function getAlpha() {
return this.a;
}
/**
* Get the brightness value of the color.
* @return {number} The brightness value. (0, 100)
*/
function getBrightness() {
return rgb2hsv(this.r, this.g, this.b)[2];
}
/**
* Get the hue value of the color.
* @return {number} The hue value. (0, 360)
*/
function getHue() {
return rgb2hsv(this.r, this.g, this.b)[0];
}
/**
* Get the saturation value of the color.
* @return {number} The saturation value. (0, 100)
*/
function getSaturation() {
return rgb2hsv(this.r, this.g, this.b)[1];
}
/**
* Get the relative luminance value of the color
* @return {number} The relative luminance value. (0, 1)
*/
function luma() {
return rgbLuma(this.r, this.g, this.b);
}
/**
* Set the alpha value of the color.
* @param {number} a The alpha value. (0, 1)
* @return {Color} The modified Color object.
*/
function setAlpha(a) {
return new Color(this.r, this.g, this.b, a);
}
/**
* Set the brightness value of the color.
* @param {number} v The brightness value. (0, 100)
* @return {Color} The modified Color object.
*/
function setBrightness(v) {
const [h, s, _] = rgb2hsv(this.r, this.g, this.b);
const [r, g, b] = hsv2rgb(h, s, v);
return new Color(r, g, b, this.a);
}
/**
* Set the hue value of the color.
* @param {number} h The hue value. (0, 360)
* @return {Color} The modified Color object.
*/
function setHue(h) {
const [_, s, v] = rgb2hsv(this.r, this.g, this.b);
const [r, g, b] = hsv2rgb(h, s, v);
return new Color(r, g, b, this.a);
}
/**
* Set the saturation value of the color.
* @param {number} s The saturation value. (0, 100)
* @return {Color} The modified Color object.
*/
function setSaturation(s) {
const [h, _, v] = rgb2hsv(this.r, this.g, this.b);
const [r, g, b] = hsv2rgb(h, s, v);
return new Color(r, g, b, this.a);
}
/**
* Color Manipulation
*/
const white = new Color(100);
const grey = new Color(50);
const black = new Color(0);
/**
* Darken the color by a specified amount.
* @param {number} amount The amount to darken the color by. (0, 1)
* @return {Color} The darkened Color object.
*/
function darken(amount) {
let [h, s, l] = rgb2hsl(this.r, this.g, this.b);
l -= l * amount;
const [r, g, b] = hsl2rgb(h, s, l);
return new Color(r, g, b, this.a);
}
/**
* Invert the color.
* @return {Color} The inverted Color object.
*/
function invert() {
return new Color(
255 - this.r,
255 - this.g,
255 - this.b,
this.a,
);
}
/**
* Lighten the color by a specified amount.
* @param {number} amount The amount to lighten the color by. (0, 1)
* @return {Color} The lightened Color object.
*/
function lighten(amount) {
let [h, s, l] = rgb2hsl(this.r, this.g, this.b);
l += (100 - l) * amount;
const [r, g, b] = hsl2rgb(h, s, l);
return new Color(r, g, b, this.a);
}
/**
* Shade the color by a specified amount.
* @param {number} amount The amount to shade the color by. (0, 1)
* @return {Color} The shaded Color object.
*/
function shade(amount) {
return mix(this, black, amount);
}
/**
* Tint the color by a specified amount.
* @param {number} amount The amount to tint the color by. (0, 1)
* @return {Color} The tinted Color object.
*/
function tint(amount) {
return mix(this, white, amount);
}
/**
* Tone the color by a specified amount.
* @param {number} amount The amount to tone the color by. (0, 1)
* @return {Color} The toned Color object.
*/
function tone(amount) {
return mix(this, grey, amount);
}
/**
* Get the closest color name for the color.
* @return {string} The name.
*/
function label() {
let closest;
let closestDistance = Number.MAX_SAFE_INTEGER;
for (const label in colors) {
if (!{}.hasOwnProperty.call(colors, label)) {
continue;
}
const color = fromHexString(colors[label]);
const distance = dist(this, color);
if (distance < closestDistance) {
closest = label;
closestDistance = distance;
}
}
return closest;
}
/**
* Return a hexadecimal string representation of the color.
* @return {string} The hexadecimal string.
*/
function toHexString() {
const hex = rgba2hex(this.r, this.g, this.b, this.a);
return toHex(hex);
}
/**
* Return a HSL/HSLA string representation of the color.
* @return {string} The HSL/HSLA string.
*/
function toHSLString() {
let [h, s, l] = rgb2hsl(this.r, this.g, this.b);
h = Math.round(h);
s = Math.round(s);
l = Math.round(l);
const a = Math.round(this.a * 100);
if (a < 100) {
return `hsl(${h}deg ${s}% ${l}% / ${a}%)`;
}
return `hsl(${h}deg ${s}% ${l}%)`;
}
/**
* Return a RGB/RGBA string representation of the color.
* @return {string} The RGB/RGBA string.
*/
function toRGBString() {
const r = Math.round(this.r);
const g = Math.round(this.g);
const b = Math.round(this.b);
const a = Math.round(this.a * 100);
if (a < 100) {
return `rgb(${r} ${g} ${b} / ${a}%)`;
}
return `rgb(${r} ${g} ${b})`;
}
/**
* Return a HTML string representation of the color.
* @return {string} The HTML color string.
*/
function toString() {
if (!this.a) {
return 'transparent';
}
if (this.a < 1) {
return this.toRGBString();
}
const hex = rgba2hex(this.r, this.g, this.b, this.a);
if (hex in hexLookup) {
return hexLookup[hex];
}
return toHex(hex);
}
/**
* Color Palette
*/
/**
* Create a palette object with a specified number of shades, tints and tone variations.
* @param {object} [options] The options for generating a palette.
* @param {number} [options.shades=10] The number of shades to generate.
* @param {number} [options.tints=10] The number of tints to generate.
* @param {number} [options.tones=10] The number of tones to generate.
* @return {object} A palette object.
*/
function palette({ shades = 10, tints = 10, tones = 10 } = {}) {
return {
shades: this.shades(shades),
tints: this.tints(tints),
tones: this.tones(tones),
};
}
/**
* Create an array with a specified number of shade variations.
* @param {number} [shades=10] The number of shades to generate.
* @return {Color[]} An array containing shade variations.
*/
function shades(shades = 10) {
return new Array(shades)
.fill()
.map(
(_, index) => this.shade(index / (shades + 1)),
);
}
/**
* Create an array with a specified number of tint variations.
* @param {number} [tints=10] The number of tints to generate.
* @return {Color[]} An array containing tint variations.
*/
function tints(tints = 10) {
return new Array(tints)
.fill()
.map(
(_, index) => this.tint(index / (tints + 1)),
);
}
/**
* Create an array with a specified number of tone variations.
* @param {number} [tones=10] The number of tones to generate.
* @return {Color[]} An array containing tone variations.
*/
function tones(tones = 10) {
return new Array(tones)
.fill()
.map(
(_, index) => this.tone(index / (tones + 1)),
);
}
/**
* Color Schemes
*/
/**
* Create an array with 2 analogous color variations.
* @return {Color[]} An array containing 2 analogous color variations.
*/
function analogous() {
const [h, s, v] = rgb2hsv(this.r, this.g, this.b);
const [r1, g1, b1] = hsv2rgb(h + 30, s, v);
const [r2, g2, b2] = hsv2rgb(h - 30, s, v);
return [
new Color(r1, g1, b1, this.a),
new Color(r2, g2, b2, this.a),
];
}
/**
* Create a complementary color variation.
* @return {Color} A complementary color variation.
*/
function complementary() {
const [h, s, v] = rgb2hsv(this.r, this.g, this.b);
const [r, g, b] = hsv2rgb(h + 180, s, v);
return new Color(r, g, b, this.a);
}
/**
* Create an array with 2 split color variations.
* @return {Color[]} An array containing 2 split color variations.
*/
function split() {
const [h, s, v] = rgb2hsv(this.r, this.g, this.b);
const [r1, g1, b1] = hsv2rgb(h + 150, s, v);
const [r2, g2, b2] = hsv2rgb(h - 150, s, v);
return [
new Color(r1, g1, b1, this.a),
new Color(r2, g2, b2, this.a),
];
}
/**
* Create an array with 3 tetradic color variations.
* @return {Color[]} An array containing 3 tetradic color variations.
*/
function tetradic() {
const [h, s, v] = rgb2hsv(this.r, this.g, this.b);
const [r1, g1, b1] = hsv2rgb(h + 60, s, v);
const [r2, g2, b2] = hsv2rgb(h + 180, s, v);
const [r3, g3, b3] = hsv2rgb(h - 120, s, v);
return [
new Color(r1, g1, b1, this.a),
new Color(r2, g2, b2, this.a),
new Color(r3, g3, b3, this.a),
];
}
/**
* Create an array with 2 triadic color variations.
* @return {Color[]} An array containing 2 triadic color variations.
*/
function triadic() {
const [h, s, v] = rgb2hsv(this.r, this.g, this.b);
const [r1, g1, b1] = hsv2rgb(h + 120, s, v);
const [r2, g2, b2] = hsv2rgb(h - 120, s, v);
return [
new Color(r1, g1, b1, this.a),
new Color(r2, g2, b2, this.a),
];
}
Color.contrast = contrast;
Color.dist = dist;
Color.findContrast = findContrast;
Color.fromCMY = fromCMY;
Color.fromCMYK = fromCMYK;
Color.fromHexString = fromHexString;
Color.fromHSL = fromHSL;
Color.fromHSLString = fromHSLString;
Color.fromHSV = fromHSV;
Color.fromRGB = fromRGB;
Color.fromRGBString = fromRGBString;
Color.fromString = fromString;
Color.mix = mix;
Color.multiply = multiply;
const proto = Color.prototype;
proto.analogous = analogous;
proto.complementary = complementary;
proto.darken = darken;
proto.getAlpha = getAlpha;
proto.getBrightness = getBrightness;
proto.getHue = getHue;
proto.getSaturation = getSaturation;
proto.invert = invert;
proto.label = label;
proto.lighten = lighten;
proto.luma = luma;
proto.palette = palette;
proto.setAlpha = setAlpha;
proto.setBrightness = setBrightness;
proto.setHue = setHue;
proto.setSaturation = setSaturation;
proto.shade = shade;
proto.shades = shades;
proto.split = split;
proto.tetradic = tetradic;
proto.tint = tint;
proto.tints = tints;
proto.toHexString = toHexString;
proto.toHSLString = toHSLString;
proto.toRGBString = toRGBString;
proto.toString = toString;
proto.tone = tone;
proto.tones = tones;
proto.triadic = triadic;
return Color;
}));
//# sourceMappingURL=frost-color.js.map