Skip to content

Commit 5d17075

Browse files
committed
Add scale.copy.
This returns a copy of the scale, such that future modifications to the scale's domain or range (or other attributes) are isolated from the copy. This is useful for transitions where you may want to make a copy of a scale before it changes, such that entering elements can be initialized using the previous copy.
1 parent ed71513 commit 5d17075

12 files changed

Lines changed: 207 additions & 143 deletions

File tree

d3.js

Lines changed: 95 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,11 +2207,11 @@ function d3_scale_niceDefault() {
22072207
return Math;
22082208
}
22092209
d3.scale.linear = function() {
2210-
var domain = [0, 1],
2211-
range = [0, 1],
2212-
interpolate = d3.interpolate,
2213-
clamp = false,
2214-
output,
2210+
return d3_scale_linear([0, 1], [0, 1], d3.interpolate, false);
2211+
};
2212+
2213+
function d3_scale_linear(domain, range, interpolate, clamp) {
2214+
var output,
22152215
input;
22162216

22172217
function rescale() {
@@ -2272,6 +2272,10 @@ d3.scale.linear = function() {
22722272
return rescale();
22732273
};
22742274

2275+
scale.copy = function() {
2276+
return d3_scale_linear(domain, range, interpolate, clamp);
2277+
};
2278+
22752279
return rescale();
22762280
};
22772281

@@ -2341,9 +2345,11 @@ function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
23412345
};
23422346
}
23432347
d3.scale.log = function() {
2344-
var linear = d3.scale.linear(),
2345-
log = d3_scale_log,
2346-
pow = log.pow;
2348+
return d3_scale_log(d3.scale.linear(), d3_scale_logp);
2349+
};
2350+
2351+
function d3_scale_log(linear, log) {
2352+
var pow = log.pow;
23472353

23482354
function scale(x) {
23492355
return linear(log(x));
@@ -2355,7 +2361,7 @@ d3.scale.log = function() {
23552361

23562362
scale.domain = function(x) {
23572363
if (!arguments.length) return linear.domain().map(pow);
2358-
log = x[0] < 0 ? d3_scale_logn : d3_scale_log;
2364+
log = x[0] < 0 ? d3_scale_logn : d3_scale_logp;
23592365
pow = log.pow;
23602366
linear.domain(x.map(log));
23612367
return scale;
@@ -2392,18 +2398,22 @@ d3.scale.log = function() {
23922398
return d3_scale_logTickFormat;
23932399
};
23942400

2401+
scale.copy = function() {
2402+
return d3_scale_log(linear.copy(), log);
2403+
};
2404+
23952405
return d3_scale_linearRebind(scale, linear);
23962406
};
23972407

2398-
function d3_scale_log(x) {
2408+
function d3_scale_logp(x) {
23992409
return Math.log(x) / Math.LN10;
24002410
}
24012411

24022412
function d3_scale_logn(x) {
24032413
return -Math.log(-x) / Math.LN10;
24042414
}
24052415

2406-
d3_scale_log.pow = function(x) {
2416+
d3_scale_logp.pow = function(x) {
24072417
return Math.pow(10, x);
24082418
};
24092419

@@ -2415,10 +2425,12 @@ function d3_scale_logTickFormat(d) {
24152425
return d.toPrecision(1);
24162426
}
24172427
d3.scale.pow = function() {
2418-
var linear = d3.scale.linear(),
2419-
exponent = 1,
2420-
powp = Number,
2421-
powb = powp;
2428+
return d3_scale_pow(d3.scale.linear(), 1);
2429+
};
2430+
2431+
function d3_scale_pow(linear, exponent) {
2432+
var powp = d3_scale_powPow(exponent),
2433+
powb = d3_scale_powPow(1 / exponent);
24222434

24232435
function scale(x) {
24242436
return linear(powp(x));
@@ -2430,8 +2442,6 @@ d3.scale.pow = function() {
24302442

24312443
scale.domain = function(x) {
24322444
if (!arguments.length) return linear.domain().map(powb);
2433-
powp = d3_scale_powPow(exponent);
2434-
powb = d3_scale_powPow(1 / exponent);
24352445
linear.domain(x.map(powp));
24362446
return scale;
24372447
};
@@ -2451,10 +2461,15 @@ d3.scale.pow = function() {
24512461
scale.exponent = function(x) {
24522462
if (!arguments.length) return exponent;
24532463
var domain = scale.domain();
2454-
exponent = x;
2464+
powp = d3_scale_powPow(exponent = x);
2465+
powb = d3_scale_powPow(1 / exponent);
24552466
return scale.domain(domain);
24562467
};
24572468

2469+
scale.copy = function() {
2470+
return d3_scale_pow(linear.copy(), exponent);
2471+
};
2472+
24582473
return d3_scale_linearRebind(scale, linear);
24592474
};
24602475

@@ -2467,43 +2482,41 @@ d3.scale.sqrt = function() {
24672482
return d3.scale.pow().exponent(.5);
24682483
};
24692484
d3.scale.ordinal = function() {
2470-
var domain = [],
2471-
index = {},
2472-
range = [],
2473-
rangeBand = 0,
2474-
rerange = d3_noop;
2485+
return d3_scale_ordinal({}, 0, d3_noop);
2486+
};
2487+
2488+
function d3_scale_ordinal(domain, size, rerange) {
2489+
var range = [],
2490+
rangeBand = 0;
24752491

24762492
function scale(x) {
2477-
var i = x in index ? index[x] : (index[x] = domain.push(x) - 1);
2478-
return range[i % range.length];
2493+
return range[((domain[x] || (domain[x] = ++size)) - 1) % range.length];
24792494
}
24802495

24812496
scale.domain = function(x) {
2482-
if (!arguments.length) return domain;
2483-
domain = x;
2484-
index = {};
2485-
var i = -1, j = -1, n = domain.length; while (++i < n) {
2486-
x = domain[i];
2487-
if (!(x in index)) index[x] = ++j;
2488-
}
2497+
if (!arguments.length) return d3.keys(domain);
2498+
domain = {};
2499+
size = 0;
2500+
var i = -1, n = x.length, xi;
2501+
while (++i < n) if (!domain[xi = x[i]]) domain[xi] = ++size;
24892502
rerange();
24902503
return scale;
24912504
};
24922505

24932506
scale.range = function(x) {
24942507
if (!arguments.length) return range;
24952508
range = x;
2509+
rangeBand = 0;
24962510
rerange = d3_noop;
24972511
return scale;
24982512
};
24992513

25002514
scale.rangePoints = function(x, padding) {
25012515
if (arguments.length < 2) padding = 0;
2516+
var start = x[0], stop = x[1];
25022517
(rerange = function() {
2503-
var start = x[0],
2504-
stop = x[1],
2505-
step = (stop - start) / (domain.length - 1 + padding);
2506-
range = domain.length == 1
2518+
var step = (stop - start) / (size - 1 + padding);
2519+
range = size < 2
25072520
? [(start + stop) / 2]
25082521
: d3.range(start + step * padding / 2, stop + step / 2, step);
25092522
rangeBand = 0;
@@ -2513,10 +2526,9 @@ d3.scale.ordinal = function() {
25132526

25142527
scale.rangeBands = function(x, padding) {
25152528
if (arguments.length < 2) padding = 0;
2529+
var start = x[0], stop = x[1];
25162530
(rerange = function() {
2517-
var start = x[0],
2518-
stop = x[1],
2519-
step = (stop - start) / (domain.length + padding);
2531+
var step = (stop - start) / (size + padding);
25202532
range = d3.range(start + step * padding, stop, step);
25212533
rangeBand = step * (1 - padding);
25222534
})();
@@ -2525,12 +2537,10 @@ d3.scale.ordinal = function() {
25252537

25262538
scale.rangeRoundBands = function(x, padding) {
25272539
if (arguments.length < 2) padding = 0;
2540+
var start = x[0], stop = x[1];
25282541
(rerange = function() {
2529-
var start = x[0],
2530-
stop = x[1],
2531-
diff = stop - start,
2532-
step = Math.floor(diff / (domain.length + padding)),
2533-
err = diff - (domain.length - padding) * step;
2542+
var step = Math.floor((stop - start) / (size + padding)),
2543+
err = stop - start - (size - padding) * step;
25342544
range = d3.range(start + Math.round(err / 2), stop, step);
25352545
rangeBand = Math.round(step * (1 - padding));
25362546
})();
@@ -2541,6 +2551,13 @@ d3.scale.ordinal = function() {
25412551
return rangeBand;
25422552
};
25432553

2554+
scale.copy = function() {
2555+
var copy = {}, x;
2556+
for (x in domain) copy[x] = domain[x];
2557+
return d3_scale_ordinal(copy, size, rerange);
2558+
};
2559+
2560+
rerange();
25442561
return scale;
25452562
};
25462563
/*
@@ -2598,16 +2615,19 @@ var d3_category20c = [
25982615
"#636363", "#969696", "#bdbdbd", "#d9d9d9"
25992616
];
26002617
d3.scale.quantile = function() {
2601-
var domain = [],
2602-
range = [],
2603-
thresholds = [];
2618+
return d3_scale_quantile([], []);
2619+
};
2620+
2621+
function d3_scale_quantile(domain, range) {
2622+
var thresholds;
26042623

26052624
function rescale() {
26062625
var k = 0,
26072626
n = domain.length,
26082627
q = range.length;
2609-
thresholds.length = Math.max(0, q - 1);
2628+
thresholds = [];
26102629
while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
2630+
return scale;
26112631
}
26122632

26132633
function scale(x) {
@@ -2618,51 +2638,60 @@ d3.scale.quantile = function() {
26182638
scale.domain = function(x) {
26192639
if (!arguments.length) return domain;
26202640
domain = x.filter(function(d) { return !isNaN(d); }).sort(d3.ascending);
2621-
rescale();
2622-
return scale;
2641+
return rescale();
26232642
};
26242643

26252644
scale.range = function(x) {
26262645
if (!arguments.length) return range;
26272646
range = x;
2628-
rescale();
2629-
return scale;
2647+
return rescale();
26302648
};
26312649

26322650
scale.quantiles = function() {
26332651
return thresholds;
26342652
};
26352653

2636-
return scale;
2654+
scale.copy = function() {
2655+
return d3_scale_quantile(domain, range); // copy on write!
2656+
};
2657+
2658+
return rescale();
26372659
};
26382660
d3.scale.quantize = function() {
2639-
var x0 = 0,
2640-
x1 = 1,
2641-
kx = 2,
2642-
i = 1,
2643-
range = [0, 1];
2661+
return d3_scale_quantize(0, 1, [0, 1]);
2662+
};
2663+
2664+
function d3_scale_quantize(x0, x1, range) {
2665+
var kx, i;
26442666

26452667
function scale(x) {
26462668
return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
26472669
}
26482670

2649-
scale.domain = function(x) {
2650-
if (!arguments.length) return [x0, x1];
2651-
x0 = x[0];
2652-
x1 = x[1];
2671+
function rescale() {
26532672
kx = range.length / (x1 - x0);
2673+
i = range.length - 1;
26542674
return scale;
2675+
}
2676+
2677+
scale.domain = function(x) {
2678+
if (!arguments.length) return [x0, x1];
2679+
x0 = +domain[0];
2680+
x1 = +domain[domain.length - 1];
2681+
return rescale();
26552682
};
26562683

26572684
scale.range = function(x) {
26582685
if (!arguments.length) return range;
26592686
range = x;
2660-
kx = range.length / (x1 - x0);
2661-
i = range.length - 1;
2662-
return scale;
2687+
return rescale();
26632688
};
26642689

2665-
return scale;
2690+
scale.copy = function() {
2691+
return d3_scale_quantize(x0, x1, range); // copy on write
2692+
};
2693+
2694+
return rescale();
26662695
};
26672696
d3.svg = {};
26682697
d3.svg.arc = function() {

d3.min.js

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

d3.time.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,7 @@ d3.time.years.utc = d3_time_range(d3.time.year.utc, function(date) {
502502
return date.getUTCFullYear();
503503
});
504504
// TODO nice
505-
function d3_time_scale(methods, format) {
506-
var linear = d3.scale.linear();
505+
function d3_time_scale(linear, methods, format) {
507506

508507
function scale(x) {
509508
return linear(x);
@@ -537,6 +536,10 @@ function d3_time_scale(methods, format) {
537536
return format;
538537
};
539538

539+
scale.clone = function() {
540+
return d3_time_scale(linear.clone(), methods, format);
541+
};
542+
540543
// TOOD expose d3_scale_linear_rebind?
541544
scale.range = d3.rebind(scale, linear.range);
542545
scale.rangeRound = d3.rebind(scale, linear.rangeRound);
@@ -619,7 +622,7 @@ var d3_time_scaleLocalFormats = [
619622
var d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
620623

621624
d3.time.scale = function() {
622-
return d3_time_scale(d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
625+
return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
623626
};
624627
var d3_time_scaleUTCMethods = [
625628
[d3.time.seconds.utc, 1],
@@ -655,6 +658,6 @@ var d3_time_scaleUTCFormats = [
655658
var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
656659

657660
d3.time.scale.utc = function() {
658-
return d3_time_scale(d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
661+
return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
659662
};
660663
})();

0 commit comments

Comments
 (0)