In answer to a question on the d3 Slack channel #help
See the more complex version, with transitions for each step, at Merge Sites.
Built with blockbuilder.org
| license: mit |
In answer to a question on the d3 Slack channel #help
See the more complex version, with transitions for each step, at Merge Sites.
Built with blockbuilder.org
| <!DOCTYPE html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <style> | |
| body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
| </style> | |
| </head> | |
| <body> | |
| <script> | |
| // Feel free to change or delete any of the code you see in this editor! | |
| var svg = d3.select("body").append("svg") | |
| .attr("width", 960) | |
| .attr("height", 500) | |
| var data = d3.range(300).map(d => { | |
| return { | |
| x: 100 + 760 * Math.random(), | |
| y: 100 + 300 * Math.random(), | |
| w: 300 * Math.random(), | |
| } | |
| }) | |
| function merge() { | |
| var merged = 0; | |
| data.forEach((d,i) => { | |
| if (d.w == 0) return; | |
| d.r = Math.sqrt(d.w); | |
| data.slice(0, i).forEach((e,j) => { | |
| if (e.w == 0) return; | |
| var dx = e.x - d.x, | |
| dy = e.y - d.y, | |
| dist2 = dx * dx + dy * dy, | |
| r2 = (d.r + e.r) * (d.r + e.r); | |
| if (dist2 < r2) { | |
| merged ++; | |
| if (d.w >= e.w) { | |
| d.x += dx * e.w / (d.w + e.w); | |
| d.y += dy * e.w / (d.w + e.w); | |
| d.w += e.w; | |
| e.w = 0; | |
| } else { | |
| e.x -= dx * d.w / (d.w + e.w); | |
| e.y -= dy * d.w / (d.w + e.w); | |
| e.w += d.w; | |
| d.w = 0; | |
| } | |
| } | |
| }); | |
| }); | |
| return merged; | |
| } | |
| var circles = svg.selectAll('circle') | |
| .data(data) | |
| .enter() | |
| .append('circle') | |
| .attr("fill", "#3498f7") | |
| .attr("opacity", 0.5) | |
| .attr('r', d => Math.sqrt(d.w)) | |
| .attr('cx', d => d.x) | |
| .attr('cy', d => d.y); | |
| while(merge()); | |
| circles.transition() | |
| .duration(2000) | |
| .attr('r', d => Math.sqrt(d.w)) | |
| .attr('cx', d => d.x) | |
| .attr('cy', d => d.y); | |
| circles.filter(d => !d.w) | |
| .transition() | |
| .duration(2000) | |
| .attr('opacity', 0) | |
| .remove(); | |
| </script> | |
| </body> |