Transition hacking by overwriting Date.now
, tricking d3.timer
into thinking it’s whatever time we want. Beyond the obvious red flags of overwriting a browser global, this only really works for moving forward (each transition in a chain self-deletes once it hits t=1
). I would not recommend this.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
text-align: center;
font: 16px sans-serif;
}
button {
margin: 0 0.5em;
}
circle {
stroke: #000;
stroke-width: 1.5px;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js"></script>
<script>
var margin = {top: 100, right: 100, bottom: 100, left: 100},
width = 960 - margin.left - margin.right,
height = 440 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(d3.range(5))
.rangePoints([0, width]);
var y = x.copy()
.rangePoints([0, height]);
var color = d3.scale.linear()
.domain(d3.extent(x.domain()))
.range(["hsl(297,50%,47%)", "hsl(81,78%,61%)"])
.interpolate(d3.interpolateHcl);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var dots = svg.selectAll("circle")
.data(x.domain())
.enter()
.append("circle")
.attr("r",20)
.attr("cx",0)
.attr("cy",y)
.style("fill",color);
var curTime = 0,
_now = Date.now; // save for later
// FREEZE TIME
Date.now = function fakeNow(){
return curTime;
};
// Create a transition
dots.transition()
.duration(3500)
.delay(function(d){
return d * 125;
})
.attr("cx",x)
.attr("r",40)
.transition()
.duration(2000)
.attr("r",20)
.attr("cx",width);
d3.select("body").append("div")
.text("Jump to: ")
.selectAll("button")
.data(d3.range(0,6500,500))
.enter()
.append("button")
.text(function(d){
return (Math.round(d/100)/10) + " s";
})
.on("click",function(d){
curTime = d; // TIME TRAVEL
});
d3.select("div").append("button")
.text("Finish")
.style("font-weight","bold")
.on("click",function(){
d3.selectAll("button").attr("disabled",true).on("click",null);
var now = _now();
d3.timer(function(){
var t = _now();
curTime += (t - now);
now = t;
if (curTime >= 6000) {
// Transitions are all done
// Restore REAL TIME
Date.now = _now;
d3.select("div").remove();
return true;
}
},0,0);
});
</script>