This example demonstrates controlling transitions separately in two groups of objects.
The two blocks are largely redundant - the intention is to show how arbitrary animations could be controlled on two distinct sets of objects using classes.
| var svg = d3.select("svg"), | |
| margin = {top: 40, right: 40, bottom: 40, left: 40}, | |
| width = svg.attr("width") - margin.left - margin.right, | |
| height = svg.attr("height") - margin.top - margin.bottom; | |
| var g = svg.append("g") | |
| .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
| data1 = [ | |
| [ | |
| {'x': 200, 'y': 150, 'r': 12, 'color': 'blue'}, | |
| {'x': 140, 'y': 83, 'r': 14, 'color': 'blue'}], | |
| [ | |
| {'x': 300, 'y': 190, 'r': 26, 'color': 'green'}, | |
| {'x': 240, 'y': 123, 'r': 27, 'color': 'green'}]] | |
| data2 = [ | |
| [ | |
| {'x': 500, 'y': 50, 'r': 30, 'color': 'red'}, | |
| {'x': 400, 'y': 90, 'r': 40, 'color': 'red'}, | |
| {'x': 440, 'y': 150, 'r': 34, 'color': 'red'}], | |
| [ | |
| {'x': 300, 'y': 200, 'r': 20, 'color': 'orange'}, | |
| {'x': 290, 'y': 240, 'r': 25, 'color': 'orange'}, | |
| {'x': 240, 'y': 300, 'r': 16, 'color': 'orange'}], | |
| [ | |
| {'x': 450, 'y': 260, 'r': 32, 'color': 'yellow'}, | |
| {'x': 460, 'y': 320, 'r': 25, 'color': 'yellow'}, | |
| {'x': 490, 'y': 360, 'r': 11, 'color': 'yellow'}]] | |
| // create group1 circles | |
| g.append('g') | |
| .selectAll("circle") | |
| .data(data1[0]) | |
| .enter() | |
| .append("circle") | |
| .attr('class', 'circ1') | |
| .attr('fill', function(d) { return d.color; }) | |
| .attr('cx', function(d) { return d.x; }) | |
| .attr('cy', function(d) { return d.y; }) | |
| .attr('r', function(d) { return d.r; }); | |
| // create group2 circles | |
| g.append('g') | |
| .selectAll("circle") | |
| .data(data2[0]) | |
| .enter() | |
| .append("circle") | |
| .attr('class', 'circ2') | |
| .attr('fill', function(d) { return d.color; }) | |
| .attr('cx', function(d) { return d.x; }) | |
| .attr('cy', function(d) { return d.y; }) | |
| .attr('r', function(d) { return d.r; }); | |
| var current_state_1 = 0; | |
| function update_circ1() { | |
| // compute current iteration stage | |
| current_state_1 = (current_state_1 + 1) % data1.length; | |
| var transitions1 = 0; | |
| d3.selectAll('.circ1') | |
| // update data | |
| .data(data1[current_state_1]) | |
| // update radius over r*35 | |
| .transition() | |
| .delay(function(d) { return d.r * 7; }) | |
| .duration(function(d) { return d.r * 35; }) | |
| .attr('r', function(d) { return d.r; }) | |
| // register the number of callbacks | |
| .on('start', function() { transitions1++; }) | |
| // update x, y, and fill over r*35 | |
| .transition() | |
| .duration(function(d) { return d.r * 35; }) | |
| .attr('fill', function(d) { return d.color; }) | |
| .attr('cx', function(d) { return d.x; }) | |
| .attr('cy', function(d) { return d.y; }) | |
| // wait for all to finish and then call update_circ1 again | |
| .on('end', function() { | |
| if( --transitions1 === 0 ) { | |
| update_circ1(); | |
| } | |
| }); | |
| } | |
| var current_state_2 = 0; | |
| function update_circ2() { | |
| // compute current iteration stage | |
| current_state_2 = (current_state_2 + 1) % data2.length; | |
| var transitions2 = 0; | |
| d3.selectAll('.circ2') | |
| // update data | |
| .data(data2[current_state_2]) | |
| // change color and radius over r*10 | |
| .transition() | |
| .delay(function(d) { return 500; }) | |
| .duration(function(d) { return d.r * 10; }) | |
| .attr('r', function(d) { return d.r; }) | |
| .attr('fill', function(d) { return d.color; }) | |
| // register the number of callbacks | |
| .on('start', function() { transitions2++; }) | |
| // change x position over 5000/r | |
| .transition() | |
| .delay(function(d) { return 5000 / d.r; }) | |
| .duration(function(d) { return d.r * 25; }) | |
| .attr('cx', function(d) { return d.x; }) | |
| // change y position over 5000/r | |
| .transition() | |
| .delay(function(d) { return 5000 / d.r; }) | |
| .duration(function(d) { return d.r * 25; }) | |
| .attr('cy', function(d) { return d.y; }) | |
| // wait for all to finish and then call update_circ2 again | |
| .on('end', function() { | |
| if( --transitions2 === 0 ) { | |
| update_circ2(); | |
| } | |
| }); | |
| } | |
| update_circ1(); | |
| update_circ2(); |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <svg width="760" height="500"></svg> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <script src="grouped.js"></script> |