Search code examples
d3.jsd3-force-directed

How to get coordinates(cx, cy) of circles after d3 force collision?


I'm trying to get coordinates of circles (cx, cy) after using d3-force collision, but I still got original positions. Are there any ways for getting translated(after collision check) coordinates of circles?

Below is just summary of code.


let data = [
{ 'x': 100, 'y': 100, 'radius': 10, cluster: 4 },
{ 'x': 100, 'y': 100, 'radius': 6, cluster: 3 },
{ 'x': 50, 'y': 200, 'radius': 10, cluster: 2 },
{ 'x': 350, 'y': 200, 'radius': 10, cluster: 2 },
{ 'x': 100, 'y': 300, 'radius': 20, cluster: 3 },
{ 'x': 100, 'y': 300, 'radius': 25, cluster: 1 },
{ 'x': 100, 'y': 300, 'radius': 33, cluster: 2 }];

var collisionForce = d3.forceCollide((d) => d.radius).strength(1).iterations(100);

var simulation = d3.forceSimulation(data).alphaDecay(0.01).force('collisionForce', collisionForce)
          .force('center', d3.forceCenter(width / 2, height / 2));

 var node = svg.selectAll('circle').data(data)
          .enter().append('circle')
          .attr('r', function (d) {
            return d.radius;
          }).attr('cx', function (d) {
            return d.x;
          }).attr('cy', function (d) {
            return d.y;
          })
          .attr('cluster', d => d.cluster)
          .attr('fill', d => that.palette[d.cluster]);

      function ticked() {
        node.attr('cx', function (d) {
          return d.x;
        })
            .attr('cy', function (d) {
              return d.y;
            });
      }

simulation.on('tick', ticked);


Solution

  • You can listen to the end event on a simulation, and then access the final coordinates for the circles by changing the last line of your code to this:

    simulation
      .on('tick', ticked)
      .on('end', () => {
        d3.selectAll('circle').each(function () {
          const thisD3 = d3.select(this)
          console.log(thisD3.attr('cx'), thisD3.attr('cy'))
        })
      }) 
    

    According to my knowledge, the array passed to d3.forceSimulation edits the array in place, so you could also access the x and y coordinates directly in that array. The key in either case is do it when the simualtion triggers the end event.

    Hope this helps!