score:1

Accepted answer

There are 3 problems:

  1. For positioning the circles near their original position, the x and y initial positions need to be specified in the data passed to simulation.nodes() call.
  2. When doing a force simulation, you need to provide the selection to be simulated in the on tick callback (see node in the on('tick') callback function).
  3. The simulation needs to use the previous d.x and d.y values as calculated by the simulation

Relevant code snippets below

// 1. Add x and y (cx, cy) to each row (circle) in data 
const citiesWithCenter = cities.map(c => ({
  ...c,
  x: projection.latLngToLayerPoint([c.latitude, c.longitude]).x,
  y: projection.latLngToLayerPoint([c.latitude, c.longitude]).y,
}))
// citiesWithCenter will be passed to selectAll('circle').data()
// 2. node selection you forgot
 const node = selection
        .selectAll('circle')
        .data(citiesWithcenter)
        .enter()
        .append('circle')
...
// let used in simulation
 simulationforce.nodes(citiesWithcenter).on('tick', function (d) {
   node
     .attr('cx', function (d) {
            // 3. use previously computed x value 
            // on the first tick run, the values in citiesWithCenter is used
            return d.x
          })
     .attr('cy', function (d) {
            // 3. use previously computed y value 
            // on the first tick run, the values in citiesWithCenter is used
            return d.y
          })
})

Full working demo here: https://jsfiddle.net/b2Lhfuw5/


Related Query

More Query from same tag