Skip to content

Commit 6cc03db

Browse files
committed
Add ordinal rangeRoundPoints. Fixes d3#1760.
1 parent db8d305 commit 6cc03db

4 files changed

Lines changed: 108 additions & 13 deletions

File tree

d3.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7617,15 +7617,28 @@
76177617
};
76187618
scale.rangePoints = function(x, padding) {
76197619
if (arguments.length < 2) padding = 0;
7620-
var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding);
7621-
range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
7620+
var start = x[0], stop = x[1], step = domain.length < 2 ? (start = (start + stop) / 2,
7621+
0) : (stop - start) / (domain.length - 1 + padding);
7622+
range = steps(start + step * padding / 2, step);
76227623
rangeBand = 0;
76237624
ranger = {
76247625
t: "rangePoints",
76257626
a: arguments
76267627
};
76277628
return scale;
76287629
};
7630+
scale.rangeRoundPoints = function(x, padding) {
7631+
if (arguments.length < 2) padding = 0;
7632+
var start = x[0], stop = x[1], step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2),
7633+
0) : (stop - start) / (domain.length - 1 + padding) | 0;
7634+
range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step);
7635+
rangeBand = 0;
7636+
ranger = {
7637+
t: "rangeRoundPoints",
7638+
a: arguments
7639+
};
7640+
return scale;
7641+
};
76297642
scale.rangeBands = function(x, padding, outerPadding) {
76307643
if (arguments.length < 2) padding = 0;
76317644
if (arguments.length < 3) outerPadding = padding;
@@ -7642,8 +7655,8 @@
76427655
scale.rangeRoundBands = function(x, padding, outerPadding) {
76437656
if (arguments.length < 2) padding = 0;
76447657
if (arguments.length < 3) outerPadding = padding;
7645-
var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step;
7646-
range = steps(start + Math.round(error / 2), step);
7658+
var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding));
7659+
range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step);
76477660
if (reverse) range.reverse();
76487661
rangeBand = Math.round(step * (1 - padding));
76497662
ranger = {

d3.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/scale/ordinal.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,24 @@ function d3_scale_ordinal(domain, ranger) {
4040
if (arguments.length < 2) padding = 0;
4141
var start = x[0],
4242
stop = x[1],
43-
step = (stop - start) / (Math.max(1, domain.length - 1) + padding);
44-
range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
43+
step = domain.length < 2 ? (start = (start + stop) / 2, 0) : (stop - start) / (domain.length - 1 + padding);
44+
range = steps(start + step * padding / 2, step);
4545
rangeBand = 0;
4646
ranger = {t: "rangePoints", a: arguments};
4747
return scale;
4848
};
4949

50+
scale.rangeRoundPoints = function(x, padding) {
51+
if (arguments.length < 2) padding = 0;
52+
var start = x[0],
53+
stop = x[1],
54+
step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2), 0) : (stop - start) / (domain.length - 1 + padding) | 0; // bitwise floor for symmetry
55+
range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step);
56+
rangeBand = 0;
57+
ranger = {t: "rangeRoundPoints", a: arguments};
58+
return scale;
59+
};
60+
5061
scale.rangeBands = function(x, padding, outerPadding) {
5162
if (arguments.length < 2) padding = 0;
5263
if (arguments.length < 3) outerPadding = padding;
@@ -67,9 +78,8 @@ function d3_scale_ordinal(domain, ranger) {
6778
var reverse = x[1] < x[0],
6879
start = x[reverse - 0],
6980
stop = x[1 - reverse],
70-
step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)),
71-
error = stop - start - (domain.length - padding) * step;
72-
range = steps(start + Math.round(error / 2), step);
81+
step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding));
82+
range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step);
7383
if (reverse) range.reverse();
7484
rangeBand = Math.round(step * (1 - padding));
7585
ranger = {t: "rangeRoundBands", a: arguments};

