vasturiano / force-graph

Force-directed graph rendered on HTML5 canvas
https://vasturiano.github.io/force-graph/example/directional-links-particles/
MIT License
1.59k stars 248 forks source link

DAG-Style force-graph: Add (Y-Axis) Space Between Children Of Same Level #222

Open manunamz opened 3 years ago

manunamz commented 3 years ago

Is your feature request related to a problem? Please describe. If there are text labels they are difficult to read when using dag-style force-graphs.

Describe the solution you'd like I'm not entirely sure what the best way to accomplish this is, but allowing for some method of incremental or pseudo-random length changes per level would go a long way for readability (similar to d3's built-in hierarchy graph-type):

With the DAG-style force-graph:

Screen Shot 2021-08-18 at 11 37 54 AM

With d3's built-in hierarchy graph:

Screen Shot 2021-08-18 at 11 37 49 AM

One way to implement this would be to have dagLevelDistance (or a new attr) accept a function rather than a number as input, so as to compute desired level lengths.

Describe alternatives you've considered It might be possible to achieve this by altering the y value of nodes in nodeCanvasObject...But that has not worked well for me (nodes oscillated for a long time before settling).

Another possibility is to use linkCurvature to add space between nodes. But I have not tried this myself: I want to keep my lines straight for artistic reasons.

Besides, with dagLevelDistance already there, it would be nice to handle that logic with that attribute.

PS Thanks for flattening the input data arrays. :D

jrmartin commented 3 years ago

Hi @manunamz , did you have good luck fixing this? I'm facing a similar issue but haven't gotten the forces quite right yet.

manunamz commented 3 years ago

Hi @jrmartin, I have not, but I am planning on revisiting this at some point.

jrmartin commented 3 years ago

Thanks for replying @manunamz :) I gave up playing with the library forces, and started calculating the x and y position of each node instead. It's the only way I got it to work.

manunamz commented 3 years ago

A month later... 😂 (I will get my notifications straight someday)

Is that to say you're fiddling with d3 directly now? Or are you setting the x/y with force-graph?

jrmartin commented 3 years ago

I'm setting the x/y positions directly with force-graph.

Before passing the nodes to the force-graph, I calculate the x and y position for each node and store them inside the node under custom properties. E.G.

node.xPos = 100;
node.yPos = 100;

I then use the force-graph 'nodeVal' method to assign the node's x and y position.

This is how I assigned them the node x and y positions: nodeVal = { node => { node.fx = node.xPos; node.fy = node.yPos; }}