Skip to content

Commit cc359a9

Browse files
committed
Fix bug with unexpected transition inheritance.
Prior to this change, transitions used transition.each internally, which had the unexpected side-effect of enabling transitions on d3.transition(selection) when called from within a tween function. This would only occur on the first invocation of the tween function when the elapsed time between the transition creation and the transition start was greater than the transition delay; however, this is fairly common as the default delay for transitions is zero. This bug caused unexpected behavior if you tried to redraw an axis within a custom tween function: in some cases, the synchronous redraw of the axis would compete with a concurrent transition, causing unexpected behavior. By avoiding the use of transition.each internally, the user now controls when automatic transitions are enabled.
1 parent ad43a2e commit cc359a9

7 files changed

Lines changed: 58 additions & 64 deletions

File tree

d3.v2.js

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,14 +2011,19 @@ d3_selectionPrototype.on = function(type, listener, capture) {
20112011
});
20122012
};
20132013
d3_selectionPrototype.each = function(callback) {
2014-
for (var j = -1, m = this.length; ++j < m;) {
2015-
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
2016-
var node = group[i];
2017-
if (node) callback.call(node, node.__data__, i, j);
2014+
return d3_selection_each(this, function(node, i, j) {
2015+
callback.call(node, node.__data__, i, j);
2016+
});
2017+
};
2018+
2019+
function d3_selection_each(groups, callback) {
2020+
for (var j = 0, m = groups.length; j < m; j++) {
2021+
for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
2022+
if (node = group[i]) callback(node, i, j);
20182023
}
20192024
}
2020-
return this;
2021-
};
2025+
return groups;
2026+
}
20222027
//
20232028
// Note: assigning to the arguments array simultaneously changes the value of
20242029
// the corresponding argument!
@@ -2145,12 +2150,12 @@ function d3_transition(groups, id, time) {
21452150
};
21462151

