Don’t pollute an ordinal scale’s domain.

Fixes #1550. By using the copy of the new scale (which we make anyway for a
snapshot) we avoid polluting the scale’s domain with the old values when using
the scale as the key function for the tick data-join.
This commit is contained in:
Mike Bostock 2013-09-26 14:08:16 -07:00
Родитель 9eb878ec7d
Коммит d2ad436fed
4 изменённых файлов: 30 добавлений и 35 удалений

9
d3.js поставляемый
Просмотреть файл

@ -7886,11 +7886,10 @@ d3 = function() {
function axis(g) {
g.each(function() {
var g = d3.select(this);
var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform;
var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"),
var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy();
var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform;
var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"),
d3.transition(path));
var scale1 = scale.copy(), scale0 = this.__chart__ || scale1;
this.__chart__ = scale1;
tickEnter.append("line");
tickEnter.append("text");
var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text");
@ -7943,7 +7942,7 @@ d3 = function() {
break;
}
}
if (scale.rangeBand) {
if (scale1.rangeBand) {
var dx = scale1.rangeBand() / 2, x = function(d) {
return scale1(d) + dx;
};

2
d3.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -19,25 +19,24 @@ d3.svg.axis = function() {
g.each(function() {
var g = d3.select(this);
// Stash a snapshot of the new scale, and retrieve the old snapshot.
var scale0 = this.__chart__ || scale,
scale1 = this.__chart__ = scale.copy();
// Ticks, or domain values for ordinal scales.
var ticks = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain()) : tickValues,
tickFormat = tickFormat_ == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : d3_identity) : tickFormat_,
tick = g.selectAll(".tick").data(ticks, scale),
var ticks = tickValues == null ? (scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain()) : tickValues,
tickFormat = tickFormat_ == null ? (scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity) : tickFormat_,
tick = g.selectAll(".tick").data(ticks, scale1),
tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε),
tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(),
tickUpdate = d3.transition(tick).style("opacity", 1),
tickTransform;
// Domain.
var range = d3_scaleRange(scale),
var range = d3_scaleRange(scale1),
path = g.selectAll(".domain").data([0]),
pathUpdate = (path.enter().append("path").attr("class", "domain"), d3.transition(path));
// Stash a snapshot of the new scale, and retrieve the old snapshot.
var scale1 = scale.copy(),
scale0 = this.__chart__ || scale1;
this.__chart__ = scale1;
tickEnter.append("line");
tickEnter.append("text");
@ -94,7 +93,7 @@ d3.svg.axis = function() {
// - any entering ticks are undefined in the old scale
// - any exiting ticks are undefined in the new scale
// Therefore, we only need to transition updating ticks.
if (scale.rangeBand) {
if (scale1.rangeBand) {
var dx = scale1.rangeBand() / 2, x = function(d) { return scale1(d) + dx; };
tickEnter.call(tickTransform, x);
tickUpdate.call(tickTransform, x);

Просмотреть файл

@ -72,6 +72,15 @@ suite.addBatch({
assert.inDelta(g.selectAll(".tick").data(), [4, 5, 6], 1e-4);
assert.inDelta(g.selectAll(".tick").data().map(x), [30, 60, 90], 1e-4);
assert.equal(g.select("path").attr("d"), "M0,6V0H90V6");
},
"when an ordinal scale, does not pollute the scales domain with old values": function(d3) {
var x = _.scale.ordinal().domain(["A", "B", "C"]).range([10, 50, 90]),
a = d3.svg.axis().scale(x),
g = d3.select("body").html("").append("g").call(a),
path = g.selectAll("path");
x.domain(["D", "E"]);
g.call(a);
assert.deepEqual(x.domain(), ["D", "E"]);
}
},
@ -305,6 +314,7 @@ suite.addBatch({
"passes any arguments to the scale's ticks function": function(d3) {
var x = _.scale.linear(), b = {}, a = d3.svg.axis().ticks(b, "%").scale(x), aa = [],
g = d3.select("body").html("").append("g");
x.copy = function() { return x; };
x.ticks = function() { aa.push(arguments); return [42]; };
g.call(a);
assert.equal(aa.length, 1);
@ -318,12 +328,8 @@ suite.addBatch({
a = d3.svg.axis().scale(x).ticks(b, "%"),
g = d3.select("body").html("").append("g"),
aa = [];
x.tickFormat = function() {
aa.push(arguments);
return String;
};
x.copy = function() { return x; };
x.tickFormat = function() { aa.push(arguments); return String; };
g.call(a);
assert.equal(aa.length, 1);
assert.equal(aa[0].length, 2);
@ -367,12 +373,8 @@ suite.addBatch({
a = d3.svg.axis().scale(x).ticks(10).tickValues([1, 2, 3]),
g = d3.select("body").html("").append("g"),
aa = [];
x.tickFormat = function() {
aa.push(arguments);
return String;
};
x.copy = function() { return x; };
x.tickFormat = function() { aa.push(arguments); return String; };
g.call(a);
assert.equal(aa.length, 1);
assert.equal(aa[0].length, 1);
@ -403,13 +405,8 @@ suite.addBatch({
"when null, uses the scale's tick format": function(d3) {
var x = _.scale.linear(), a = d3.svg.axis().scale(x),
g = d3.select("body").html("").append("g");
x.tickFormat = function() {
return function(d) {
return "foo-" + d;
};
};
x.copy = function() { return x; };
x.tickFormat = function() { return function(d) { return "foo-" + d; }; };
g.call(a);
var t = g.selectAll("g text");
assert.equal(t.text(), "foo-0");