Skip to content

Commit

Permalink
Polylinear scales. Fixes #61.
Browse files Browse the repository at this point in the history
For example:

    d3.scale.linear()
        .domain([-100, 0, 100])
        .range(["red", "white", "green"]);
  • Loading branch information
jasondavies committed May 5, 2011
1 parent 0f2846e commit 1a83029
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 49 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ d3.core.js: \
src/core/call.js \
src/core/range.js \
src/core/requote.js \
src/core/search.js \
src/core/xhr.js \
src/core/text.js \
src/core/json.js \
Expand Down Expand Up @@ -161,6 +162,7 @@ tests: \
tests/test-time-parse.test \
tests/test-transition.test \
tests/test-scale-linear.test \
tests/test-scale-polylinear.test \
tests/test-scale-log.test \
tests/test-scale-sqrt.test \
tests/test-scale-pow.test \
Expand Down
60 changes: 37 additions & 23 deletions d3.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,16 @@ d3.requote = function(s) {
};

var d3_requote_re = /[\\\^\$\*\+\?\[\]\(\)\.\{\}]/g;
d3.search = function(array, value) {
var low = 0, high = array.length - 1;
while (low <= high) {
var mid = (low + high) >> 1, midValue = array[mid];
if (midValue < value) low = mid + 1;
else if (midValue > value) high = mid - 1;
else return mid;
}
return -low - 1;
}
d3.xhr = function(url, mime, callback) {
var req = new XMLHttpRequest();
if (arguments.length < 3) callback = mime;
Expand Down Expand Up @@ -1958,41 +1968,41 @@ var d3_timer_frame = window.requestAnimationFrame
|| function(callback) { setTimeout(callback, 17); };
d3.scale = {};
d3.scale.linear = function() {
var x0 = 0,
x1 = 1,
y0 = 0,
y1 = 1,
kx = 1, // 1 / (x1 - x0)
ky = 1, // (x1 - x0) / (y1 - y0)
var d = [0, 1],
r = [0, 1],
interpolate = d3.interpolate,
i = interpolate(y0, y1),
i = [interpolate(0, 1)],
clamp = false;

function scale(x) {
x = (x - x0) * kx;
return i(clamp ? Math.max(0, Math.min(1, x)) : x);
var j = d3.search(d, x);
if (j < 0) j = -j - 2;
j = Math.max(0, Math.min(i.length - 1, j));
x = (x - d[j]) / (d[j + 1] - d[j]);
return i[j](clamp ? Math.max(0, Math.min(1, x)) : x);
}

// Note: requires range is coercible to number!
scale.invert = function(y) {
return (y - y0) * ky + x0;
var j = d3.search(r, y);
if (j < 0) j = -j - 2;
j = Math.max(0, Math.min(i.length - 1, j));
return d[j] + (y - r[j]) / (r[j + 1] - r[j]) * (d[j + 1] - d[j]);
};

scale.domain = function(x) {
if (!arguments.length) return [x0, x1];
x0 = +x[0];
x1 = +x[1];
kx = 1 / (x1 - x0);
ky = (x1 - x0) / (y1 - y0);
if (!arguments.length) return d;
d = x.map(Number);
return scale;
};

scale.range = function(x) {
if (!arguments.length) return [y0, y1];
y0 = x[0];
y1 = x[1];
ky = (x1 - x0) / (y1 - y0);
i = interpolate(y0, y1);
if (!arguments.length) return r;
r = x;
i = [];
for (var j = 0; j < r.length - 1; j++) {
i.push(interpolate(r[j], r[j + 1]));
}
return scale;
};

Expand All @@ -2008,14 +2018,18 @@ d3.scale.linear = function() {

scale.interpolate = function(x) {
if (!arguments.length) return interpolate;
i = (interpolate = x)(y0, y1);
interpolate = x;
i = [];
for (var j = 0; j < r.length - 1; j++) {
i.push(interpolate(r[j], r[j + 1]));
}
return scale;
};

// TODO Dates? Ugh.
function tickRange(m) {
var start = Math.min(x0, x1),
stop = Math.max(x0, x1),
var start = d3.min(d),
stop = d3.max(d),
span = stop - start,
step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)),
err = m / (span / step);
Expand Down
4 changes: 2 additions & 2 deletions d3.min.js

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/core/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
d3.search = function(array, value) {
var low = 0, high = array.length - 1;
while (low <= high) {
var mid = (low + high) >> 1, midValue = array[mid];
if (midValue < value) low = mid + 1;
else if (midValue > value) high = mid - 1;
else return mid;
}
return -low - 1;
}
50 changes: 27 additions & 23 deletions src/scale/linear.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
d3.scale.linear = function() {
var x0 = 0,
x1 = 1,
y0 = 0,
y1 = 1,
kx = 1, // 1 / (x1 - x0)
ky = 1, // (x1 - x0) / (y1 - y0)
var d = [0, 1],
r = [0, 1],
interpolate = d3.interpolate,
i = interpolate(y0, y1),
i = [interpolate(0, 1)],
clamp = false;

function scale(x) {
x = (x - x0) * kx;
return i(clamp ? Math.max(0, Math.min(1, x)) : x);
var j = d3.search(d, x);
if (j < 0) j = -j - 2;
j = Math.max(0, Math.min(i.length - 1, j));
x = (x - d[j]) / (d[j + 1] - d[j]);
return i[j](clamp ? Math.max(0, Math.min(1, x)) : x);
}

// Note: requires range is coercible to number!
scale.invert = function(y) {
return (y - y0) * ky + x0;
var j = d3.search(r, y);
if (j < 0) j = -j - 2;
j = Math.max(0, Math.min(i.length - 1, j));
return d[j] + (y - r[j]) / (r[j + 1] - r[j]) * (d[j + 1] - d[j]);
};

scale.domain = function(x) {
if (!arguments.length) return [x0, x1];
x0 = +x[0];
x1 = +x[1];
kx = 1 / (x1 - x0);
ky = (x1 - x0) / (y1 - y0);
if (!arguments.length) return d;
d = x.map(Number);
return scale;
};

scale.range = function(x) {
if (!arguments.length) return [y0, y1];
y0 = x[0];
y1 = x[1];
ky = (x1 - x0) / (y1 - y0);
i = interpolate(y0, y1);
if (!arguments.length) return r;
r = x;
i = [];
for (var j = 0; j < r.length - 1; j++) {
i.push(interpolate(r[j], r[j + 1]));
}
return scale;
};

Expand All @@ -49,14 +49,18 @@ d3.scale.linear = function() {

scale.interpolate = function(x) {
if (!arguments.length) return interpolate;
i = (interpolate = x)(y0, y1);
interpolate = x;
i = [];
for (var j = 0; j < r.length - 1; j++) {
i.push(interpolate(r[j], r[j + 1]));
}
return scale;
};

// TODO Dates? Ugh.
function tickRange(m) {
var start = Math.min(x0, x1),
stop = Math.max(x0, x1),
var start = d3.min(d),
stop = d3.max(d),
span = stop - start,
step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)),
err = m / (span / step);
Expand Down
2 changes: 1 addition & 1 deletion tests/test-scale-log.out
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ domain([01/01/1990, 01/01/1991]).range([0, 1]):

domain([.1, 10]).range(["red", "blue"]):
0.1 -> rgb(255,0,0)
1 -> rgb(128,0,128)
1 -> rgb(128,0,127)
5 -> rgb(38,0,217)
10 -> rgb(0,0,255)

Expand Down
10 changes: 10 additions & 0 deletions tests/test-scale-polylinear.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require("./../lib/env-js/envjs/node");
require("./../d3");

var x = d3.scale.linear().domain([-1, 0, 1]).range(["red", "white", "green"]);
console.log("domain([-1, 0, 1]).range([\"red\", \"white\", \"green\"]):");
console.log(" -0.5 -> ", x(-0.5));
console.log(" 0.0 -> ", x(0.0));
console.log(" 0.5 -> ", x(0.5));
console.log(" 1.0 -> ", x(1.0));
console.log("");
6 changes: 6 additions & 0 deletions tests/test-scale-polylinear.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
domain([-1, 0, 1]).range(["red", "white", "green"]):
-0.5 -> rgb(255,128,128)
0.0 -> rgb(255,255,255)
0.5 -> rgb(128,192,128)
1.0 -> rgb(0,128,0)

0 comments on commit 1a83029

Please sign in to comment.