Skip to content

Commit 694ed8f

Browse files
committed
Ensure that niced domains always span ticks
fixes #209
1 parent 732ed4b commit 694ed8f

File tree

2 files changed

+59
-33
lines changed

2 files changed

+59
-33
lines changed

src/linear.js

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,59 @@ import {initRange} from "./init.js";
44
import tickFormat from "./tickFormat.js";
55

66
export function linearish(scale) {
7-
var domain = scale.domain;
7+
const domain = scale.domain;
88

99
scale.ticks = function(count) {
10-
var d = domain();
10+
const d = domain();
1111
return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
1212
};
1313

1414
scale.tickFormat = function(count, specifier) {
15-
var d = domain();
15+
const d = domain();
1616
return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
1717
};
1818

1919
scale.nice = function(count) {
2020
if (count == null) count = 10;
2121

22-
var d = domain(),
23-
i0 = 0,
24-
i1 = d.length - 1,
25-
start = d[i0],
26-
stop = d[i1],
27-
step;
22+
const d = domain();
23+
let i0 = 0;
24+
let i1 = d.length - 1;
25+
let start = d[i0];
26+
let stop = d[i1];
27+
let prestep;
28+
let step;
2829

2930
if (stop < start) {
3031
step = start, start = stop, stop = step;
3132
step = i0, i0 = i1, i1 = step;
3233
}
33-
34-
step = tickIncrement(start, stop, count);
35-
36-
if (step > 0) {
37-
start = Math.floor(start / step) * step;
38-
stop = Math.ceil(stop / step) * step;
39-
step = tickIncrement(start, stop, count);
40-
} else if (step < 0) {
41-
start = Math.ceil(start * step) / step;
42-
stop = Math.floor(stop * step) / step;
43-
step = tickIncrement(start, stop, count);
34+
35+
// eslint-disable-next-line no-constant-condition
36+
while (true) {
37+
const step = tickIncrement(start, stop, count);
38+
if (step === prestep) {
39+
d[i0] = start
40+
d[i1] = stop
41+
return domain(d);
42+
} else if (step > 0) {
43+
start = Math.floor(start / step) * step;
44+
stop = Math.ceil(stop / step) * step;
45+
} else if (step < 0) {
46+
start = Math.ceil(start * step) / step;
47+
stop = Math.floor(stop * step) / step;
48+
} else {
49+
return scale;
50+
}
51+
prestep = step;
4452
}
45-
46-
if (step > 0) {
47-
d[i0] = Math.floor(start / step) * step;
48-
d[i1] = Math.ceil(stop / step) * step;
49-
domain(d);
50-
} else if (step < 0) {
51-
d[i0] = Math.ceil(start * step) / step;
52-
d[i1] = Math.floor(stop * step) / step;
53-
domain(d);
54-
}
55-
56-
return scale;
5753
};
5854

5955
return scale;
6056
}
6157

6258
export default function linear() {
63-
var scale = continuous();
59+
const scale = continuous();
6460

6561
scale.copy = function() {
6662
return copy(scale, linear());

test/linear-test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,36 @@ tape("linear.ticks(count) returns the expected ticks for a polylinear domain", f
373373
test.end();
374374
});
375375

376+
tape("linear.ticks(X) spans linear.nice(X).domain()", function(test) {
377+
function check(domain, count) {
378+
var s = scale.scaleLinear().domain(domain).nice(count);
379+
var ticks = s.ticks(count);
380+
test.deepEqual([ticks[0], ticks[ticks.length - 1]], s.domain());
381+
}
382+
383+
check([1, 9], 2);
384+
check([1, 9], 3);
385+
check([1, 9], 4);
386+
387+
check([8, 9], 2);
388+
check([8, 9], 3);
389+
check([8, 9], 4);
390+
391+
check([1, 21], 2);
392+
check([2, 21], 2);
393+
check([3, 21], 2);
394+
check([4, 21], 2);
395+
check([5, 21], 2);
396+
check([6, 21], 2);
397+
check([7, 21], 2);
398+
check([8, 21], 2);
399+
check([9, 21], 2);
400+
check([10, 21], 2);
401+
check([11, 21], 2);
402+
403+
test.end();
404+
})
405+
376406
tape("linear.ticks(count) returns the empty array if count is not a positive integer", function(test) {
377407
var s = scale.scaleLinear();
378408
test.deepEqual(s.ticks(NaN), []);

0 commit comments

Comments
 (0)