UNPKG

@mapbox/mapbox-gl-style-spec

Version:

a specification for mapbox gl styles

137 lines (119 loc) 3.46 kB
import Color from './color'; import {number as interpolateNumber} from './interpolate'; type LABColor = { l: number; a: number; b: number; alpha: number; }; type HCLColor = { h: number; c: number; l: number; alpha: number; }; // Constants const Xn = 0.950470, // D65 standard referent Yn = 1, Zn = 1.088830, t0 = 4 / 29, t1 = 6 / 29, t2 = 3 * t1 * t1, t3 = t1 * t1 * t1, deg2rad = Math.PI / 180, rad2deg = 180 / Math.PI; // Utilities function xyz2lab(t: number) { return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0; } function lab2xyz(t: number) { return t > t1 ? t * t * t : t2 * (t - t0); } function xyz2rgb(x: number) { return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055); } function rgb2xyz(x: number) { x /= 255; return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); } // LAB function rgbToLab(rgbColor: Color): LABColor { const b = rgb2xyz(rgbColor.r), a = rgb2xyz(rgbColor.g), l = rgb2xyz(rgbColor.b), x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn), y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn), z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn); return { l: 116 * y - 16, a: 500 * (x - y), b: 200 * (y - z), alpha: rgbColor.a }; } function labToRgb(labColor: LABColor): Color { let y = (labColor.l + 16) / 116, x = isNaN(labColor.a) ? y : y + labColor.a / 500, z = isNaN(labColor.b) ? y : y - labColor.b / 200; y = Yn * lab2xyz(y); x = Xn * lab2xyz(x); z = Zn * lab2xyz(z); return new Color( xyz2rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z), xyz2rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z), labColor.alpha ); } function interpolateLab(from: LABColor, to: LABColor, t: number): LABColor { return { l: interpolateNumber(from.l, to.l, t), a: interpolateNumber(from.a, to.a, t), b: interpolateNumber(from.b, to.b, t), alpha: interpolateNumber(from.alpha, to.alpha, t) }; } // HCL function rgbToHcl(rgbColor: Color): HCLColor { const {l, a, b} = rgbToLab(rgbColor); const h = Math.atan2(b, a) * rad2deg; return { h: h < 0 ? h + 360 : h, c: Math.sqrt(a * a + b * b), l, alpha: rgbColor.a }; } function hclToRgb(hclColor: HCLColor): Color { const h = hclColor.h * deg2rad, c = hclColor.c, l = hclColor.l; return labToRgb({ l, a: Math.cos(h) * c, b: Math.sin(h) * c, alpha: hclColor.alpha }); } function interpolateHue(a: number, b: number, t: number) { const d = b - a; return a + t * (d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d); } function interpolateHcl(from: HCLColor, to: HCLColor, t: number): HCLColor { return { h: interpolateHue(from.h, to.h, t), c: interpolateNumber(from.c, to.c, t), l: interpolateNumber(from.l, to.l, t), alpha: interpolateNumber(from.alpha, to.alpha, t) }; } export const lab = { forward: rgbToLab, reverse: labToRgb, interpolate: interpolateLab } as const; export const hcl = { forward: rgbToHcl, reverse: hclToRgb, interpolate: interpolateHcl } as const;