Skip to content

Instantly share code, notes, and snippets.

@magjac
Last active August 13, 2017 11:43
Show Gist options
  • Save magjac/a06c2e3c541bcb07d4ce888a8a60f915 to your computer and use it in GitHub Desktop.
Save magjac/a06c2e3c541bcb07d4ce888a8a60f915 to your computer and use it in GitHub Desktop.
Jumps in Chained Transitions Because of Long Computational Time at the Start and End Event Callbacks of the First Transition
height: 250

This example shows that:

  • A long computational time in the start event callback of a transition causes the transition to jump.
  • If a long computational time in the end event of the first of two chained transitions is not accomodated for as a delay in the second, the transition jumps. The solution to this problem is to add a delay to the second transition that is equal to or larger than the computational time. See that solution in action here.

Timeline:

  • 0 s:
  • A small red rectangle is drawn
  • The first transition is scheduled to start at 2 s and end at 6 s
  • The second transition is scheduled to start at 6 s (after the first) and end at 10 s
  • 2 s:
  • The first transition starts and calls its event callback
  • The first transtion end event callback returns after wasting 2 s
  • The small rectangle should starts to grow to a medium size rectange, but doesn't
  • 4 s:
  • The first transition starts 2 seconds too late, causing the transition to jump
  • 6 s:
  • The first transition ends and calls its event callback
  • The rectangle should start to grow to a large rectangle and fade to blue, but doesn't
  • 8 s:
  • The first transtion end event callback returns after wasting 2 s
  • The second transition starts 2 seconds too late, causing the transition to jump
  • 10 s:
  • The second transition ends

Open the console if you want to see timestamped events during the transitions.

Note: a bug in d3-timer that is fixed, but at the time of this writing not yet released, requires this example to use a non official d3-timer.min.js.

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3-selection.v1.min.js"></script>
<!-- This script is d3-timer.min.js with https://github.com/d3/d3-timer/pull/28 that fixes https://github.com/d3/d3-timer/issues/27 -->
<script>!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})}(this,function(t){"use strict";function n(){return h||(x(e),h=v.now()+y)}function e(){h=0}function o(){this._call=this._time=this._next=null}function i(t,n,e){var i=new o;return i.restart(t,n,e),i}function r(){n(),++_;for(var t,e=f;e;)(t=h-e._time)>=0&&e._call.call(null,t),e=e._next;--_}function u(){h=(d=v.now())+y,_=m=0;try{r()}finally{_=0,c(),h=0}}function l(){var t=v.now(),n=t-d;n>w&&(y-=n,d=t)}function c(){for(var t,n,e=f,o=1/0;e;)e._call?(o>e._time&&(o=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:f=n);s=t,a(o)}function a(t){_||(m&&(m=clearTimeout(m)),t-h>24?(t<1/0&&(m=setTimeout(u,t-v.now()-y)),p&&(p=clearInterval(p))):(p||(d=v.now(),p=setInterval(l,w)),_=1,x(u)))}var f,s,_=0,m=0,p=0,w=1e3,d=0,h=0,y=0,v="object"==typeof performance&&performance.now?performance:Date,x="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};o.prototype=i.prototype={constructor:o,restart:function(t,e,o){if("function"!=typeof t)throw new TypeError("callback is not a function");o=(null==o?n():+o)+(null==e?0:+e),this._next||s===this||(s?s._next=this:f=this,s=this),this._call=t,this._time=o,a()},stop:function(){this._call&&(this._call=null,this._time=1/0,a())}};t.now=n,t.timer=i,t.timerFlush=r,t.timeout=function(t,n,e){var i=new o;return n=null==n?0:+n,i.restart(function(e){i.stop(),t(e+n)},n,e),i},t.interval=function(t,e,i){var r=new o,u=e;return null==e?(r.restart(t,e,i),r):(e=+e,i=null==i?n():+i,r.restart(function n(o){o+=u,r.restart(n,u+=e,i),t(o)},e,i),r)},Object.defineProperty(t,"__esModule",{value:!0})});</script>
<script src="//d3js.org/d3-dispatch.v1.min.js"></script>
<script src="//d3js.org/d3-interpolate.v1.min.js"></script>
<script src="//d3js.org/d3-color.v1.min.js"></script>
<script src="//d3js.org/d3-ease.v1.min.js"></script>
<script src="//d3js.org/d3-transition.v1.min.js"></script>
<script src="//d3js.org/d3-scale.v1.min.js"></script>
<script src="//d3js.org/d3-zoom.v1.min.js"></script>
<div style="text-align: center;"></div>
<script>
var start = Date.now();
function elapsed() {
return Date.now() - start;
}
function waste(time) {
var t0 = Date.now();
while (Date.now() - t0 < time)
;
}
var svg = d3.select("div").append("svg")
.attr("width", 800)
.attr("height", 500);
var g = svg.append("g");
var start1Waste = 2000;
var end1Waste = 2000;
var start2Waste = 0;
var end2Waste = 0;
g.selectAll("rect")
.data([10, 100, 200])
.enter()
.append("rect")
.attr("width", d => d)
.attr("height", d => d)
.attr("fill", "none")
.attr("stroke", "black")
var rect = g.append("rect")
.attr("width", 10)
.attr("height", 10)
.style("fill", "#d62728")
.transition()
.delay(2000)
.duration(4000)
.ease(d3.easeLinear)
.attr("width", 100)
.attr("height", 100)
.on("start", function () {
console.log('Start event 1', elapsed() / 1000);
waste(start1Waste);
console.log('Start event 1 returning', elapsed() / 1000);
})
.on("end", function () {
console.log('End event 1', elapsed() / 1000);
waste(end1Waste);
console.log('End event 1 returning', elapsed() / 1000);
})
.transition()
// Without this delay, the second transition jumps
// .delay(end1Waste)
.attr("width", 200)
.attr("height", 200)
.style("fill", "#1f77b4")
.on("start", function () {
console.log('Start event 2', elapsed() / 1000);
waste(start2Waste);
console.log('Start event 2 returning', elapsed() / 1000);
})
.on("end", function () {
console.log('End event 2', elapsed() / 1000);
waste(end2Waste);
console.log('End event 2 returning', elapsed() / 1000);
})
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment