Please see this pen for a working but janky version of what I want: a d3 animation that simulates, in real time, the path of a line being draw by a person.
I have two issues with my current implementation:
It's choppy. You can see each piece of the path appearing as a chunk, rather than looking as if it was the path of a pen being moved across the screen. One solution is to make each chunk smaller -- is there any other solution?
It's recursive. Recursively calling draw with setTimeout()
feels antithetical to the d3 spirit. Is there a more declarative solution? Perhaps one using transition()
?
var svg = d3.select("body").append("svg")
.attr("width", "100%")
.attr("height", "100%");
var lineData = d3.range(5,800,15).map(function(x) {
return {x: x, y: 10 + Math.floor(Math.random()*6)-3}
});
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("basis");
function draw(points) {
var lineGraph = svg.append("path")
.attr("stroke", "blue")
.attr("stroke-width", 1)
.attr("fill", "none")
.attr("d", lineFunction(points));
if (points.length < lineData.length)
setTimeout(function(){
draw(lineData.slice(0,points.length+1));
}, 50);
}
draw([]);
See this simple (and neat) trick for gradually animating the drawing of a path, using stroke-dasharray
. Here's your code, modified.
var lineGraph = svg
.append("path")
.attr("stroke", "blue")
.attr("stroke-width", 1)
.attr("fill", "none")
.attr("d", lineFunction(lineData))
.transition()
.duration(5000)
.attrTween("stroke-dasharray", tweenDash)
function tweenDash() {
var l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l);
return function(t) { return i(t); };
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With