Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

additional colour space for d3 #579

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c119d09
initial xyz file, conversion from rgb
justincormack Feb 27, 2012
16c3fbb
add more tests
justincormack Mar 2, 2012
4c14c3c
xyz to rgb conversion
justincormack Mar 2, 2012
9bf1caf
xyz to hsl conversion
justincormack Mar 2, 2012
475bc16
add assert.xyzEqual()
justincormack Mar 2, 2012
68faca2
clean up tests a little
justincormack Mar 2, 2012
868224b
local functions to tidy conversion
justincormack Mar 2, 2012
93c562f
add start of cielab support and test
justincormack Mar 2, 2012
6e19b86
rgb and hsl conversions
justincormack Mar 2, 2012
ebc7055
rgb and hsl conversions other way
justincormack Mar 2, 2012
6c8d3ce
add cielab to xyz conversion
justincormack Mar 2, 2012
6864754
add cielab brighter and darker
justincormack Mar 2, 2012
1597cce
add cielab and xyz string conversion tests
justincormack Mar 2, 2012
5395642
start of cielch support
justincormack Mar 2, 2012
1d1a49d
cielch support with conversion back
justincormack Mar 2, 2012
89e6ba0
direct cielab to rgb conversion not via xyz
justincormack Mar 4, 2012
730736c
direct rgb to cielab conversion not via xyz
justincormack Mar 4, 2012
b017e61
remove all conversions to xyz and tests
justincormack Mar 4, 2012
12a9edc
remove xyz colour space
justincormack Mar 4, 2012
7ed0f40
start removing excessive cross colour space conversions
justincormack Mar 4, 2012
01f9ccd
clean up lab to rgb conversion
justincormack Mar 4, 2012
9a0de8b
clean up cielab and cielch initialization
justincormack Mar 4, 2012
f8bbbde
add chroma and hue set and get to cielab
justincormack Mar 4, 2012
68130f9
remove cielch support
justincormack Mar 4, 2012
c8f57ad
remove unused test functions
justincormack Mar 4, 2012
66cb11d
rename cielab to simply lab for brevity
justincormack Mar 4, 2012
f1b3831
remove extraneous function in lab.js
justincormack Mar 4, 2012
a00c344
add CIELab interpolator
justincormack Mar 4, 2012
73db4dc
cleanups to make smaller
justincormack Mar 4, 2012
3fd51d4
extra prototype removed
justincormack Mar 10, 2012
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -76,6 +76,7 @@ d3.core.js: \
src/core/uninterpolate.js \
src/core/rgb.js \
src/core/hsl.js \
src/core/lab.js \
src/core/selection.js \
src/core/selection-select.js \
src/core/selection-selectAll.js \
Expand Down
149 changes: 149 additions & 0 deletions d3.v2.js
Expand Up @@ -1082,6 +1082,20 @@ d3.interpolateHsl = function(a, b) {
};
};

d3.interpolateLab = function(a, b) {
a = d3.lab(a);
b = d3.lab(b);
var l0 = a.l,
a0 = a.a,
b0 = a.b,
l1 = b.l - l0,
a1 = b.a - a0,
b1 = b.b - b0;
return function(t) {
return d3_lab_rgb(l0 + l1 * t, a0 + a1 * t, b0 + b1 * t).toString();
};
};

