KIC
KIC

Reputation: 6121

d3 - How to animate over array

I am pretty new to d3. For the moment I am able to draw circles based on an array of data - wow - I know :-) But now I would like to just draw two circles at one time while I animate the whole array. Let's say I have 1000 elements in my array and I want to draw 1 and 2 at the same time, then draw 2 and 3, 3 and 4 and so on. This should get a very pretty animation :-) I have played with functions i index and with exit().remove() but this does not work.

This is what I have:

var w = 500;
        var h = 300;
        var padding = 20;

        var dataset = [
                        [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
                        [410, 12], [475, 44], [25, 67], [85, 21], [220, 88],
                        [600, 150]
                      ];

        //Create SVG element
        var svg = d3.select("body")
            .append("svg")
            .attr("width", w)
            .attr("height", h);

        //Create scale functions
        var xScale = d3.scale.linear()
            .domain([0, d3.max(dataset, function(d) { return d[0]; })])
            .range([padding, w - padding * 2]);

        var yScale = d3.scale.linear()
            .domain([0, d3.max(dataset, function(d) { return d[1]; })])
            .range([h - padding, padding]);

        //Create circles
        svg.selectAll("circle")
               .data(dataset.slice(0,2))
               .enter()
               .append("circle")
               .attr("cx", function(d) {
                    return xScale(d[0]);
               })
               .attr("cy", function(d) {
                    return yScale(d[1]);
               })
               .attr("r",10);

        for (var i=0; i<4;i++) {

            svg.selectAll("circle").data(dataset.slice(i,i+2)).transition().duration(2000).delay(2000)
            .attr("cx", function(d) {
                    return xScale(d[0]);
               })
               .attr("cy", function(d) {
                    return yScale(d[1]);
               })
               .attr("r", 10);
            //svg.selectAll("circle").data(dataset.slice(i,i+1)).exit().remove();
            console.log(dataset.slice(i,i+2));
        }

But I will get only one single animation instead of 4 .. hmm .. what is going wrong?

Upvotes: 2

Views: 2094

Answers (2)

david4096
david4096

Reputation: 204

The delay function accepts callbacks, so there is no need to wrap your selection in a for loop.

    .delay( function(d, i) { (2000*i); } )

Upvotes: 1

logical Chimp
logical Chimp

Reputation: 1014

Looking at the code, you've got a fixed duration (2s) and a fixed delay (2s). The FOR loop will run instantly, thus queueing all four animations up at once, and thus they are probably all playing at the same time - but (probably) only the last will be visible because you've rebound the data.

try something like:

svg.selectAll("circle")
   .delay( (2000*i) )
   .data(dataset.slice(i,i+2))
   .transition()
   .duration(2000)
   .attr("cx", function(d) {return xScale(d[0]);})
   .attr("cy", function(d) {return yScale(d[1]);})
   .attr("r", 10);)

Multiplying the delay by the animation counter should offset each animation, and by putting the delay first, it should the data gets rebound just before starting the animation (thereby stopping the final animation step from rebinding it's data before the first animation has run)

Upvotes: 0

Related Questions