Pirs Pirs - 11 months ago 98
Javascript Question

How can I simulate gravity correctly in a bounded area?

I'm trying to do a container with balls inside, attracted to the floor like gravity. I'm close to doing it well but the balls eventually melt into each other then don't preserve their visibility.

See the demo here

I think the problem comes from the gravity function itself because the radius of each node isn't into account:

var gravity = function() {
return function(d) {
d.y += (d.cy - d.y);
d.x += (d.cx - d.x);
};
}


or from the bounding function in the simulation animation (tick), for the same problem above

d3.selectAll("circle.node")
.attr("cx", function(d,i){ return Math.max(radius, Math.min(width - radius, d.x)); })
.attr("cy", function(d,i){ return Math.max(radius, Math.min(height - radius, d.y)); });


How can I separate each ball distinctly in this case?

Edit: i found the solution i ll share it soon

Answer Source

Ok, i finally read the docs and understood the problem !

See the demo here

All is about the collide between each node, to integrate it correctly in the forceSimulation, and the bound calculation in the tick function:

...


  // Change values below to modify the physic
  var simulation = d3.forceSimulation()
    .velocityDecay(0.3)
    .force("y", d3.forceY(height).strength(.035)) // gravity at bottom
    .force("collide", d3.forceCollide().radius(radius).strength(1.5).iterations(10))
    .nodes(nodes)
    .on('tick', tick);

  function tick() {
    // bound
    node.attr('cx', function(d) { return d.x = Math.max(radius, Math.min(width - radius, d.x)); })
        .attr('cy', function(d) { return d.y = Math.max(radius, Math.min(height - radius, d.y)); });
  }
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download