Skip to content

Commit be2bee7

Browse files
committed
Fix d3#1402 - transition callback order.
Rather than registering new timers, reassign the transition’s timer callback in- place such that the order of callbacks for transitions is always prioritized based on when the transition was created.
1 parent 95bc9f4 commit be2bee7

4 files changed

Lines changed: 51 additions & 47 deletions

File tree

d3.js

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,14 +1881,14 @@ d3 = function() {
18811881
};
18821882
d3.csv = d3.dsv(",", "text/csv");
18831883
d3.tsv = d3.dsv(" ", "text/tab-separated-values");
1884-
var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout;
1884+
var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) {
1885+
setTimeout(callback, 17);
1886+
};
18851887
d3.timer = function(callback, delay, then) {
1886-
if (arguments.length < 3) {
1887-
if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return;
1888-
then = Date.now();
1889-
}
1890-
var time = then + delay;
1891-
var timer = {
1888+
var n = arguments.length;
1889+
if (n < 2) delay = 0;
1890+
if (n < 3) then = Date.now();
1891+
var time = then + delay, timer = {
18921892
callback: callback,
18931893
time: time,
18941894
next: null
@@ -1918,11 +1918,19 @@ d3 = function() {
19181918
d3_timer_mark();
19191919
d3_timer_sweep();
19201920
};
1921+
function d3_timer_replace(callback, delay, then) {
1922+
var n = arguments.length;
1923+
if (n < 2) delay = 0;
1924+
if (n < 3) then = Date.now();
1925+
d3_timer_active.callback = callback;
1926+
d3_timer_active.time = then + delay;
1927+
}
19211928
function d3_timer_mark() {
1922-
var now = Date.now(), timer = d3_timer_queueHead;
1923-
while (timer) {
1924-
if (now >= timer.time) timer.flush = timer.callback(now - timer.time);
1925-
timer = timer.next;
1929+
var now = Date.now();
1930+
d3_timer_active = d3_timer_queueHead;
1931+
while (d3_timer_active) {
1932+
if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time);
1933+
d3_timer_active = d3_timer_active.next;
19261934
}
19271935
return now;
19281936
}
@@ -1939,9 +1947,6 @@ d3 = function() {
19391947
d3_timer_queueTail = t0;
19401948
return time;
19411949
}
1942-
var d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) {
1943-
setTimeout(callback, 17);
1944-
};
19451950
var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$";
19461951
var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix);
19471952
d3.formatPrefix = function(value, precision) {
@@ -7701,7 +7706,7 @@ d3 = function() {
77017706
++lock.count;
77027707
d3.timer(function(elapsed) {
77037708
var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, tweened = [];
7704-
return delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time), 1;
7709+
if (delay <= elapsed) start(elapsed); else d3_timer_replace(start, delay, time);
77057710
function start(elapsed) {
77067711
if (lock.active > id) return stop();
77077712
lock.active = id;
@@ -7711,8 +7716,8 @@ d3 = function() {
77117716
tweened.push(value);
77127717
}
77137718
});
7714-
if (!tick(elapsed)) d3.timer(tick, 0, time);
7715-
return 1;
7719+
if (tick(elapsed)) return 1;
7720+
d3_timer_replace(tick, 0, time);
77167721
}
77177722
function tick(elapsed) {
77187723
if (lock.active !== id) return stop();
@@ -7731,7 +7736,6 @@ d3 = function() {
77317736
return 1;
77327737
}
77337738
}, 0, time);
7734-
return transition;
77357739
}
77367740
}
77377741
d3.svg.axis = function() {

d3.min.js

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

src/event/timer.js

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,18 @@ import "../core/vendor";
44
var d3_timer_queueHead,
55
d3_timer_queueTail,
66
d3_timer_interval, // is an interval (or frame) active?
7-
d3_timer_timeout; // is a timeout active?
7+
d3_timer_timeout, // is a timeout active?
8+
d3_timer_active, // active timer object
9+
d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { setTimeout(callback, 17); };
810

911
// The timer will continue to fire until callback returns true.
1012
d3.timer = function(callback, delay, then) {
11-
if (arguments.length < 3) {
12-
if (arguments.length < 2) delay = 0;
13-
else if (!isFinite(delay)) return;
14-
then = Date.now();
15-
}
16-
17-
var time = then + delay;
13+
var n = arguments.length;
14+
if (n < 2) delay = 0;
15+
if (n < 3) then = Date.now();
1816

1917
// Add the callback to the tail of the queue.
20-
var timer = {callback: callback, time: time, next: null};
18+
var time = then + delay, timer = {callback: callback, time: time, next: null};
2119
if (d3_timer_queueTail) d3_timer_queueTail.next = timer;
2220
else d3_timer_queueHead = timer;
2321
d3_timer_queueTail = timer;
@@ -50,12 +48,20 @@ d3.timer.flush = function() {
5048
d3_timer_sweep();
5149
};
5250

51+
function d3_timer_replace(callback, delay, then) {
52+
var n = arguments.length;
53+
if (n < 2) delay = 0;
54+
if (n < 3) then = Date.now();
55+
d3_timer_active.callback = callback;
56+
d3_timer_active.time = then + delay;
57+
}
58+
5359
function d3_timer_mark() {
54-
var now = Date.now(),
55-
timer = d3_timer_queueHead;
56-
while (timer) {
57-
if (now >= timer.time) timer.flush = timer.callback(now - timer.time);
58-
timer = timer.next;
60+
var now = Date.now();
61+
d3_timer_active = d3_timer_queueHead;
62+
while (d3_timer_active) {
63+
if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time);
64+
d3_timer_active = d3_timer_active.next;
5965
}
6066
return now;
6167
}
@@ -77,6 +83,3 @@ function d3_timer_sweep() {
7783
d3_timer_queueTail = t0;
7884
return time;
7985
}
80-
81-
var d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")]
82-
|| function(callback) { setTimeout(callback, 17); };

src/transition/transition.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,8 @@ function d3_transitionNode(node, i, id, inherit) {
6969
duration = transition.duration,
7070
tweened = [];
7171

72-
return delay <= elapsed
73-
? start(elapsed)
74-
: d3.timer(start, delay, time), 1;
72+
if (delay <= elapsed) start(elapsed);
73+
else d3_timer_replace(start, delay, time);
7574

7675
function start(elapsed) {
7776
if (lock.active > id) return stop();
@@ -84,8 +83,8 @@ function d3_transitionNode(node, i, id, inherit) {
8483
}
8584
});
8685

87-
if (!tick(elapsed)) d3.timer(tick, 0, time);
88-
return 1;
86+
if (tick(elapsed)) return 1;
87+
d3_timer_replace(tick, 0, time);
8988
}
9089

9190
function tick(elapsed) {
@@ -112,7 +111,5 @@ function d3_transitionNode(node, i, id, inherit) {
112111
return 1;
113112
}
114113
}, 0, time);
115-
116-
return transition;
117114
}
118115
}

0 commit comments

Comments
 (0)