d3.interpolateArray = function(a, b) {
var x = [],
c = [],
Expand Down Expand Up @@ -1189,6 +1203,10 @@ d3_Rgb.prototype.hsl = function() {
return d3_rgb_hsl(this.r, this.g, this.b);
};

d3_Rgb.prototype.lab = function() {
return d3_rgb_lab(this.r, this.g, this.b);
};

d3_Rgb.prototype.toString = function() {
return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
};
Expand Down Expand Up @@ -1270,6 +1288,42 @@ function d3_rgb_hsl(r, g, b) {
return d3_hsl(h, s, l);
}

function d3_rgb_lab(r, g, b) {
r /= 255;
g /= 255;
b /= 255;

function v(r) {
return r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : r / 12.92;
}

r = v(r) * 100;
g = v(g) * 100;
b = v(b) * 100;

var x = r * 0.4124 + g * 0.3576 + b * 0.1805,
y = r * 0.2126 + g * 0.7152 + b * 0.0722,
z = r * 0.0193 + g * 0.1192 + b * 0.9505;

x /= 95.047;
y /= 100.000;
z /= 108.883;

function w(x) {
return x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
}

x = w(x);
y = w(y);
z = w(z);

var l = y > 0.008856 ? (116 * y) - 16 : 903.3 * y,
a = 500 * (x - y),
b = 200 * (y - z);

return d3_lab(l, a, b);
}

function d3_rgb_parseNumber(c) { // either integer or percentage
var f = parseFloat(c);
return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
Expand Down Expand Up @@ -1491,6 +1545,101 @@ function d3_hsl_rgb(h, s, l) {

return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
}
d3.lab = function(l, a, b) {
return arguments.length === 1
? (l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b)
: d3_rgb_parse("" + l, d3_rgb, d3_hsl_rgb).lab())
: d3_lab(+l, +a, +b);
};

function d3_lab(l, a, b) {
return new d3_Lab(l, a, b);
}

function d3_Lab(l, a, b) {
this.l = l;
this.a = a;
this.b = b;
}

d3_Lab.prototype.rgb = function() {
return d3_lab_rgb(this.l, this.a, this.b);
};

d3_Lab.prototype.cielch = function() {
return d3_lab_cielch(this.l, this.a, this.b);
};

/* 18 chosen to correspond roughly to RGB brighter/darker */
d3_Lab.prototype.brighter = function(k) {
return d3_lab(Math.min(100, this.l + 18 * (arguments.length ? k : 1)), this.a, this.b);
};

d3_Lab.prototype.darker = function(k) {
return d3_lab(Math.max(0, this.l - 18 * (arguments.length ? k : 1)), this.a, this.b);
};

d3_Lab.prototype.hue = function(h) {
var a = this.a,
b = this.b;

if (arguments.length) {
return d3_lab_lch(this.l, this.chroma(), h)
}

var h = Math.atan2(b, a);

return h > 0 ? (h / Math.PI) * 180 : 360 - (Math.abs(h) / Math.PI) * 180;
}

d3_Lab.prototype.chroma = function(c) {
var a = this.a,
b = this.b;

if (arguments.length) {
return d3_lab_lch(this.l, c, this.hue())
}

return Math.sqrt(a * a + b * b);
}

d3_Lab.prototype.toString = function() {
return this.rgb().toString();
};

function d3_lab_rgb(l, a, b) {
var y = (l + 16) / 116,
x = a / 500 + y,
z = y - b / 200;

function v(x) {
var p = x * x * x;
return p > 0.008856 ? p : (x - 16 / 116) / 7.787;
}

var x = v(x) * 0.95047,
y = v(y),
z = v(z) * 1.08883;

var r = x * 3.2406 + y * -1.5372 + z * -0.4986,
g = x * -0.9689 + y * 1.8758 + z * 0.0415,
b = x * 0.0557 + y * -0.2040 + z * 1.0570;

function w(r) {
r = r > 0.0031308 ? 1.055 * Math.pow(r, (1 / 2.4)) - 0.055 : 12.92 * r;
return Math.round(r * 255)
}

return d3_rgb(w(r), w(g), w(b));
}

function d3_lab_lch(l, c, h) {
var hr = h * (Math.PI / 180),
a = Math.cos(hr) * c,
b = Math.sin(hr) * c;
return d3_lab(l, a, b);
}

function d3_selection(groups) {
d3_arraySubclass(groups, d3_selectionPrototype);
return groups;
Expand Down
8 changes: 4 additions & 4 deletions d3.v2.min.js

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions src/core/interpolate.js
Expand Up @@ -175,6 +175,20 @@ d3.interpolateHsl = function(a, b) {
};
};

d3.interpolateLab = function(a, b) {
a = d3.lab(a);
b = d3.lab(b);
var l0 = a.l,
a0 = a.a,
b0 = a.b,
l1 = b.l - l0,
a1 = b.a - a0,
b1 = b.b - b0;
return function(t) {
return d3_lab_rgb(l0 + l1 * t, a0 + a1 * t, b0 + b1 * t).toString();
};
};

d3.interpolateArray = function(a, b) {
var x = [],
c = [],
Expand Down
91 changes: 91 additions & 0 deletions src/core/lab.js
@@ -0,0 +1,91 @@
d3.lab = function(l, a, b) {
return arguments.length === 1
? (l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b)
: d3_rgb_parse("" + l, d3_rgb, d3_hsl_rgb).lab())
: d3_lab(+l, +a, +b);
};

function d3_lab(l, a, b) {
return new d3_Lab(l, a, b);
}

function d3_Lab(l, a, b) {
this.l = l;
this.a = a;
this.b = b;
}

d3_Lab.prototype.rgb = function() {
return d3_lab_rgb(this.l, this.a, this.b);
};

/* 18 chosen to correspond roughly to RGB brighter/darker */
d3_Lab.prototype.brighter = function(k) {
return d3_lab(Math.min(100, this.l + 18 * (arguments.length ? k : 1)), this.a, this.b);
};

d3_Lab.prototype.darker = function(k) {
return d3_lab(Math.max(0, this.l - 18 * (arguments.length ? k : 1)), this.a, this.b);
};

d3_Lab.prototype.hue = function(h) {
var a = this.a,
b = this.b;

if (arguments.length) {
return d3_lab_lch(this.l, this.chroma(), h)
}

var h = Math.atan2(b, a);

return h > 0 ? (h / Math.PI) * 180 : 360 - (Math.abs(h) / Math.PI) * 180;
}

d3_Lab.prototype.chroma = function(c) {
var a = this.a,
b = this.b;

if (arguments.length) {
return d3_lab_lch(this.l, c, this.hue())
}

return Math.sqrt(a * a + b * b);
}

d3_Lab.prototype.toString = function() {
return this.rgb().toString();
};

function d3_lab_rgb(l, a, b) {
var y = (l + 16) / 116,
x = a / 500 + y,
z = y - b / 200;

function v(x) {
var p = x * x * x;
return p > 0.008856 ? p : (x - 16 / 116) / 7.787;
}

var x = v(x) * 0.95047,
y = v(y),
z = v(z) * 1.08883;

var r = x * 3.2406 + y * -1.5372 + z * -0.4986,
g = x * -0.9689 + y * 1.8758 + z * 0.0415,
b = x * 0.0557 + y * -0.2040 + z * 1.0570;

function w(r) {
r = r > 0.0031308 ? 1.055 * Math.pow(r, (1 / 2.4)) - 0.055 : 12.92 * r;
return Math.round(r * 255)
}

return d3_rgb(w(r), w(g), w(b));
}

function d3_lab_lch(l, c, h) {
var hr = h * (Math.PI / 180),
a = Math.cos(hr) * c,
b = Math.sin(hr) * c;
return d3_lab(l, a, b);
}

40 changes: 40 additions & 0 deletions src/core/rgb.js
Expand Up @@ -43,6 +43,10 @@ d3_Rgb.prototype.hsl = function() {
return d3_rgb_hsl(this.r, this.g, this.b);
};

d3_Rgb.prototype.lab = function() {
return d3_rgb_lab(this.r, this.g, this.b);
};

d3_Rgb.prototype.toString = function() {
return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
};
Expand Down Expand Up @@ -124,6 +128,42 @@ function d3_rgb_hsl(r, g, b) {
return d3_hsl(h, s, l);
}

function d3_rgb_lab(r, g, b) {
r /= 255;
g /= 255;
b /= 255;

function v(r) {
return r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : r / 12.92;
}

r = v(r) * 100;
g = v(g) * 100;
b = v(b) * 100;

var x = r * 0.4124 + g * 0.3576 + b * 0.1805,
y = r * 0.2126 + g * 0.7152 + b * 0.0722,
z = r * 0.0193 + g * 0.1192 + b * 0.9505;

x /= 95.047;
y /= 100.000;
z /= 108.883;

function w(x) {
return x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
}

x = w(x);
y = w(y);
z = w(z);

var l = y > 0.008856 ? (116 * y) - 16 : 903.3 * y,
a = 500 * (x - y),
b = 200 * (y - z);

return d3_lab(l, a, b);
}

function d3_rgb_parseNumber(c) { // either integer or percentage
var f = parseFloat(c);
return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
Expand Down