After a few clicks, the animation freezes, why?

I have the following code that I took and changed from here

Here is my jsfiddle in action

I'm currently developing interaction with a user who needs these bubbles, exactly 5 bubbles that stretch to the center of the screen. The fact is, I know how many times the user clicks on each of these bubbles. I noticed that at some point the bubbles continue to grow, but the collision between them will stop working.

Here you can see the code that will change:

var width = 500, height = 500, padding = 1.5, // separation between same-color circles clusterPadding = 4, // separation between different-color circles maxRadius = 40; var n = 5, // total number of circles m = 1; // number of distinct clusters var color = d3.scale.category10() .domain(d3.range(m)); // The largest node for each cluster. var clusters = new Array(m); var nodes = d3.range(n).map(function() { var i = Math.floor(Math.random() * m), //r = Math.sqrt((i + 1) / m * -Math.log(Math.random())) * maxRadius, r = maxRadius, d = {cluster: i, radius: r}; if (!clusters[i] || (r > clusters[i].radius)) clusters[i] = d; return d; }); // Use the pack layout to initialize node positions. d3.layout.pack() .sort(null) .size([width, height]) .children(function(d) { return d.values; }) .value(function(d) { return d.radius * d.radius; }) .nodes({values: d3.nest() .key(function(d) { return d.cluster; }) .entries(nodes)}); var force = d3.layout.force() .nodes(nodes) .size([width, height]) .gravity(.02) .charge(0) .on("tick", tick) .start(); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var node = svg.selectAll("circle") .data(nodes) .enter().append("circle") .style("fill", function(d) { return color(d.cluster); }) .on("click", function(d) { d.radius *= 1.1; d3.select(this).attr("r", d.radius); }) .call(force.drag); node.transition() .duration(750) .delay(function(d, i) { return i * 5; }) .attrTween("r", function(d) { var i = d3.interpolate(0, d.radius); return function(t) { return d.radius = i(t); }; }); function tick(e) { node .each(cluster(10 * e.alpha * e.alpha)) .each(collide(.5)) .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); } // Move d to be adjacent to the cluster node. function cluster(alpha) { return function(d) { var cluster = clusters[d.cluster]; if (cluster === d) return; var x = dx - cluster.x, y = dy - cluster.y, l = Math.sqrt(x * x + y * y), r = d.radius + cluster.radius; if (l != r) { l = (l - r) / l * alpha; dx -= x *= l; dy -= y *= l; cluster.x += x; cluster.y += y; } }; } // Resolves collisions between d and all other circles. function collide(alpha) { var quadtree = d3.geom.quadtree(nodes); return function(d) { var r = d.radius + maxRadius + Math.max(padding, clusterPadding), nx1 = dx - r, nx2 = dx + r, ny1 = dy - r, ny2 = dy + r; quadtree.visit(function(quad, x1, y1, x2, y2) { if (quad.point && (quad.point !== d)) { var x = dx - quad.point.x, y = dy - quad.point.y, l = Math.sqrt(x * x + y * y), r = d.radius + quad.point.radius + (d.cluster === quad.point.cluster ? padding : clusterPadding); if (l < r) { l = (l - r) / l * alpha; dx -= x *= l; dy -= y *= l; quad.point.x += x; quad.point.y += y; } } return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; }); }; } 
+5
source share
1 answer

This behavior that you described is happening because force modeling is complete. So, the easiest solution is to reheat the force with each press:

 .on("click", function(d) { d.radius *= 1.1; d3.select(this).attr("r", d.radius); force.resume(); }) 

Here force.resume() :

Sets the cooling parameter alpha 0.1. This method sets the internal alpha parameter to 0.1, and then restarts the timer. As a rule, you do not need to directly access this method; It starts automatically at the beginning. It is also automatically called by drag and drop during drag gestures.

Here is your updated script: https://jsfiddle.net/usb7nhfm/

+2
source

Source: https://habr.com/ru/post/1259281/


All Articles