简体   繁体   中英

d3: repeat transition for series of elements?

I'm having trouble getting a transition to repeat, for a series of elements, in this case a set of three lines. The animation runs just fine once, but when it is repeated (with the same data), all three lines merge into a single line (the last array in data ). What am I doing wrong?

 (function() { var w = 100, h = 100 var div = d3.select('#sketches').append('div') var svg = div.append("svg") .attr("width", w) .attr("height", h) var x = 0, y = 55 var data = [ [x, y, x+20, y-40], [x+10, y, x+30, y-40], [x+20, y, x+40, y-40] ]; (function lines() { svg.selectAll('line') .data(data).enter().append('line') .attr("stroke", "black") .attr('x1', function(d) {return d[0]}) .attr('y1', function(d) {return d[1]}) .attr('x2', function(d) {return d[2]}) .attr('y2', function(d) {return d[3]}) .transition() .duration(3000) .ease('linear') .attr('x1', function(d) {return d[0] + 60}) .attr('y1', function(d) {return d[1]}) .attr('x2', function(d) {return d[2] + 60}) .attr('y2', function(d) {return d[3]}) .each('end', function(d) { d3.select(this).remove() lines() }) })() })() 
 body { padding: 1rem; } svg { background-color: silver; stroke: black; stroke-width: 1; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <div id="sketches"></div> 

The issue is the each function will initiate for each line you have. So actually what you are doing is calling lines() three times every time. Why it's yieling the output of one line I'm not entirely sure (still looking into it) but for some reason, it seems like data defaults to the last array so its only setting the drawing to be based on data[3] .

To fix it, you want to make sure lines() only gets called after it has finished going through removing all the lines so it only runs once. I'm pretty sure there is better way (ie a promise of some kind so after all of each has ran, it'll run a function, but what you can do is set a count and then just run lines() every N times where N is the number of lines you want removed. Because you go through array data and append a line for each index, N is data.length .

(I'm gonna see if there's a cleaner way to do this and I'll edit my answer if I find a way but hopefully this helps you understand the issue at the very least)

 (function() { var w = 100, h = 100 var div = d3.select('#sketches').append('div') var svg = div.append("svg") .attr("width", w) .attr("height", h) var x = 0, y = 55 var data = [ [x, y, x+20, y-40], [x+10, y, x+30, y-40], [x+20, y, x+40, y-40] ]; var count = 0; (function lines() { svg.selectAll('line') .data(data).enter().append('line') .attr("stroke", "black") .attr('x1', function(d) {return d[0]}) .attr('y1', function(d) {return d[1]}) .attr('x2', function(d) {return d[2]}) .attr('y2', function(d) {return d[3]}) .transition() .duration(3000) .ease('linear') .attr('x1', function(d) {return d[0] + 60}) .attr('y1', function(d) {return d[1]}) .attr('x2', function(d) {return d[2] + 60}) .attr('y2', function(d) {return d[3]}) .each('end', function(d) { d3.select(this).remove() count++; if (count == data.length) { count = 0; lines(); } }) })() })() 
 body { padding: 1rem; } svg { background-color: silver; stroke: black; stroke-width: 1; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <div id="sketches"></div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM