Skip to content

Instantly share code, notes, and snippets.

@ezyang
Created December 11, 2012 19:44
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 ezyang/4261441 to your computer and use it in GitHub Desktop.
Save ezyang/4261441 to your computer and use it in GitHub Desktop.
Tweening lines with kinks
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<script src="http://d3js.org/d3.v3.js"></script>
<style>
path {stroke-width: 4px; fill:none; stroke:#000}
circle {fill:#000}
</style>
</head>
<body>
<script type="text/javascript">
var w = 700, h = 500;
var svg = d3.select("body").insert("svg")
.attr("width", w)
.attr("height", h);
var data1 = [{id:0,x:100,y:100}, {id:2,x:200,y:200}, {id:3,x:300,y:200,f:true}, {id:4,x:400,y:300,f:true}, {id:5,x:300,y:300}];
var data2 = [{id:0,x:200,y:200}, {id:1,x:200,y:300,f:true}, {id:2,x:400,y:200}, {id:5,x:500,y:400}];
var line = d3.svg.line().x(function(d){return d.x}).y(function(d){return d.y});
function fi(_,i) {return i}
function fid(d) {return d.id}
redraw(data1, 0);
var cur = false;
function tween(d2, i, a) {
var d1 = this.pathdata;
var i = 0, j = 0;
var nd1 = [], nd2 = [];
while (i < d1.length || j < d2.length) {
if (i < d1.length && j < d2.length && (d1[i].id == d2[j].id || (d1[i].f && d2[j].f))) {
nd1.push(d1[i++]);
nd2.push(d2[j++]);
} else if (j >= d2.length || d1[i].f) {
nd1.push(d1[i++]);
nd2.push(d2[j]);
} else if (i >= d1.length || d2[j].f) {
nd1.push(d1[i]);
nd2.push(d2[j++]);
} else {
throw "tween: impossible!";
}
}
this.pathdata = d2;
return d3.interpolate(line(nd1),line(nd2));
}
function redraw(data, dur) {
var path = svg.selectAll("path").data([data], fi);
var circle = svg.selectAll("circle").data(data, fid);
path
.enter()
.insert("path")
.property("pathdata", function(d) { return d; })
.attr("d", function(d) { return line(d); });
path.transition().duration(dur)
.attrTween("d", tween);
path.exit().remove();
circle.enter()
.insert("circle")
.filter(function(d) {return !d.f})
.attr("r", 6)
.attr("cx", function(d) {return d.x})
.attr("cy", function(d) {return d.y});
circle.transition().duration(dur)
.attr("cx", function(d) {return d.x})
.attr("cy", function(d) {return d.y});
circle.exit().remove();
}
</script>
<input value="Update" type="submit" onclick="redraw(cur ? data1 : data2, 1000); cur = !cur" />
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment