El Gato Blanco
El Gato Blanco

Reputation: 23

d3.js arc segment animation issue

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);   
}

Upvotes: 2

Views: 2535

Answers (1)

serhalp
serhalp

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

Related Questions