Skip to content

Instantly share code, notes, and snippets.

@veltman
Last active July 3, 2016 10:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save veltman/94a6ddbb5c4a23ebae34 to your computer and use it in GitHub Desktop.
Save veltman/94a6ddbb5c4a23ebae34 to your computer and use it in GitHub Desktop.
Jumping to the end of a transition

An example of a way to declare the end-state of a transition once in a generic setter with chaining, and then use that setter on the transition to update gradually or call it on a selection to jump to the end state.

Should work with .style(), .attr(), .styleTween(), and .attrTween(), but not .tween().

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
text-align: center;
}
button {
font-size: 24px;
}
circle {
stroke: none;
fill: #de1e3d;
}
path {
stroke-width: 1px;
stroke: black;
fill: none;
}
</style>
<body>
<div><button>Jump To End</button></div>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.10/d3.min.js"></script>
<script>
var width = 860,
height = 300,
margin = 50;
var svg = d3.select("body").append("svg")
.attr("width",width + margin * 2)
.attr("height",height + margin * 2)
.append("g")
.attr("transform","translate(" + margin + " " + margin + ")")
var path = svg.append("path")
.attr("d","M0 150 C 205 0, 225 0, 430 150 S 655 300, 860 150");
var dots = svg.selectAll("circle")
.data(d3.range(2))
.enter()
.append("circle")
.attr("r",25)
.attr("cx",function(d){
return d ? width : 0;
})
.attr("cy",height / 2);
var dotSetter = setter()
.style("fill",function(d){
return d ? "#0e88ba" : "#fc0";
})
.attr("cx",function(d){
return d ? 0 : width;
});
var pathSetter = setter()
.style("stroke-width","6px")
.attrTween("stroke-dasharray",tweenDash)
.attr("cx",width);
dots.transition()
.duration(3000)
.call(dotSetter);
path.transition()
.duration(3000)
.call(pathSetter);
d3.select("button").on("click",function(){
dots.interrupt().call(dotSetter);
path.interrupt().call(pathSetter);
});
function setter() {
var props = [];
function set(selection) {
props.forEach(function(p){
var idx = p.type.indexOf("Tween");
if (idx < 0 || selection instanceof d3.transition) {
selection[p.type](p.key,p.value);
} else {
// convert attrTween to attr and styleTween to style,
// call the tween with a t value of 1
// TODO: also catch generic `.tween()`?
// TODO: catch null tween returned from factory?
selection[p.type.slice(0,idx)](p.key,function(d,i){
return p.value.call(this,d,i)(1);
});
}
return selection;
});
}
["attr","style","text","attrTween","styleTween"].forEach(function(type){
set[type] = function(key,value) {
props.push({type: type, key: key, value: value});
return set;
};
});
return set;
}
function tweenDash() {
var l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l);
return function(t) { return i(t); };
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment