-
Notifications
You must be signed in to change notification settings - Fork 7
/
hsl.js
87 lines (75 loc) · 2.15 KB
/
hsl.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// HSL space (hue, saturation, lightness within sRGB gamut)
// Reference:
// https://github.com/color-js/color.js/blob/cfe55d358adb6c2e23c8a897282adf42904fd32d/src/spaces/hsl.js
import { sRGB, sRGBLinear } from "../../src/index.js";
export const HSL = {
id: "hsl",
// Note: @texel/color currently only supports 1-level depth for color spaces
// (for performance & memory reasons) - so our base must be one without another base space
base: sRGBLinear,
// Adapted from https://drafts.csswg.org/css-color-4/better-rgbToHsl.js
fromBase: (rgb, out = [0, 0, 0]) => {
// from sRGBLinear (this space's base) to sRGB (for HSL conversion)
sRGB.fromBase(rgb, out);
const r = out[0];
const g = out[1];
const b = out[2];
let max = Math.max(r, g, b);
let min = Math.min(r, g, b);
let h = 0,
s = 0,
l = (min + max) / 2;
let d = max - min;
if (d !== 0) {
s = l === 0 || l === 1 ? 0 : (max - l) / Math.min(l, 1 - l);
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;
}
h = h * 60;
}
// Very out of gamut colors can produce negative saturation
// If so, just rotate the hue by 180 and use a positive saturation
// see https://github.com/w3c/csswg-drafts/issues/9222
if (s < 0) {
h += 180;
s = Math.abs(s);
}
if (h >= 360) {
h -= 360;
}
out[0] = h;
out[1] = s * 100;
out[2] = l * 100;
return out;
},
// Adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative
toBase: (hsl, out = [0, 0, 0]) => {
let h = hsl[0];
let s = hsl[1];
let l = hsl[2];
h = h % 360;
if (h < 0) {
h += 360;
}
s /= 100;
l /= 100;
const a = s * Math.min(l, 1 - l);
out[0] = f(h, l, a, 0);
out[1] = f(h, l, a, 8);
out[2] = f(h, l, a, 4);
// from sRGB to sRGBLinear (this space's base)
sRGB.toBase(out, out);
return out;
},
};
function f(h, l, a, n) {
let k = (n + h / 30) % 12;
return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
}