UNPKG

toosoon-utils

Version:
348 lines (347 loc) 14.2 kB
import { clamp, lerp } from '../../maths'; import Color from './Color'; /** * Utility class for generating and processing color scales * * @exports * @class ColorScale */ export default class ColorScale { isColorScale = true; type = 'ColorScale'; /** * Array of colors composing this color scale */ colors = []; *[Symbol.iterator]() { yield* this.colors; } /** * Pick an interpolated color from this color scale * * @param {number} t Normalized time value to interpolate * @returns {Color} Interpolated color on this scale */ getColor(t) { const index = lerp(t, 0, this.length - 1); return this.colors[index]; } /** * Set this color scale colors to an array of interpolated colors * * @param {ColorInterpolation} interpolation Type of interpolation used for generation * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @returns {this} */ generate(interpolation, length, color1, color2, params) { this.colors = ColorScale.generate(interpolation, length, color1, color2, params); return this; } /** * Set this color scale colors to an array of interpolated colors in the RGB color space * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number} [params.power] Interpolation exponent * @returns {this} */ generateRgb(length, color1, color2, params) { this.colors = ColorScale.generateRgb(length, color1, color2, params); return this; } /** * Set this color scale colors to an array of interpolated colors in the HSL color space * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number|number[]} [params.power] Interpolation exponent(s) : [h, s, l] * @param {string} [params.hueMode] Hue interpolation mode. Can be 'direct' | 'shortest' | 'longest' * @returns {this} */ generateHsl(length, color1, color2, params) { this.colors = ColorScale.generateHsl(length, color1, color2, params); return this; } /** * Set this color scale colors to an array of interpolated colors in the HSB color space * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number|number[]} [params.power] Interpolation exponent(s) : [h, s, b] * @param {string} [params.hueMode] Hue interpolation mode. Can be 'direct' | 'shortest' | 'longest' * @returns {this} */ generateHsb(length, color1, color2, params) { this.colors = ColorScale.generateHsb(length, color1, color2, params); return this; } /** * Set this color scale colors to an array of interpolated colors following HCL Qualitative color palettes algorithm * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {string} [params.hueMode] Hue interpolation mode. Can be 'direct' | 'shortest' | 'longest' * @returns {this} */ generateQualitative(length, color1, color2, params) { this.colors = ColorScale.generateQualitative(length, color1, color2, params); return this; } /** * Set this color scale colors to an array of interpolated colors following HCL Sequential color palettes algorithm * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {number|number[]} [params.power] Interpolation exponent(s) : [c, l] * @param {string} [params.hueMode] Hue interpolation mode. Can be 'direct' | 'shortest' | 'longest' * @param {number} [params.chromaMax] Maximum chroma value * @returns {this} */ generateSequential(length, color1, color2, params) { this.colors = ColorScale.generateSequential(length, color1, color2, params); return this; } /** * Set this color scale colors to an array of interpolated colors following HCL Diverging color palettes algorithm * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number|number[]} [params.power] Interpolation exponent(s) : ([c, l]) * @returns {this} */ generateDiverging(length, color1, color2, params) { this.colors = ColorScale.generateDiverging(length, color1, color2, params); return this; } /** * Process all colors composing this scale * * @param {ColorScaleProcessingParameters} [params] Processing parameters * @returns {this} */ process(params) { ColorScale.process(this, params); return this; } /** * Amount of colors composing this color scale */ get length() { return this.colors.length; } /** * Generate an array of interpolated colors * * @param {ColorInterpolation} interpolation Type of interpolation used for generation * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @returns {Color[]} Generated color scale */ static generate(interpolation, length, color1, color2, params) { const interpolate = ColorScale._getInterpolateFunction(interpolation, color1, color2, params); const colors = []; for (let i = 0; i < length; i++) { const t = i / (length - 1); const color = interpolate(t); colors.push(color); } return colors; } /** * Generate an array of interpolated colors in the RGB color space * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number} [params.power] Interpolation exponent * @returns {Color[]} Generated RGB color scale */ static generateRgb(length, color1, color2, params) { return ColorScale.generate('rgb', length, color1, color2, params); } /** * Generate an array of interpolated colors in the HSL color space * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number|number[]} [params.power] Interpolation exponent(s) : [h, s, l] * @param {string} [params.hueMode] Hue interpolation mode. Can be 'direct' | 'shortest' | 'longest' * @returns {Color[]} Generated HSL color scale */ static generateHsl(length, color1, color2, params) { return ColorScale.generate('hsl', length, color1, color2, params); } /** * Generate an array of interpolated colors in the HSB color space * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number|number[]} [params.power] Interpolation exponent(s) : [h, s, b] * @param {string} [params.hueMode] Hue interpolation mode. Can be 'direct' | 'shortest' | 'longest' * @returns {Color[]} Generated HSB color scale */ static generateHsb(length, color1, color2, params) { return ColorScale.generate('hsb', length, color1, color2, params); } /** * Generate an array of interpolated colors following HCL Qualitative color palettes algorithm * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {string} [params.hueMode] Hue interpolation mode. Can be 'direct' | 'shortest' | 'longest' * @returns {Color[]} Generated qualitative color scale */ static generateQualitative(length, color1, color2, params) { return ColorScale.generate('qualitative', length, color1, color2, params); } /** * Generate an array of interpolated colors following HCL Sequential color palettes algorithm * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number|number[]} [params.power] Interpolation exponent(s) : [c, l] * @param {string} [params.hueMode] Hue interpolation mode. Can be 'direct' | 'shortest' | 'longest' * @param {number} [params.chromaMax] Maximum chroma value * @returns {Color[]} Generated sequential color scale */ static generateSequential(length, color1, color2, params) { return ColorScale.generate('sequential', length, color1, color2, params); } /** * Generate an array of interpolated colors following HCL Diverging color palettes algorithm * * @param {number} length Amount of colors to generate * @param {Color} color1 Start color * @param {Color} color2 End color * @param {object} [params] Interpolation parameters * @param {number|number[]} [params.power] Interpolation exponent(s) : ([c, l]) * @returns {Color[]} Generated diverging color scale */ static generateDiverging(length, color1, color2, params) { return ColorScale.generate('diverging', length, color1, color2, params); } /** * Process a given value * * @param {number} value Value to process * @param {ColorScaleProcessingTarget} [target] Processing target * @returns {number} Processed value */ static processValue(value, target) { if (typeof target === 'undefined') return value; if (typeof target === 'number') return target; if (Array.isArray(target)) return clamp(value, target[0], target[1]); return value; } /** * Process a given color * * @param {Color} color Color to process * @param {ColorScaleProcessingParameters} [params] Processing parameters * @returns {Color} Processed color */ static processColor(color, params = {}) { if (params.hsl) { let [h, s, l] = color.hsl; h = this.processValue(h, params.hsl.hue); s = this.processValue(s, params.hsl.saturation); l = this.processValue(l, params.hsl.lightness); color.setHsl([h, s, l]); } if (params.hsb) { let [h, s, b] = color.hsb; h = this.processValue(h, params.hsb.hue); s = this.processValue(s, params.hsb.saturation); b = this.processValue(b, params.hsb.brightness); color.setHsb([h, s, b]); } if (params.hcl) { let [h, c, l] = color.hcl; h = this.processValue(h, params.hcl.hue); c = this.processValue(c, params.hcl.chroma); l = this.processValue(l, params.hcl.luminance); color.setHcl([h, c, l]); } return color; } /** * Process all colors composing a given scale * * @param {ColorScale} scale Color scale to process * @param {ColorScaleProcessingParameters} [params] Processing parameters * @returns {ColorScale} Processed color scale */ static process(scale, params = {}) { scale.colors.forEach((color) => this.processColor(color, params)); return scale; } static _getInterpolateFunction(interpolation, color1, color2, params) { switch (interpolation) { case 'rgb': default: return (t) => { const rgb = Color.lerpRgb(t, color1.rgb, color2.rgb, params); const color = new Color().setRgb(rgb); return color; }; case 'hsl': return (t) => { const hsl = Color.lerpHsl(t, color1.hsl, color2.hsl, params); const color = new Color().setHsl(hsl); return color; }; case 'hsb': return (t) => { const hsb = Color.lerpHsb(t, color1.hsb, color2.hsb, params); const color = new Color().setHsb(hsb); return color; }; case 'qualitative': return (t) => { const hcl = Color.interpolateQualitative(t, color1.hcl, color2.hcl, params); const color = new Color().setHcl(hcl); return color; }; case 'sequential': return (t) => { const hcl = Color.interpolateSequential(t, color1.hcl, color2.hcl, params); const color = new Color().setHcl(hcl); return color; }; case 'diverging': return (t) => { const hcl = Color.interpolateDiverging(t, color1.hcl, color2.hcl, params); const color = new Color().setHcl(hcl); return color; }; } } }