-->

d3-force update radius of forceCollide after initi

2019-02-18 10:44发布

问题:

This question is a follow-up on a previous one titled "D3-Force updating parameters after initializing graph" (D3-Force updating parameters after initializing graph) and that @altocumulus answered.

I am trying to update the simulation forces after modifying the radius of some nodes. However, when I call on forceCollide to account for the changes it does not work.

The graph first initiates correctly, using forceCollide and a function to have the force correspond with the radius:

var forceCollide = d3.forceCollide()
.radius(function(d){return d.radius;})
.iterations(2)
.strength(0.95);

var simulation = d3.forceSimulation()
.velocityDecay(velocityDecay)
.force("collide", forceCollide);

I then modify the d.radius object and want forceCollide to reflect the changes. However, when I call on the forceCollide again it does not work:

forceCollide.radius(function(d){
d.radius;})

Any thoughts on why this is happening?

回答1:

This will not actually update the radius. You are just re-setting the callback used to determine the radius, which doesn't even change compared to what it was before. Even if it did change, this would not trigger your update, because the radii won't be re-evaluated based on your updated data.

When updating the distance callback of the link force, the force itself will get initialized. A look at the source shows a call to initializeDistance():

force.distance = function(_) {
  return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), initializeDistance(), force) : distance;
};

The same holds true for many other updates of other forces' parameters.

Looking at the source of the collide force, however, one notices that there is no initialization invoked:

force.radius = function(_) {
  return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), force) : radius;
};

Since your callback doesn't change you won't need to call forceCollide.radius() again. Instead you need to call

forceCollide.initialize(simulation.nodes());

This will re-evaluate the radii based on your updated data.