21472152
d3.timer(function(elapsed) {
2148-
groups.each(function(d, i, j) {
2153+
return d3_selection_each(groups, function(node, i, j) {
21492154
var tweened = [],
2150-
node = this,
2151-
delay = groups[j][i].delay,
2152-
duration = groups[j][i].duration,
2153-
lock = node.__transition__ || (node.__transition__ = {active: 0, count: 0});
2155+
delay = node.delay,
2156+
duration = node.duration,
2157+
lock = (node = node.node).__transition__ || (node.__transition__ = {active: 0, count: 0}),
2158+
d = node.__data__;
21542159

21552160
++lock.count;
21562161

@@ -2196,7 +2201,6 @@ function d3_transition(groups, id, time) {
21962201
return 1;
21972202
}
21982203
});
2199-
return 1;
22002204
}, 0, time);
22012205

22022206
return groups;
@@ -2341,16 +2345,14 @@ d3_transitionPrototype.remove = function() {
23412345
});
23422346
};
23432347
d3_transitionPrototype.delay = function(value) {
2344-
var groups = this;
2345-
return groups.each(typeof value === "function"
2346-
? function(d, i, j) { groups[j][i].delay = value.apply(this, arguments) | 0; }
2347-
: (value = value | 0, function(d, i, j) { groups[j][i].delay = value; }));
2348+
return d3_selection_each(this, typeof value === "function"
2349+
? function(node, i, j) { node.delay = value.call(node = node.node, node.__data__, i, j) | 0; }
2350+
: (value = value | 0, function(node) { node.delay = value; }));
23482351
};
23492352
d3_transitionPrototype.duration = function(value) {
2350-
var groups = this;
2351-
return groups.each(typeof value === "function"
2352-
? function(d, i, j) { groups[j][i].duration = Math.max(1, value.apply(this, arguments) | 0); }
2353-
: (value = Math.max(1, value | 0), function(d, i, j) { groups[j][i].duration = value; }));
2353+
return d3_selection_each(this, typeof value === "function"
2354+
? function(node, i, j) { node.duration = Math.max(1, value.call(node = node.node, node.__data__, i, j) | 0); }
2355+
: (value = Math.max(1, value | 0), function(node) { node.duration = value; }));
23542356
};
23552357
function d3_transition_each(callback) {
23562358
var id = d3_transitionId,
@@ -2360,16 +2362,11 @@ function d3_transition_each(callback) {
23602362

23612363
d3_transitionId = this.id;
23622364
d3_transitionEase = this.ease();
2363-
for (var j = 0, m = this.length; j < m; j++) {
2364-
for (var group = this[j], i = 0, n = group.length; i < n; i++) {
2365-
var node = group[i];
2366-
if (node) {
2367-
d3_transitionDelay = this[j][i].delay;
2368-
d3_transitionDuration = this[j][i].duration;
2369-
callback.call(node = node.node, node.__data__, i, j);
2370-
}
2371-
}
2372-
}
2365+
d3_selection_each(this, function(node, i, j) {
2366+
d3_transitionDelay = node.delay;
2367+
d3_transitionDuration = node.duration;
2368+
callback.call(node = node.node, node.__data__, i, j);
2369+
});
23732370

23742371
d3_transitionId = id;
23752372
d3_transitionEase = ease;

d3.v2.min.js

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

src/core/selection-each.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
d3_selectionPrototype.each = function(callback) {
2-
for (var j = -1, m = this.length; ++j < m;) {
3-
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
4-
var node = group[i];
5-
if (node) callback.call(node, node.__data__, i, j);
2+
return d3_selection_each(this, function(node, i, j) {
3+
callback.call(node, node.__data__, i, j);
4+
});
5+
};
6+
7+
function d3_selection_each(groups, callback) {
8+
for (var j = 0, m = groups.length; j < m; j++) {
9+
for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
10+
if (node = group[i]) callback(node, i, j);
611
}
712
}
8-
return this;
9-
};
13+
return groups;
14+
}

src/core/transition-delay.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
d3_transitionPrototype.delay = function(value) {
2-
var groups = this;
3-
return groups.each(typeof value === "function"
4-
? function(d, i, j) { groups[j][i].delay = value.apply(this, arguments) | 0; }
5-
: (value = value | 0, function(d, i, j) { groups[j][i].delay = value; }));
2+
return d3_selection_each(this, typeof value === "function"
3+
? function(node, i, j) { node.delay = value.call(node = node.node, node.__data__, i, j) | 0; }
4+
: (value = value | 0, function(node) { node.delay = value; }));
65
};

src/core/transition-duration.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
d3_transitionPrototype.duration = function(value) {
2-
var groups = this;
3-
return groups.each(typeof value === "function"
4-
? function(d, i, j) { groups[j][i].duration = Math.max(1, value.apply(this, arguments) | 0); }
5-
: (value = Math.max(1, value | 0), function(d, i, j) { groups[j][i].duration = value; }));
2+
return d3_selection_each(this, typeof value === "function"
3+
? function(node, i, j) { node.duration = Math.max(1, value.call(node = node.node, node.__data__, i, j) | 0); }
4+
: (value = Math.max(1, value | 0), function(node) { node.duration = value; }));
65
};

src/core/transition-each.js

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,11 @@ function d3_transition_each(callback) {
66

77
d3_transitionId = this.id;
88
d3_transitionEase = this.ease();
9-
for (var j = 0, m = this.length; j < m; j++) {
10-
for (var group = this[j], i = 0, n = group.length; i < n; i++) {
11-
var node = group[i];
12-
if (node) {
13-
d3_transitionDelay = this[j][i].delay;
14-
d3_transitionDuration = this[j][i].duration;
15-
callback.call(node = node.node, node.__data__, i, j);
16-
}
17-
}
18-
}
9+
d3_selection_each(this, function(node, i, j) {
10+
d3_transitionDelay = node.delay;
11+
d3_transitionDuration = node.duration;
12+
callback.call(node = node.node, node.__data__, i, j);
13+
});
1914

2015
d3_transitionId = id;
2116
d3_transitionEase = ease;

src/core/transition.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ function d3_transition(groups, id, time) {
2929
};
3030

3131
d3.timer(function(elapsed) {
32-
groups.each(function(d, i, j) {
32+
return d3_selection_each(groups, function(node, i, j) {
3333
var tweened = [],
34-
node = this,
35-
delay = groups[j][i].delay,
36-
duration = groups[j][i].duration,
37-
lock = node.__transition__ || (node.__transition__ = {active: 0, count: 0});
34+
delay = node.delay,
35+
duration = node.duration,
36+
lock = (node = node.node).__transition__ || (node.__transition__ = {active: 0, count: 0}),
37+
d = node.__data__;
3838

3939
++lock.count;
4040

@@ -80,7 +80,6 @@ function d3_transition(groups, id, time) {
8080
return 1;
8181
}
8282
});
83-
return 1;
8483
}, 0, time);
8584

8685
return groups;

0 commit comments

Comments
 (0)