2

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:

jsfiddle

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);   
}
  • Have you seen [this example](http://blog.stephenboak.com/2011/08/07/easy-as-a-pie.html)? – Lars Kotthoff May 23 '13 at 14:57
  • I think D3 is interpolating between each set of points for you, so animating between each state by moving the points along a straight line, rather than along a radial as you'd like. To accomplish that you need to specify a tweening function that specifies the transition animation that you want. The example Lars linked to should show you what you need. – Richard Marr May 23 '13 at 15:54
  • The example linked strangely refers to a function (`pieTween`) that is never provided. Have a look at these possibly more useful examples: [Pie Chart Update, II](http://bl.ocks.org/mbostock/1346410), [Arc Tween (Clock)](http://bl.ocks.org/mbostock/1098617) and [explanation of why this is necessary by d3 creator Mike Bostock](http://stackoverflow.com/a/10090745/1798568). – serhalp May 23 '13 at 16:45

1 Answers1

1

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/

serhalp
  • 201
  • 2
  • 7
  • Another problem is that its setting an interval to 2 seconds. And the animation takes 2,5 seconds. So, it should be modified the transition time to be below the new data coming time. – Tom Roggero May 23 '13 at 17:13