UNPKG

seed-color

Version:

Generate random colors from a seed

413 lines (412 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * Color */ class Color { /** * RGB Array: [r, g, b] */ get rgb() { return [this.r, this.g, this.b]; } set rgb(rgb) { this.r = rgb[0]; this.g = rgb[1]; this.b = rgb[2]; } /** * Hex to RGB */ static parseHex(hex) { if (hex[0] === '#') { hex = hex.substr(1); } switch (hex.length) { case 6: return { r: parseInt(hex.substr(0, 2), 16), g: parseInt(hex.substr(2, 2), 16), b: parseInt(hex.substr(4, 2), 16) }; case 3: return { r: parseInt(hex.substr(0, 1).repeat(2), 16), g: parseInt(hex.substr(1, 1).repeat(2), 16), b: parseInt(hex.substr(2, 1).repeat(2), 16) }; default: throw 'Invalid color code'; } } /** * Analyze string */ static parseString(x) { if (x[0] === '#') { return Color.parseHex(x); } else { return null; } } static rgbToHsv(x, y, z) { let r; let g; let b; if (x && y && z) { r = x; g = y; b = z; } else if (typeof x === 'string') { const rgb = Color.parseString(x); if (rgb !== null) { r = rgb.r; g = rgb.g; b = rgb.b; } else { throw 'unknown color string'; } } else if (Array.isArray(x)) { r = x[0]; g = x[1]; b = x[2]; } else if (x.hasOwnProperty('r') && x.hasOwnProperty('g') && x.hasOwnProperty('b')) { r = x.r; g = x.g; b = x.b; } else { throw 'invalid argument'; } const max = Math.max(r, g, b); const min = Math.min(r, g, b); const d = max - min; let h; let s; const v = max; if (max === 0) { s = 0; } else { s = d / max; } if (max === min) { h = 0; } else { switch (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; } h /= 6; } return { h, s, v }; } static rgbToHsl(x, y, z) { let r; let g; let b; if (x && y && z) { r = x; g = y; b = z; } else if (typeof x === 'string') { const rgb = Color.parseString(x); if (rgb !== null) { r = rgb.r; g = rgb.g; b = rgb.b; } else { throw 'unknown color string'; } } else if (Array.isArray(x)) { r = x[0]; g = x[1]; b = x[2]; } else if (x.hasOwnProperty('r') && x.hasOwnProperty('g') && x.hasOwnProperty('b')) { r = x.r; g = x.g; b = x.b; } else { throw 'invalid argument'; } const max = Math.max(r, g, b); const min = Math.min(r, g, b); const d = max - min; let h; const l = (max + min) / 2; let s; if (max === min) { h = 0; s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (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; } h /= 6; } return { h, s, l }; } static hsvToRgb(x, y, z) { let r; let g; let b; let h; let s; let v; if (typeof x === 'object') { h = x.h; s = x.s; v = x.v; } else { h = x; s = y; v = z; } while (h < 0) { h += 360; } h = h % 360; if (s === 0) { v = Math.round(v); return { r: v, g: v, b: v }; } s = s / 255; const i = Math.floor(h / 60) % 6; const f = (h / 60) - i; const p = v * (1 - s); const q = v * (1 - f * s); const t = v * (1 - (1 - f) * s); switch (i) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; case 5: r = v; g = p; b = q; break; } return { r: Math.round(r), g: Math.round(g), b: Math.round(b) }; } static hslToRgb(x, y, z) { let r; let g; let b; let h; let s; let l; if (typeof x === 'object') { h = x.h; s = x.s; l = x.l; } else { h = x; s = y; l = z; } if (s === 0) { r = g = b = l; // achromatic } else { const hueToRgb = (p, q, t) => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; }; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hueToRgb(p, q, h + 1 / 3); g = hueToRgb(p, q, h); b = hueToRgb(p, q, h - 1 / 3); } return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) }; } constructor(x, y, z) { // r, g, b if (x != null && y != null && z != null) { this.r = x; this.g = y; this.b = z; // Color name or Color code } else if (typeof x === 'string') { const rgb = Color.parseString(x); if (rgb !== null) { this.setRGB(rgb); } else { throw 'unknown color string'; } // RGB, HSV or HSL object } else if (typeof x === 'object') { if (x.r != null && x.g != null && x.b != null) { this.setRGB(x); } else if (x.h != null && x.s != null && x.v != null) { this.setHSV(x); } else if (x.h != null && x.s != null && x.l != null) { this.setHSL(x); } else { throw 'Invalid color space'; } // Other } else { throw 'Invalid arugument'; } } /** * Get an RGB object that represent this color */ toRGB() { return { r: this.r, g: this.g, b: this.b }; } /** * Set the color using the RGB */ setRGB(rgb) { this.r = rgb.r; this.g = rgb.g; this.b = rgb.b; return this; } /** * Get HSV object */ toHSV() { return Color.rgbToHsv(this); } setHSV(x, y, z) { this.setRGB(Color.hsvToRgb(x, y, z)); } /** * Get HSL object */ toHSL() { return Color.rgbToHsl(this); } setHSL(x, y, z) { this.setRGB(Color.hslToRgb(x, y, z)); } /** * Get color code */ toHex(withNumberSign = true) { const rHex1 = this.r.toString(16); const gHex1 = this.g.toString(16); const bHex1 = this.b.toString(16); const rHex2 = `0${rHex1}`.slice(-2); const gHex2 = `0${gHex1}`.slice(-2); const bHex2 = `0${bHex1}`.slice(-2); return withNumberSign ? `#${rHex2}${gHex2}${bHex2}` : rHex2 + gHex2 + bHex2; } /** * Get luminance of this color */ luminance(rWeight = 0.2126, gWeight = 0.7152, bWeight = 0.0722) { return ((rWeight * this.r / 255) + (gWeight * this.g / 255) + (bWeight * this.b / 255)); } contrast(threshold = 0.43, dark, light) { return this.luminance() > threshold ? dark || new Color(0, 0, 0) : light || new Color(255, 255, 255); } /** * Invert this color */ invert() { this.r = 255 - this.r; this.g = 255 - this.g; this.b = 255 - this.b; return this; } /** * Clone this instance */ clone() { return new Color(this); } } exports.default = Color; function clamp(v, max) { return Math.min(Math.max(v, 0), max); }