Reputation: 23
I'm trying to create an animated arc segment with d3.js. I got the arc and the transition working, but while the animation is running, the arc gets distorted and I can't figure out why.
Here is what i have so far:
var dataset = {
apples: [532, 284]
};
var degree = Math.PI/180;
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie().startAngle(-90*degree).endAngle(90*degree)
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(dataset.apples))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
window.setInterval(dummyData, 2000);
function dummyData(){
var num = Math.round(Math.random() * 100);
var key = Math.floor(Math.random() * dataset.apples.length);
dataset.apples[key] = num;
draw();
};
function draw(){
svg.selectAll("path")
.data(pie(dataset.apples))
.transition()
.duration(2500)
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
}
Upvotes: 2
Views: 2535
Reputation: 211
As Richard explained, you're interpolating between the previously computed SVG path string and the newly computed string -- which is going to do some strange things -- rather than interpolating between the previous angle and the new angle, which is what you want.
You need to interpolate over the input and for each interpolated value map that to an SVG path string using your arc
function. To do this, you need to store each previous datum somewhere and to use a custom tweening function, which you can find in examples in my previous comment.
1. Remember previous datum (initially):
.each(function(d) { this._current = d; });
2. Define a custom tweening function:
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0); // Remember previous datum for next time
return function(t) {
return arc(i(t));
};
}
3. Use it:
.attrTween("d", arcTween)
Here's what it looks like: http://jsfiddle.net/Qh9X5/18/
Upvotes: 1