4 cie.lab = function(l, a, b) {
5 return arguments.length === 1
6 ? (l instanceof Lab ? lab(l.l, l.a, l.b)
7 : (l instanceof Lch ? lch_lab(l.l, l.c, l.h)
8 : rgb_lab((l = d3.rgb(l)).r, l.g, l.b)))
12 cie.lch = function(l, c, h) {
13 return arguments.length === 1
14 ? (l instanceof Lch ? lch(l.l, l.c, l.h)
15 : (l instanceof Lab ? lab_lch(l.l, l.a, l.b)
16 : lab_lch((l = rgb_lab((l = d3.rgb(l)).r, l.g, l.b)).l, l.a, l.b)))
20 cie.interpolateLab = function(a, b) {
30 return lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
34 cie.interpolateLch = function(a, b) {
43 if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; // shortest path
45 return lch_lab(al + bl * t, ac + bc * t, ah + bh * t) + "";
49 function lab(l, a, b) {
50 return new Lab(l, a, b);
53 function Lab(l, a, b) {
59 Lab.prototype.brighter = function(k) {
60 return lab(Math.min(100, this.l + K * (arguments.length ? k : 1)), this.a, this.b);
63 Lab.prototype.darker = function(k) {
64 return lab(Math.max(0, this.l - K * (arguments.length ? k : 1)), this.a, this.b);
67 Lab.prototype.rgb = function() {
68 return lab_rgb(this.l, this.a, this.b);
71 Lab.prototype.toString = function() {
72 return this.rgb() + "";
75 function lch(l, c, h) {
76 return new Lch(l, c, h);
79 function Lch(l, c, h) {
85 Lch.prototype.brighter = function(k) {
86 return lch(Math.min(100, this.l + K * (arguments.length ? k : 1)), this.c, this.h);
89 Lch.prototype.darker = function(k) {
90 return lch(Math.max(0, this.l - K * (arguments.length ? k : 1)), this.c, this.h);
93 Lch.prototype.rgb = function() {
94 return lch_lab(this.l, this.c, this.h).rgb();
97 Lch.prototype.toString = function() {
98 return this.rgb() + "";
101 // Corresponds roughly to RGB brighter/darker
104 // D65 standard referent
105 var X = 0.950470, Y = 1, Z = 1.088830;
107 function lab_rgb(l, a, b) {
108 var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
113 xyz_rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z),
114 xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
115 xyz_rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z)
119 function rgb_lab(r, g, b) {
123 var x = xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / X),
124 y = xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / Y),
125 z = xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / Z);
126 return lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
129 function lab_lch(l, a, b) {
130 var c = Math.sqrt(a * a + b * b),
131 h = Math.atan2(b, a) / Math.PI * 180;
135 function lch_lab(l, c, h) {
136 h = h * Math.PI / 180;
137 return lab(l, Math.cos(h) * c, Math.sin(h) * c);
140 function lab_xyz(x) {
141 return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
144 function xyz_lab(x) {
145 return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
148 function xyz_rgb(r) {
149 return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055));
152 function rgb_xyz(r) {
153 return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);