I am trying to get d3.forceRadial() to distribute nodes hierarchically around their respective parents, but when I set the the x and y parameters on the force all the nodes shoot off towards the bottom right corner and beyond with x and y values ending up in the tenthousands..
My code looks like this:
let simulation = d3.forceSimulation()
.force('radial', d3.forceRadial((d) => (d.distance * 100))
.x((d) => ((d.parent && !isNaN(d.parent.x)) ? d.parent.x + d.parent.vx : 0))
.y((d) => ((d.parent && !isNaN(d.parent.y)) ? d.parent.y + d.parent.vy : 0))
.strength(3))
.force('link', d3.forceLink().id((d) => (d.entity_id)).strength(0))
.nodes(data.nodes);
Where parent is a reference to the parent node and d.distance is the number of steps away from the root node. I have tried setting all node's x and y to 0 beforehand but to no avail..
Unfortunately, in the current version (4.13.0 at the time of the writing), d3.forceRadial
does not accept a function for the x()
and y()
methods, despite the fact that it does accept a function for the radius()
method.
We can see this inspecting the source code.
This is the code for radius()
:
force.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ :
constant(+_), initialize(), force) : radius;
};
As you can see, it accepts a function.
But this is the code for x()
and y()
:
force.x = function(_) {
return arguments.length ? (x = +_, force) : x;
};
force.y = function(_) {
return arguments.length ? (y = +_, force) : y;
};
As you can see, it does not accept a function.
You can also see that the API only talks about numbers, not functions. Regarding radial.x
:
If x is specified, sets the x-coordinate of the circle center to the specified number and returns this force. (emphasis mine)
The same goes for radial.y
.