How to do animation of sequential data with d3.js?

白昼怎懂夜的黑 提交于 2020-01-04 05:33:27

问题


I have a sequential data. Data is an array divided into 30 steps. In the first step I draw initial data. Then I take data from second step, compare it with data from previous step. And make some animation/transition.

Now I want to repeat animation for the rest of 28 steps. If I will use code like this

var old_data = start_data;
for (var i = 0, i < rest_data.length; i++){
    var new_data = rest_data[i];
    var diff_data = diff(old_data, new_data);

    var t0 = d3.transition().duration(3000);
    var selection = d3.selectAll('g').data(diff_data)
    selection.transition(t0).attr('my', function(d,i) { ... });
    old_data = new_data;
}       

it will not work because transition() is async code.The loop run faster than complete the first animation. And at best I will have an animation between data[0] and data[29].

What is the best way to create an animation with sequential data like my?

Use d3.transition().on('end', function() {...}), where function() { ... } some function with closure where I will store old_data, rest_data and other variables? I don't like this solution because I have many variables to calculate diff_data, and I have to keep them in the closure.


回答1:


You are correct: the for loop will run to the end almost instantly, and it will simply call that bunch of transitions at the same time, which, of course, will not work.

There are some different solutions here. Good news is that transition().on("end"... is just one of them, you don't need to use it if you don't want.

My favourite one is creating a function that you call repeatedly with setTimeout or, even better, with d3.timeout.

This is the logic of it:

var counter = 0;//this is, of course, a counter

function loop(){

    //if there is a data element for the next counter index, call 'loop' again:
    if(data[counter + 1]){ d3.timeout(loop, delay)}

    //access the data using the counter here,
    //and manipulate the selection

    //increase the counter
    counter++;

}

Have a look at this demo:

var data = [30, 400, 170, 280, 460, 40, 250];
var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 100);
var circle = svg.append("circle")
  .attr("cy", 50)
  .attr("cx", 250)
  .attr("r", 10)
  .attr("fill", "tan")
  .attr("stroke", "black");

var counter = 0;

loop();

function loop() {
  if (data[counter + 1]) {
    d3.timeout(loop, 1000)
  }
  circle.transition()
    .duration(500)
    .attr("cx", data[counter]);
  counter++
}
<script src="https://d3js.org/d3.v4.min.js"></script>


来源:https://stackoverflow.com/questions/45258853/how-to-do-animation-of-sequential-data-with-d3-js

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!