chartjs-chart-funnel
Version:
Chart.js module for charting funnel charts
1,664 lines (1,465 loc) • 124 kB
JavaScript
/**
* chartjs-chart-funnel
* https://github.com/sgratzl/chartjs-chart-funnel
*
* Copyright (c) 2021 Samuel Gratzl <samu@sgratzl.com>
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('chart.js'), require('chart.js/helpers')) :
typeof define === 'function' && define.amd ? define(['exports', 'chart.js', 'chart.js/helpers'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ChartFunnel = {}, global.Chart, global.Chart.helpers));
})(this, (function (exports, chart_js, helpers) { 'use strict';
const { min: min$4, max: max$4 } = Math;
var limit = (x, low = 0, high = 1) => {
return min$4(max$4(low, x), high);
};
var clip_rgb = (rgb) => {
rgb._clipped = false;
rgb._unclipped = rgb.slice(0);
for (let i = 0; i <= 3; i++) {
if (i < 3) {
if (rgb[i] < 0 || rgb[i] > 255) rgb._clipped = true;
rgb[i] = limit(rgb[i], 0, 255);
} else if (i === 3) {
rgb[i] = limit(rgb[i], 0, 1);
}
}
return rgb;
};
// ported from jQuery's $.type
const classToType = {};
for (let name of [
'Boolean',
'Number',
'String',
'Function',
'Array',
'Date',
'RegExp',
'Undefined',
'Null'
]) {
classToType[`[object ${name}]`] = name.toLowerCase();
}
function type (obj) {
return classToType[Object.prototype.toString.call(obj)] || 'object';
}
var unpack = (args, keyOrder = null) => {
// if called with more than 3 arguments, we return the arguments
if (args.length >= 3) return Array.prototype.slice.call(args);
// with less than 3 args we check if first arg is object
// and use the keyOrder string to extract and sort properties
if (type(args[0]) == 'object' && keyOrder) {
return keyOrder
.split('')
.filter((k) => args[0][k] !== undefined)
.map((k) => args[0][k]);
}
// otherwise we just return the first argument
// (which we suppose is an array of args)
return args[0].slice(0);
};
var last = (args) => {
if (args.length < 2) return null;
const l = args.length - 1;
if (type(args[l]) == 'string') return args[l].toLowerCase();
return null;
};
const { PI: PI$2, min: min$3, max: max$3 } = Math;
const rnd2 = (a) => Math.round(a * 100) / 100;
const rnd3 = (a) => Math.round(a * 100) / 100;
const TWOPI = PI$2 * 2;
const PITHIRD = PI$2 / 3;
const DEG2RAD = PI$2 / 180;
const RAD2DEG = 180 / PI$2;
/**
* Reverse the first three elements of an array
*
* @param {any[]} arr
* @returns {any[]}
*/
function reverse3(arr) {
return [...arr.slice(0, 3).reverse(), ...arr.slice(3)];
}
var input = {
format: {},
autodetect: []
};
class Color {
constructor(...args) {
const me = this;
if (
type(args[0]) === 'object' &&
args[0].constructor &&
args[0].constructor === this.constructor
) {
// the argument is already a Color instance
return args[0];
}
// last argument could be the mode
let mode = last(args);
let autodetect = false;
if (!mode) {
autodetect = true;
if (!input.sorted) {
input.autodetect = input.autodetect.sort((a, b) => b.p - a.p);
input.sorted = true;
}
// auto-detect format
for (let chk of input.autodetect) {
mode = chk.test(...args);
if (mode) break;
}
}
if (input.format[mode]) {
const rgb = input.format[mode].apply(
null,
autodetect ? args : args.slice(0, -1)
);
me._rgb = clip_rgb(rgb);
} else {
throw new Error('unknown format: ' + args);
}
// add alpha channel
if (me._rgb.length === 3) me._rgb.push(1);
}
toString() {
if (type(this.hex) == 'function') return this.hex();
return `[${this._rgb.join(',')}]`;
}
}
// this gets updated automatically
const version = '3.1.2';
const chroma = (...args) => {
return new Color(...args);
};
chroma.version = version;
/**
X11 color names
http://www.w3.org/TR/css3-color/#svg-color
*/
const w3cx11 = {
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',
darkgreen: '#006400',
darkgrey: '#a9a9a9',
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',
green: '#008000',
greenyellow: '#adff2f',
grey: '#808080',
honeydew: '#f0fff0',
hotpink: '#ff69b4',
indianred: '#cd5c5c',
indigo: '#4b0082',
ivory: '#fffff0',
khaki: '#f0e68c',
laserlemon: '#ffff54',
lavender: '#e6e6fa',
lavenderblush: '#fff0f5',
lawngreen: '#7cfc00',
lemonchiffon: '#fffacd',
lightblue: '#add8e6',
lightcoral: '#f08080',
lightcyan: '#e0ffff',
lightgoldenrod: '#fafad2',
lightgoldenrodyellow: '#fafad2',
lightgray: '#d3d3d3',
lightgreen: '#90ee90',
lightgrey: '#d3d3d3',
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',
maroon2: '#7f0000',
maroon3: '#b03060',
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',
purple2: '#7f007f',
purple3: '#a020f0',
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 RE_HEX = /^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
const RE_HEXA = /^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/;
const hex2rgb = (hex) => {
if (hex.match(RE_HEX)) {
// remove optional leading #
if (hex.length === 4 || hex.length === 7) {
hex = hex.substr(1);
}
// expand short-notation to full six-digit
if (hex.length === 3) {
hex = hex.split('');
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
const u = parseInt(hex, 16);
const r = u >> 16;
const g = (u >> 8) & 0xff;
const b = u & 0xff;
return [r, g, b, 1];
}
// match rgba hex format, eg #FF000077
if (hex.match(RE_HEXA)) {
if (hex.length === 5 || hex.length === 9) {
// remove optional leading #
hex = hex.substr(1);
}
// expand short-notation to full eight-digit
if (hex.length === 4) {
hex = hex.split('');
hex =
hex[0] +
hex[0] +
hex[1] +
hex[1] +
hex[2] +
hex[2] +
hex[3] +
hex[3];
}
const u = parseInt(hex, 16);
const r = (u >> 24) & 0xff;
const g = (u >> 16) & 0xff;
const b = (u >> 8) & 0xff;
const a = Math.round(((u & 0xff) / 0xff) * 100) / 100;
return [r, g, b, a];
}
// we used to check for css colors here
// if _input.css? and rgb = _input.css hex
// return rgb
throw new Error(`unknown hex color: ${hex}`);
};
const { round: round$5 } = Math;
const rgb2hex = (...args) => {
let [r, g, b, a] = unpack(args, 'rgba');
let mode = last(args) || 'auto';
if (a === undefined) a = 1;
if (mode === 'auto') {
mode = a < 1 ? 'rgba' : 'rgb';
}
r = round$5(r);
g = round$5(g);
b = round$5(b);
const u = (r << 16) | (g << 8) | b;
let str = '000000' + u.toString(16); //#.toUpperCase();
str = str.substr(str.length - 6);
let hxa = '0' + round$5(a * 255).toString(16);
hxa = hxa.substr(hxa.length - 2);
switch (mode.toLowerCase()) {
case 'rgba':
return `#${str}${hxa}`;
case 'argb':
return `#${hxa}${str}`;
default:
return `#${str}`;
}
};
Color.prototype.name = function () {
const hex = rgb2hex(this._rgb, 'rgb');
for (let n of Object.keys(w3cx11)) {
if (w3cx11[n] === hex) return n.toLowerCase();
}
return hex;
};
input.format.named = (name) => {
name = name.toLowerCase();
if (w3cx11[name]) return hex2rgb(w3cx11[name]);
throw new Error('unknown color name: ' + name);
};
input.autodetect.push({
p: 5,
test: (h, ...rest) => {
if (!rest.length && type(h) === 'string' && w3cx11[h.toLowerCase()]) {
return 'named';
}
}
});
Color.prototype.alpha = function (a, mutate = false) {
if (a !== undefined && type(a) === 'number') {
if (mutate) {
this._rgb[3] = a;
return this;
}
return new Color([this._rgb[0], this._rgb[1], this._rgb[2], a], 'rgb');
}
return this._rgb[3];
};
Color.prototype.clipped = function () {
return this._rgb._clipped || false;
};
const labConstants = {
// Corresponds roughly to RGB brighter/darker
Kn: 18,
// D65 standard referent
labWhitePoint: 'd65',
Xn: 0.95047,
Yn: 1,
Zn: 1.08883,
t0: 0.137931034, // 4 / 29
t1: 0.206896552, // 6 / 29
t2: 0.12841855, // 3 * t1 * t1
t3: 0.008856452, // t1 * t1 * t1,
kE: 216.0 / 24389.0,
kKE: 8.0,
kK: 24389.0 / 27.0,
RefWhiteRGB: {
// sRGB
X: 0.95047,
Y: 1,
Z: 1.08883
},
MtxRGB2XYZ: {
m00: 0.4124564390896922,
m01: 0.21267285140562253,
m02: 0.0193338955823293,
m10: 0.357576077643909,
m11: 0.715152155287818,
m12: 0.11919202588130297,
m20: 0.18043748326639894,
m21: 0.07217499330655958,
m22: 0.9503040785363679
},
MtxXYZ2RGB: {
m00: 3.2404541621141045,
m01: -0.9692660305051868,
m02: 0.055643430959114726,
m10: -1.5371385127977166,
m11: 1.8760108454466942,
m12: -0.2040259135167538,
m20: -0.498531409556016,
m21: 0.041556017530349834,
m22: 1.0572251882231791
},
// used in rgb2xyz
As: 0.9414285350000001,
Bs: 1.040417467,
Cs: 1.089532651,
MtxAdaptMa: {
m00: 0.8951,
m01: -0.7502,
m02: 0.0389,
m10: 0.2664,
m11: 1.7135,
m12: -0.0685,
m20: -0.1614,
m21: 0.0367,
m22: 1.0296
},
MtxAdaptMaI: {
m00: 0.9869929054667123,
m01: 0.43230526972339456,
m02: -0.008528664575177328,
m10: -0.14705425642099013,
m11: 0.5183602715367776,
m12: 0.04004282165408487,
m20: 0.15996265166373125,
m21: 0.0492912282128556,
m22: 0.9684866957875502
}
};
// taken from https://de.mathworks.com/help/images/ref/whitepoint.html
const ILLUMINANTS = new Map([
// ASTM E308-01
['a', [1.0985, 0.35585]],
// Wyszecki & Stiles, p. 769
['b', [1.0985, 0.35585]],
// C ASTM E308-01
['c', [0.98074, 1.18232]],
// D50 (ASTM E308-01)
['d50', [0.96422, 0.82521]],
// D55 (ASTM E308-01)
['d55', [0.95682, 0.92149]],
// D65 (ASTM E308-01)
['d65', [0.95047, 1.08883]],
// E (ASTM E308-01)
['e', [1, 1, 1]],
// F2 (ASTM E308-01)
['f2', [0.99186, 0.67393]],
// F7 (ASTM E308-01)
['f7', [0.95041, 1.08747]],
// F11 (ASTM E308-01)
['f11', [1.00962, 0.6435]],
['icc', [0.96422, 0.82521]]
]);
function setLabWhitePoint(name) {
const ill = ILLUMINANTS.get(String(name).toLowerCase());
if (!ill) {
throw new Error('unknown Lab illuminant ' + name);
}
labConstants.labWhitePoint = name;
labConstants.Xn = ill[0];
labConstants.Zn = ill[1];
}
function getLabWhitePoint() {
return labConstants.labWhitePoint;
}
/*
* L* [0..100]
* a [-100..100]
* b [-100..100]
*/
const lab2rgb = (...args) => {
args = unpack(args, 'lab');
const [L, a, b] = args;
const [x, y, z] = lab2xyz(L, a, b);
const [r, g, b_] = xyz2rgb(x, y, z);
return [r, g, b_, args.length > 3 ? args[3] : 1];
};
const lab2xyz = (L, a, b) => {
const { kE, kK, kKE, Xn, Yn, Zn } = labConstants;
const fy = (L + 16.0) / 116.0;
const fx = 0.002 * a + fy;
const fz = fy - 0.005 * b;
const fx3 = fx * fx * fx;
const fz3 = fz * fz * fz;
const xr = fx3 > kE ? fx3 : (116.0 * fx - 16.0) / kK;
const yr = L > kKE ? Math.pow((L + 16.0) / 116.0, 3.0) : L / kK;
const zr = fz3 > kE ? fz3 : (116.0 * fz - 16.0) / kK;
const x = xr * Xn;
const y = yr * Yn;
const z = zr * Zn;
return [x, y, z];
};
const compand = (linear) => {
/* sRGB */
const sign = Math.sign(linear);
linear = Math.abs(linear);
return (
(linear <= 0.0031308
? linear * 12.92
: 1.055 * Math.pow(linear, 1.0 / 2.4) - 0.055) * sign
);
};
const xyz2rgb = (x, y, z) => {
const { MtxAdaptMa, MtxAdaptMaI, MtxXYZ2RGB, RefWhiteRGB, Xn, Yn, Zn } =
labConstants;
const As = Xn * MtxAdaptMa.m00 + Yn * MtxAdaptMa.m10 + Zn * MtxAdaptMa.m20;
const Bs = Xn * MtxAdaptMa.m01 + Yn * MtxAdaptMa.m11 + Zn * MtxAdaptMa.m21;
const Cs = Xn * MtxAdaptMa.m02 + Yn * MtxAdaptMa.m12 + Zn * MtxAdaptMa.m22;
const Ad =
RefWhiteRGB.X * MtxAdaptMa.m00 +
RefWhiteRGB.Y * MtxAdaptMa.m10 +
RefWhiteRGB.Z * MtxAdaptMa.m20;
const Bd =
RefWhiteRGB.X * MtxAdaptMa.m01 +
RefWhiteRGB.Y * MtxAdaptMa.m11 +
RefWhiteRGB.Z * MtxAdaptMa.m21;
const Cd =
RefWhiteRGB.X * MtxAdaptMa.m02 +
RefWhiteRGB.Y * MtxAdaptMa.m12 +
RefWhiteRGB.Z * MtxAdaptMa.m22;
const X1 =
(x * MtxAdaptMa.m00 + y * MtxAdaptMa.m10 + z * MtxAdaptMa.m20) *
(Ad / As);
const Y1 =
(x * MtxAdaptMa.m01 + y * MtxAdaptMa.m11 + z * MtxAdaptMa.m21) *
(Bd / Bs);
const Z1 =
(x * MtxAdaptMa.m02 + y * MtxAdaptMa.m12 + z * MtxAdaptMa.m22) *
(Cd / Cs);
const X2 =
X1 * MtxAdaptMaI.m00 + Y1 * MtxAdaptMaI.m10 + Z1 * MtxAdaptMaI.m20;
const Y2 =
X1 * MtxAdaptMaI.m01 + Y1 * MtxAdaptMaI.m11 + Z1 * MtxAdaptMaI.m21;
const Z2 =
X1 * MtxAdaptMaI.m02 + Y1 * MtxAdaptMaI.m12 + Z1 * MtxAdaptMaI.m22;
const r = compand(
X2 * MtxXYZ2RGB.m00 + Y2 * MtxXYZ2RGB.m10 + Z2 * MtxXYZ2RGB.m20
);
const g = compand(
X2 * MtxXYZ2RGB.m01 + Y2 * MtxXYZ2RGB.m11 + Z2 * MtxXYZ2RGB.m21
);
const b = compand(
X2 * MtxXYZ2RGB.m02 + Y2 * MtxXYZ2RGB.m12 + Z2 * MtxXYZ2RGB.m22
);
return [r * 255, g * 255, b * 255];
};
const rgb2lab = (...args) => {
const [r, g, b, ...rest] = unpack(args, 'rgb');
const [x, y, z] = rgb2xyz(r, g, b);
const [L, a, b_] = xyz2lab(x, y, z);
return [L, a, b_, ...(rest.length > 0 && rest[0] < 1 ? [rest[0]] : [])];
};
function xyz2lab(x, y, z) {
const { Xn, Yn, Zn, kE, kK } = labConstants;
const xr = x / Xn;
const yr = y / Yn;
const zr = z / Zn;
const fx = xr > kE ? Math.pow(xr, 1.0 / 3.0) : (kK * xr + 16.0) / 116.0;
const fy = yr > kE ? Math.pow(yr, 1.0 / 3.0) : (kK * yr + 16.0) / 116.0;
const fz = zr > kE ? Math.pow(zr, 1.0 / 3.0) : (kK * zr + 16.0) / 116.0;
return [116.0 * fy - 16.0, 500.0 * (fx - fy), 200.0 * (fy - fz)];
}
function gammaAdjustSRGB(companded) {
const sign = Math.sign(companded);
companded = Math.abs(companded);
const linear =
companded <= 0.04045
? companded / 12.92
: Math.pow((companded + 0.055) / 1.055, 2.4);
return linear * sign;
}
const rgb2xyz = (r, g, b) => {
// normalize and gamma adjust
r = gammaAdjustSRGB(r / 255);
g = gammaAdjustSRGB(g / 255);
b = gammaAdjustSRGB(b / 255);
const { MtxRGB2XYZ, MtxAdaptMa, MtxAdaptMaI, Xn, Yn, Zn, As, Bs, Cs } =
labConstants;
let x = r * MtxRGB2XYZ.m00 + g * MtxRGB2XYZ.m10 + b * MtxRGB2XYZ.m20;
let y = r * MtxRGB2XYZ.m01 + g * MtxRGB2XYZ.m11 + b * MtxRGB2XYZ.m21;
let z = r * MtxRGB2XYZ.m02 + g * MtxRGB2XYZ.m12 + b * MtxRGB2XYZ.m22;
const Ad = Xn * MtxAdaptMa.m00 + Yn * MtxAdaptMa.m10 + Zn * MtxAdaptMa.m20;
const Bd = Xn * MtxAdaptMa.m01 + Yn * MtxAdaptMa.m11 + Zn * MtxAdaptMa.m21;
const Cd = Xn * MtxAdaptMa.m02 + Yn * MtxAdaptMa.m12 + Zn * MtxAdaptMa.m22;
let X = x * MtxAdaptMa.m00 + y * MtxAdaptMa.m10 + z * MtxAdaptMa.m20;
let Y = x * MtxAdaptMa.m01 + y * MtxAdaptMa.m11 + z * MtxAdaptMa.m21;
let Z = x * MtxAdaptMa.m02 + y * MtxAdaptMa.m12 + z * MtxAdaptMa.m22;
X *= Ad / As;
Y *= Bd / Bs;
Z *= Cd / Cs;
x = X * MtxAdaptMaI.m00 + Y * MtxAdaptMaI.m10 + Z * MtxAdaptMaI.m20;
y = X * MtxAdaptMaI.m01 + Y * MtxAdaptMaI.m11 + Z * MtxAdaptMaI.m21;
z = X * MtxAdaptMaI.m02 + Y * MtxAdaptMaI.m12 + Z * MtxAdaptMaI.m22;
return [x, y, z];
};
Color.prototype.lab = function () {
return rgb2lab(this._rgb);
};
const lab$1 = (...args) => new Color(...args, 'lab');
Object.assign(chroma, { lab: lab$1, getLabWhitePoint, setLabWhitePoint });
input.format.lab = lab2rgb;
input.autodetect.push({
p: 2,
test: (...args) => {
args = unpack(args, 'lab');
if (type(args) === 'array' && args.length === 3) {
return 'lab';
}
}
});
Color.prototype.darken = function (amount = 1) {
const me = this;
const lab = me.lab();
lab[0] -= labConstants.Kn * amount;
return new Color(lab, 'lab').alpha(me.alpha(), true);
};
Color.prototype.brighten = function (amount = 1) {
return this.darken(-amount);
};
Color.prototype.darker = Color.prototype.darken;
Color.prototype.brighter = Color.prototype.brighten;
Color.prototype.get = function (mc) {
const [mode, channel] = mc.split('.');
const src = this[mode]();
if (channel) {
const i = mode.indexOf(channel) - (mode.substr(0, 2) === 'ok' ? 2 : 0);
if (i > -1) return src[i];
throw new Error(`unknown channel ${channel} in mode ${mode}`);
} else {
return src;
}
};
const { pow: pow$6 } = Math;
const EPS = 1e-7;
const MAX_ITER = 20;
Color.prototype.luminance = function (lum, mode = 'rgb') {
if (lum !== undefined && type(lum) === 'number') {
if (lum === 0) {
// return pure black
return new Color([0, 0, 0, this._rgb[3]], 'rgb');
}
if (lum === 1) {
// return pure white
return new Color([255, 255, 255, this._rgb[3]], 'rgb');
}
// compute new color using...
let cur_lum = this.luminance();
let max_iter = MAX_ITER;
const test = (low, high) => {
const mid = low.interpolate(high, 0.5, mode);
const lm = mid.luminance();
if (Math.abs(lum - lm) < EPS || !max_iter--) {
// close enough
return mid;
}
return lm > lum ? test(low, mid) : test(mid, high);
};
const rgb = (
cur_lum > lum
? test(new Color([0, 0, 0]), this)
: test(this, new Color([255, 255, 255]))
).rgb();
return new Color([...rgb, this._rgb[3]]);
}
return rgb2luminance(...this._rgb.slice(0, 3));
};
const rgb2luminance = (r, g, b) => {
// relative luminance
// see http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
r = luminance_x(r);
g = luminance_x(g);
b = luminance_x(b);
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
};
const luminance_x = (x) => {
x /= 255;
return x <= 0.03928 ? x / 12.92 : pow$6((x + 0.055) / 1.055, 2.4);
};
var index = {};
var mix = (col1, col2, f = 0.5, ...rest) => {
let mode = rest[0] || 'lrgb';
if (!index[mode] && !rest.length) {
// fall back to the first supported mode
mode = Object.keys(index)[0];
}
if (!index[mode]) {
throw new Error(`interpolation mode ${mode} is not defined`);
}
if (type(col1) !== 'object') col1 = new Color(col1);
if (type(col2) !== 'object') col2 = new Color(col2);
return index[mode](col1, col2, f).alpha(
col1.alpha() + f * (col2.alpha() - col1.alpha())
);
};
Color.prototype.mix = Color.prototype.interpolate = function (
col2,
f = 0.5,
...rest
) {
return mix(this, col2, f, ...rest);
};
Color.prototype.premultiply = function (mutate = false) {
const rgb = this._rgb;
const a = rgb[3];
if (mutate) {
this._rgb = [rgb[0] * a, rgb[1] * a, rgb[2] * a, a];
return this;
} else {
return new Color([rgb[0] * a, rgb[1] * a, rgb[2] * a, a], 'rgb');
}
};
const { sin: sin$3, cos: cos$4 } = Math;
const lch2lab = (...args) => {
/*
Convert from a qualitative parameter h and a quantitative parameter l to a 24-bit pixel.
These formulas were invented by David Dalrymple to obtain maximum contrast without going
out of gamut if the parameters are in the range 0-1.
A saturation multiplier was added by Gregor Aisch
*/
let [l, c, h] = unpack(args, 'lch');
if (isNaN(h)) h = 0;
h = h * DEG2RAD;
return [l, cos$4(h) * c, sin$3(h) * c];
};
const lch2rgb = (...args) => {
args = unpack(args, 'lch');
const [l, c, h] = args;
const [L, a, b_] = lch2lab(l, c, h);
const [r, g, b] = lab2rgb(L, a, b_);
return [r, g, b, args.length > 3 ? args[3] : 1];
};
const hcl2rgb = (...args) => {
const hcl = reverse3(unpack(args, 'hcl'));
return lch2rgb(...hcl);
};
const { sqrt: sqrt$4, atan2: atan2$2, round: round$4 } = Math;
const lab2lch = (...args) => {
const [l, a, b] = unpack(args, 'lab');
const c = sqrt$4(a * a + b * b);
let h = (atan2$2(b, a) * RAD2DEG + 360) % 360;
if (round$4(c * 10000) === 0) h = Number.NaN;
return [l, c, h];
};
const rgb2lch = (...args) => {
const [r, g, b, ...rest] = unpack(args, 'rgb');
const [l, a, b_] = rgb2lab(r, g, b);
const [L, c, h] = lab2lch(l, a, b_);
return [L, c, h, ...(rest.length > 0 && rest[0] < 1 ? [rest[0]] : [])];
};
Color.prototype.lch = function () {
return rgb2lch(this._rgb);
};
Color.prototype.hcl = function () {
return reverse3(rgb2lch(this._rgb));
};
const lch$1 = (...args) => new Color(...args, 'lch');
const hcl = (...args) => new Color(...args, 'hcl');
Object.assign(chroma, { lch: lch$1, hcl });
input.format.lch = lch2rgb;
input.format.hcl = hcl2rgb;
['lch', 'hcl'].forEach((m) =>
input.autodetect.push({
p: 2,
test: (...args) => {
args = unpack(args, m);
if (type(args) === 'array' && args.length === 3) {
return m;
}
}
})
);
Color.prototype.saturate = function (amount = 1) {
const me = this;
const lch = me.lch();
lch[1] += labConstants.Kn * amount;
if (lch[1] < 0) lch[1] = 0;
return new Color(lch, 'lch').alpha(me.alpha(), true);
};
Color.prototype.desaturate = function (amount = 1) {
return this.saturate(-amount);
};
Color.prototype.set = function (mc, value, mutate = false) {
const [mode, channel] = mc.split('.');
const src = this[mode]();
if (channel) {
const i = mode.indexOf(channel) - (mode.substr(0, 2) === 'ok' ? 2 : 0);
if (i > -1) {
if (type(value) == 'string') {
switch (value.charAt(0)) {
case '+':
src[i] += +value;
break;
case '-':
src[i] += +value;
break;
case '*':
src[i] *= +value.substr(1);
break;
case '/':
src[i] /= +value.substr(1);
break;
default:
src[i] = +value;
}
} else if (type(value) === 'number') {
src[i] = value;
} else {
throw new Error(`unsupported value for Color.set`);
}
const out = new Color(src, mode);
if (mutate) {
this._rgb = out._rgb;
return this;
}
return out;
}
throw new Error(`unknown channel ${channel} in mode ${mode}`);
} else {
return src;
}
};
Color.prototype.tint = function (f = 0.5, ...rest) {
return mix(this, 'white', f, ...rest);
};
Color.prototype.shade = function (f = 0.5, ...rest) {
return mix(this, 'black', f, ...rest);
};
const rgb$1 = (col1, col2, f) => {
const xyz0 = col1._rgb;
const xyz1 = col2._rgb;
return new Color(
xyz0[0] + f * (xyz1[0] - xyz0[0]),
xyz0[1] + f * (xyz1[1] - xyz0[1]),
xyz0[2] + f * (xyz1[2] - xyz0[2]),
'rgb'
);
};
// register interpolator
index.rgb = rgb$1;
const { sqrt: sqrt$3, pow: pow$5 } = Math;
const lrgb = (col1, col2, f) => {
const [x1, y1, z1] = col1._rgb;
const [x2, y2, z2] = col2._rgb;
return new Color(
sqrt$3(pow$5(x1, 2) * (1 - f) + pow$5(x2, 2) * f),
sqrt$3(pow$5(y1, 2) * (1 - f) + pow$5(y2, 2) * f),
sqrt$3(pow$5(z1, 2) * (1 - f) + pow$5(z2, 2) * f),
'rgb'
);
};
// register interpolator
index.lrgb = lrgb;
const lab = (col1, col2, f) => {
const xyz0 = col1.lab();
const xyz1 = col2.lab();
return new Color(
xyz0[0] + f * (xyz1[0] - xyz0[0]),
xyz0[1] + f * (xyz1[1] - xyz0[1]),
xyz0[2] + f * (xyz1[2] - xyz0[2]),
'lab'
);
};
// register interpolator
index.lab = lab;
var interpolate_hsx = (col1, col2, f, m) => {
let xyz0, xyz1;
if (m === 'hsl') {
xyz0 = col1.hsl();
xyz1 = col2.hsl();
} else if (m === 'hsv') {
xyz0 = col1.hsv();
xyz1 = col2.hsv();
} else if (m === 'hcg') {
xyz0 = col1.hcg();
xyz1 = col2.hcg();
} else if (m === 'hsi') {
xyz0 = col1.hsi();
xyz1 = col2.hsi();
} else if (m === 'lch' || m === 'hcl') {
m = 'hcl';
xyz0 = col1.hcl();
xyz1 = col2.hcl();
} else if (m === 'oklch') {
xyz0 = col1.oklch().reverse();
xyz1 = col2.oklch().reverse();
}
let hue0, hue1, sat0, sat1, lbv0, lbv1;
if (m.substr(0, 1) === 'h' || m === 'oklch') {
[hue0, sat0, lbv0] = xyz0;
[hue1, sat1, lbv1] = xyz1;
}
let sat, hue, lbv, dh;
if (!isNaN(hue0) && !isNaN(hue1)) {
// both colors have hue
if (hue1 > hue0 && hue1 - hue0 > 180) {
dh = hue1 - (hue0 + 360);
} else if (hue1 < hue0 && hue0 - hue1 > 180) {
dh = hue1 + 360 - hue0;
} else {
dh = hue1 - hue0;
}
hue = hue0 + f * dh;
} else if (!isNaN(hue0)) {
hue = hue0;
if ((lbv1 == 1 || lbv1 == 0) && m != 'hsv') sat = sat0;
} else if (!isNaN(hue1)) {
hue = hue1;
if ((lbv0 == 1 || lbv0 == 0) && m != 'hsv') sat = sat1;
} else {
hue = Number.NaN;
}
if (sat === undefined) sat = sat0 + f * (sat1 - sat0);
lbv = lbv0 + f * (lbv1 - lbv0);
return m === 'oklch'
? new Color([lbv, sat, hue], m)
: new Color([hue, sat, lbv], m);
};
const lch = (col1, col2, f) => {
return interpolate_hsx(col1, col2, f, 'lch');
};
// register interpolator
index.lch = lch;
index.hcl = lch;
const num2rgb = (num) => {
if (type(num) == 'number' && num >= 0 && num <= 0xffffff) {
const r = num >> 16;
const g = (num >> 8) & 0xff;
const b = num & 0xff;
return [r, g, b, 1];
}
throw new Error('unknown num color: ' + num);
};
const rgb2num = (...args) => {
const [r, g, b] = unpack(args, 'rgb');
return (r << 16) + (g << 8) + b;
};
Color.prototype.num = function () {
return rgb2num(this._rgb);
};
const num$1 = (...args) => new Color(...args, 'num');
Object.assign(chroma, { num: num$1 });
input.format.num = num2rgb;
input.autodetect.push({
p: 5,
test: (...args) => {
if (
args.length === 1 &&
type(args[0]) === 'number' &&
args[0] >= 0 &&
args[0] <= 0xffffff
) {
return 'num';
}
}
});
const num = (col1, col2, f) => {
const c1 = col1.num();
const c2 = col2.num();
return new Color(c1 + f * (c2 - c1), 'num');
};
// register interpolator
index.num = num;
const { floor: floor$3 } = Math;
/*
* this is basically just HSV with some minor tweaks
*
* hue.. [0..360]
* chroma .. [0..1]
* grayness .. [0..1]
*/
const hcg2rgb = (...args) => {
args = unpack(args, 'hcg');
let [h, c, _g] = args;
let r, g, b;
_g = _g * 255;
const _c = c * 255;
if (c === 0) {
r = g = b = _g;
} else {
if (h === 360) h = 0;
if (h > 360) h -= 360;
if (h < 0) h += 360;
h /= 60;
const i = floor$3(h);
const f = h - i;
const p = _g * (1 - c);
const q = p + _c * (1 - f);
const t = p + _c * f;
const v = p + _c;
switch (i) {
case 0:
[r, g, b] = [v, t, p];
break;
case 1:
[r, g, b] = [q, v, p];
break;
case 2:
[r, g, b] = [p, v, t];
break;
case 3:
[r, g, b] = [p, q, v];
break;
case 4:
[r, g, b] = [t, p, v];
break;
case 5:
[r, g, b] = [v, p, q];
break;
}
}
return [r, g, b, args.length > 3 ? args[3] : 1];
};
const rgb2hcg = (...args) => {
const [r, g, b] = unpack(args, 'rgb');
const minRgb = min$3(r, g, b);
const maxRgb = max$3(r, g, b);
const delta = maxRgb - minRgb;
const c = (delta * 100) / 255;
const _g = (minRgb / (255 - delta)) * 100;
let h;
if (delta === 0) {
h = Number.NaN;
} else {
if (r === maxRgb) h = (g - b) / delta;
if (g === maxRgb) h = 2 + (b - r) / delta;
if (b === maxRgb) h = 4 + (r - g) / delta;
h *= 60;
if (h < 0) h += 360;
}
return [h, c, _g];
};
Color.prototype.hcg = function () {
return rgb2hcg(this._rgb);
};
const hcg$1 = (...args) => new Color(...args, 'hcg');
chroma.hcg = hcg$1;
input.format.hcg = hcg2rgb;
input.autodetect.push({
p: 1,
test: (...args) => {
args = unpack(args, 'hcg');
if (type(args) === 'array' && args.length === 3) {
return 'hcg';
}
}
});
const hcg = (col1, col2, f) => {
return interpolate_hsx(col1, col2, f, 'hcg');
};
// register interpolator
index.hcg = hcg;
const { cos: cos$3 } = Math;
/*
* hue [0..360]
* saturation [0..1]
* intensity [0..1]
*/
const hsi2rgb = (...args) => {
/*
borrowed from here:
http://hummer.stanford.edu/museinfo/doc/examples/humdrum/keyscape2/hsi2rgb.cpp
*/
args = unpack(args, 'hsi');
let [h, s, i] = args;
let r, g, b;
if (isNaN(h)) h = 0;
if (isNaN(s)) s = 0;
// normalize hue
if (h > 360) h -= 360;
if (h < 0) h += 360;
h /= 360;
if (h < 1 / 3) {
b = (1 - s) / 3;
r = (1 + (s * cos$3(TWOPI * h)) / cos$3(PITHIRD - TWOPI * h)) / 3;
g = 1 - (b + r);
} else if (h < 2 / 3) {
h -= 1 / 3;
r = (1 - s) / 3;
g = (1 + (s * cos$3(TWOPI * h)) / cos$3(PITHIRD - TWOPI * h)) / 3;
b = 1 - (r + g);
} else {
h -= 2 / 3;
g = (1 - s) / 3;
b = (1 + (s * cos$3(TWOPI * h)) / cos$3(PITHIRD - TWOPI * h)) / 3;
r = 1 - (g + b);
}
r = limit(i * r * 3);
g = limit(i * g * 3);
b = limit(i * b * 3);
return [r * 255, g * 255, b * 255, args.length > 3 ? args[3] : 1];
};
const { min: min$2, sqrt: sqrt$2, acos } = Math;
const rgb2hsi = (...args) => {
/*
borrowed from here:
http://hummer.stanford.edu/museinfo/doc/examples/humdrum/keyscape2/rgb2hsi.cpp
*/
let [r, g, b] = unpack(args, 'rgb');
r /= 255;
g /= 255;
b /= 255;
let h;
const min_ = min$2(r, g, b);
const i = (r + g + b) / 3;
const s = i > 0 ? 1 - min_ / i : 0;
if (s === 0) {
h = NaN;
} else {
h = (r - g + (r - b)) / 2;
h /= sqrt$2((r - g) * (r - g) + (r - b) * (g - b));
h = acos(h);
if (b > g) {
h = TWOPI - h;
}
h /= TWOPI;
}
return [h * 360, s, i];
};
Color.prototype.hsi = function () {
return rgb2hsi(this._rgb);
};
const hsi$1 = (...args) => new Color(...args, 'hsi');
chroma.hsi = hsi$1;
input.format.hsi = hsi2rgb;
input.autodetect.push({
p: 2,
test: (...args) => {
args = unpack(args, 'hsi');
if (type(args) === 'array' && args.length === 3) {
return 'hsi';
}
}
});
const hsi = (col1, col2, f) => {
return interpolate_hsx(col1, col2, f, 'hsi');
};
// register interpolator
index.hsi = hsi;
const hsl2rgb = (...args) => {
args = unpack(args, 'hsl');
const [h, s, l] = args;
let r, g, b;
if (s === 0) {
r = g = b = l * 255;
} else {
const t3 = [0, 0, 0];
const c = [0, 0, 0];
const t2 = l < 0.5 ? l * (1 + s) : l + s - l * s;
const t1 = 2 * l - t2;
const h_ = h / 360;
t3[0] = h_ + 1 / 3;
t3[1] = h_;
t3[2] = h_ - 1 / 3;
for (let i = 0; i < 3; i++) {
if (t3[i] < 0) t3[i] += 1;
if (t3[i] > 1) t3[i] -= 1;
if (6 * t3[i] < 1) c[i] = t1 + (t2 - t1) * 6 * t3[i];
else if (2 * t3[i] < 1) c[i] = t2;
else if (3 * t3[i] < 2) c[i] = t1 + (t2 - t1) * (2 / 3 - t3[i]) * 6;
else c[i] = t1;
}
[r, g, b] = [c[0] * 255, c[1] * 255, c[2] * 255];
}
if (args.length > 3) {
// keep alpha channel
return [r, g, b, args[3]];
}
return [r, g, b, 1];
};
/*
* supported arguments:
* - rgb2hsl(r,g,b)
* - rgb2hsl(r,g,b,a)
* - rgb2hsl([r,g,b])
* - rgb2hsl([r,g,b,a])
* - rgb2hsl({r,g,b,a})
*/
const rgb2hsl$1 = (...args) => {
args = unpack(args, 'rgba');
let [r, g, b] = args;
r /= 255;
g /= 255;
b /= 255;
const minRgb = min$3(r, g, b);
const maxRgb = max$3(r, g, b);
const l = (maxRgb + minRgb) / 2;
let s, h;
if (maxRgb === minRgb) {
s = 0;
h = Number.NaN;
} else {
s =
l < 0.5
? (maxRgb - minRgb) / (maxRgb + minRgb)
: (maxRgb - minRgb) / (2 - maxRgb - minRgb);
}
if (r == maxRgb) h = (g - b) / (maxRgb - minRgb);
else if (g == maxRgb) h = 2 + (b - r) / (maxRgb - minRgb);
else if (b == maxRgb) h = 4 + (r - g) / (maxRgb - minRgb);
h *= 60;
if (h < 0) h += 360;
if (args.length > 3 && args[3] !== undefined) return [h, s, l, args[3]];
return [h, s, l];
};
Color.prototype.hsl = function () {
return rgb2hsl$1(this._rgb);
};
const hsl$1 = (...args) => new Color(...args, 'hsl');
chroma.hsl = hsl$1;
input.format.hsl = hsl2rgb;
input.autodetect.push({
p: 2,
test: (...args) => {
args = unpack(args, 'hsl');
if (type(args) === 'array' && args.length === 3) {
return 'hsl';
}
}
});
const hsl = (col1, col2, f) => {
return interpolate_hsx(col1, col2, f, 'hsl');
};
// register interpolator
index.hsl = hsl;
const { floor: floor$2 } = Math;
const hsv2rgb = (...args) => {
args = unpack(args, 'hsv');
let [h, s, v] = args;
let r, g, b;
v *= 255;
if (s === 0) {
r = g = b = v;
} else {
if (h === 360) h = 0;
if (h > 360) h -= 360;
if (h < 0) h += 360;
h /= 60;
const i = floor$2(h);
const f = h - i;
const p = v * (1 - s);
const q = v * (1 - s * f);
const t = v * (1 - s * (1 - f));
switch (i) {
case 0:
[r, g, b] = [v, t, p];
break;
case 1:
[r, g, b] = [q, v, p];
break;
case 2:
[r, g, b] = [p, v, t];
break;
case 3:
[r, g, b] = [p, q, v];
break;
case 4:
[r, g, b] = [t, p, v];
break;
case 5:
[r, g, b] = [v, p, q];
break;
}
}
return [r, g, b, args.length > 3 ? args[3] : 1];
};
const { min: min$1, max: max$2 } = Math;
/*
* supported arguments:
* - rgb2hsv(r,g,b)
* - rgb2hsv([r,g,b])
* - rgb2hsv({r,g,b})
*/
const rgb2hsl = (...args) => {
args = unpack(args, 'rgb');
let [r, g, b] = args;
const min_ = min$1(r, g, b);
const max_ = max$2(r, g, b);
const delta = max_ - min_;
let h, s, v;
v = max_ / 255.0;
if (max_ === 0) {
h = Number.NaN;
s = 0;
} else {
s = delta / max_;
if (r === max_) h = (g - b) / delta;
if (g === max_) h = 2 + (b - r) / delta;
if (b === max_) h = 4 + (r - g) / delta;
h *= 60;
if (h < 0) h += 360;
}
return [h, s, v];
};
Color.prototype.hsv = function () {
return rgb2hsl(this._rgb);
};
const hsv$1 = (...args) => new Color(...args, 'hsv');
chroma.hsv = hsv$1;
input.format.hsv = hsv2rgb;
input.autodetect.push({
p: 2,
test: (...args) => {
args = unpack(args, 'hsv');
if (type(args) === 'array' && args.length === 3) {
return 'hsv';
}
}
});
const hsv = (col1, col2, f) => {
return interpolate_hsx(col1, col2, f, 'hsv');
};
// register interpolator
index.hsv = hsv;
// from https://www.w3.org/TR/css-color-4/multiply-matrices.js
function multiplyMatrices(A, B) {
let m = A.length;
if (!Array.isArray(A[0])) {
// A is vector, convert to [[a, b, c, ...]]
A = [A];
}
if (!Array.isArray(B[0])) {
// B is vector, convert to [[a], [b], [c], ...]]
B = B.map((x) => [x]);
}
let p = B[0].length;
let B_cols = B[0].map((_, i) => B.map((x) => x[i])); // transpose B
let product = A.map((row) =>
B_cols.map((col) => {
if (!Array.isArray(row)) {
return col.reduce((a, c) => a + c * row, 0);
}
return row.reduce((a, c, i) => a + c * (col[i] || 0), 0);
})
);
if (m === 1) {
product = product[0]; // Avoid [[a, b, c, ...]]
}
if (p === 1) {
return product.map((x) => x[0]); // Avoid [[a], [b], [c], ...]]
}
return product;
}
const oklab2rgb = (...args) => {
args = unpack(args, 'lab');
const [L, a, b, ...rest] = args;
const [X, Y, Z] = OKLab_to_XYZ([L, a, b]);
const [r, g, b_] = xyz2rgb(X, Y, Z);
return [r, g, b_, ...(rest.length > 0 && rest[0] < 1 ? [rest[0]] : [])];
};
// from https://www.w3.org/TR/css-color-4/#color-conversion-code
function OKLab_to_XYZ(OKLab) {
// Given OKLab, convert to XYZ relative to D65
var LMStoXYZ = [
[1.2268798758459243, -0.5578149944602171, 0.2813910456659647],
[-0.0405757452148008, 1.112286803280317, -0.0717110580655164],
[-0.0763729366746601, -0.4214933324022432, 1.5869240198367816]
];
var OKLabtoLMS = [
[1.0, 0.3963377773761749, 0.2158037573099136],
[1.0, -0.1055613458156586, -0.0638541728258133],
[1.0, -0.0894841775298119, -1.2914855480194092]
];
var LMSnl = multiplyMatrices(OKLabtoLMS, OKLab);
return multiplyMatrices(
LMStoXYZ,
LMSnl.map((c) => c ** 3)
);
}
const rgb2oklab = (...args) => {
const [r, g, b, ...rest] = unpack(args, 'rgb');
const xyz = rgb2xyz(r, g, b);
const oklab = XYZ_to_OKLab(xyz);
return [...oklab, ...(rest.length > 0 && rest[0] < 1 ? [rest[0]] : [])];
};
// from https://www.w3.org/TR/css-color-4/#color-conversion-code
function XYZ_to_OKLab(XYZ) {
// Given XYZ relative to D65, convert to OKLab
const XYZtoLMS = [
[0.819022437996703, 0.3619062600528904, -0.1288737815209879],
[0.0329836539323885, 0.9292868615863434, 0.0361446663506424],
[0.0481771893596242, 0.2642395317527308, 0.6335478284694309]
];
const LMStoOKLab = [
[0.210454268309314, 0.7936177747023054, -0.0040720430116193],
[1.9779985324311684, -2.4285922420485799, 0.450593709617411],
[0.0259040424655478, 0.7827717124575296, -0.8086757549230774]
];
const LMS = multiplyMatrices(XYZtoLMS, XYZ);
// JavaScript Math.cbrt returns a sign-matched cube root
// beware if porting to other languages
// especially if tempted to use a general power function
return multiplyMatrices(
LMStoOKLab,
LMS.map((c) => Math.cbrt(c))
);
// L in range [0,1]. For use in CSS, multiply by 100 and add a percent
}
Color.prototype.oklab = function () {
return rgb2oklab(this._rgb);
};
const oklab$1 = (...args) => new Color(...args, 'oklab');
Object.assign(chroma, { oklab: oklab$1 });
input.format.oklab = oklab2rgb;
input.autodetect.push({
p: 2,
test: (...args) => {
args = unpack(args, 'oklab');
if (type(args) === 'array' && args.length === 3) {
return 'oklab';
}
}
});
const oklab = (col1, col2, f) => {
const xyz0 = col1.oklab();
const xyz1 = col2.oklab();
return new Color(
xyz0[0] + f * (xyz1[0] - xyz0[0]),
xyz0[1] + f * (xyz1[1] - xyz0[1]),
xyz0[2] + f * (xyz1[2] - xyz0[2]),
'ok