test/scale/ordinal-test.js

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ suite.addBatch({
114114
var x = ordinal().domain(["a", "b", "c"]).rangePoints([0, 120], 2);
115115
assert.deepEqual(x.range(), [30, 60, 90]);
116116
},
117+
"correctly handles empty domains": function(ordinal) {
118+
var x = ordinal().domain([]).rangePoints([0, 120]);
119+
assert.deepEqual(x.range(), []);
120+
assert.isUndefined(x("b"));
121+
assert.deepEqual(x.domain(), []);
122+
},
117123
"correctly handles singleton domains": function(ordinal) {
118124
var x = ordinal().domain(["a"]).rangePoints([0, 120]);
119125
assert.deepEqual(x.range(), [60]);
@@ -122,7 +128,7 @@ suite.addBatch({
122128
},
123129
"can be set to a descending range": function(ordinal) {
124130
var x = ordinal().domain(["a", "b", "c"]).rangePoints([120, 0]);
125-
assert.deepEqual(x.range(), [120, 60,0]);
131+
assert.deepEqual(x.range(), [120, 60, 0]);
126132
var x = ordinal().domain(["a", "b", "c"]).rangePoints([120, 0], 1);
127133
assert.deepEqual(x.range(), [100, 60, 20]);
128134
var x = ordinal().domain(["a", "b", "c"]).rangePoints([120, 0], 2);
@@ -157,6 +163,72 @@ suite.addBatch({
157163
}
158164
},
159165

166+
"rangeRoundPoints": {
167+
"computes discrete points in a continuous range": function(ordinal) {
168+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 120]);
169+
assert.deepEqual(x.range(), [0, 60, 120]);
170+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 120], 1);
171+
assert.deepEqual(x.range(), [20, 60, 100]);
172+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 120], 2);
173+
assert.deepEqual(x.range(), [30, 60, 90]);
174+
},
175+
"rounds to the nearest equispaced integer values": function(ordinal) {
176+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 119]);
177+
assert.deepEqual(x.range(), [1, 60, 119]);
178+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 119], 1);
179+
assert.deepEqual(x.range(), [21, 60, 99]);
180+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 119], 2);
181+
assert.deepEqual(x.range(), [31, 60, 89]);
182+
},
183+
"correctly handles empty domains": function(ordinal) {
184+
var x = ordinal().domain([]).rangeRoundPoints([0, 119]);
185+
assert.deepEqual(x.range(), []);
186+
assert.isUndefined(x("b"));
187+
assert.deepEqual(x.domain(), []);
188+
},
189+
"correctly handles singleton domains": function(ordinal) {
190+
var x = ordinal().domain(["a"]).rangeRoundPoints([0, 119]);
191+
assert.deepEqual(x.range(), [60]);
192+
assert.isUndefined(x("b"));
193+
assert.deepEqual(x.domain(), ["a"]);
194+
},
195+
"can be set to a descending range": function(ordinal) {
196+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([119, 0]);
197+
assert.deepEqual(x.range(), [119, 60, 1]);
198+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([119, 0], 1);
199+
assert.deepEqual(x.range(), [99, 60, 21]);
200+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([119, 0], 2);
201+
assert.deepEqual(x.range(), [89, 60, 31]);
202+
},
203+
"has a rangeBand of zero": function(ordinal) {
204+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 119]);
205+
assert.equal(x.rangeBand(), 0);
206+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 119], 1);
207+
assert.equal(x.rangeBand(), 0);
208+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 119], 2);
209+
assert.equal(x.rangeBand(), 0);
210+
var x = ordinal().domain(["a"]).rangeRoundPoints([0, 119]);
211+
assert.equal(x.rangeBand(), 0);
212+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([119, 0]);
213+
assert.equal(x.rangeBand(), 0);
214+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([119, 0], 1);
215+
assert.equal(x.rangeBand(), 0);
216+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([119, 0], 2);
217+
assert.equal(x.rangeBand(), 0);
218+
},
219+
"returns undefined for values outside the domain": function(ordinal) {
220+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 1]);
221+
assert.isUndefined(x("d"));
222+
assert.isUndefined(x("e"));
223+
assert.isUndefined(x("f"));
224+
},
225+
"does not implicitly add values to the domain": function(ordinal) {
226+
var x = ordinal().domain(["a", "b", "c"]).rangeRoundPoints([0, 1]);
227+
x("d"), x("e");
228+
assert.deepEqual(x.domain(), ["a", "b", "c"]);
229+
}
230+
},
231+
160232
"rangeBands": {
161233
"computes discrete bands in a continuous range": function(ordinal) {
162234
var x = ordinal().domain(["a", "b", "c"]).rangeBands([0, 120]);

0 commit comments

Comments
 (0)