Hello everyone!
First i want to thanks @BartButenaers for bringing me in javascript development several years ago
Working on a javascript project that will generate a flows.json file from a config file.... Don't ask me why
Managed to append subflows files, create nodes, connect them, put them in one flow, all of that based on one file.
Now i can load up the flow, but all of the elements are with x,y coordinates of 100
But they are connected as i want (defined the nodes, and connections in the original config file).
Now the part where i ran out of ideas is... How can i position nodes in the most efficient (readable way).
Essentially the desired input itself is a flow.json file, searched npm packages but could not find anything useful
The only idea i had in mind is to filter out the flows.json to have a variable that will essentially look something like this:
{
injectnodeId:{ changenodeId : { debugnodeId}}
}
And from here create a function that will assign x,y for each of the node.
But again this will break if we would have multiple flows...
Well, that is a whole entire area of Math in its own right. It is an incredibly complex task. Have fun doing the research on the math principles of graph theory.
Honestly, the application of the x/y values is trivial. It is the working out of what they need to be for each node that is complex. As you will be aware, Node-RED itself does not really do that, it just has a stab at the x/y of the next node.
You could potentially simplify the calculations by setting max x bounds, making an assumption about the size of each node and calculating a suitable x/y grid of coordinates and then apply those to your flow. But that has some serious limitations and assumptions. That the nodes are a particular size, that you don't mind the wires crossing back to x=0 when you reach max x, that all of your nodes were added in a logical sequence. And, of course, that still doesn't deal with multiple flow fragments.
Fortunately, you may not have to understand much graph theory to get started. The flows.json file tells you which nodes are connected to one another, and that information is enough to start up an algorithm like this:
There are JavaScript libraries (for example) that implement variations on this method, and will return a set of node positions that you can push back into the flow file.
All this is easier said than done, and I've never done it, but I think this should involve more programming than calculation.
That is quite a long time ago. I assume you have become meanwhile a true Javascript magician
You might also have a look at this old pull-request:
It was an experiment to auto layout the nodes in a flow. As you can see it has never been merged (very unfortunately...), but you might have a look at the code how they did it...
I've always wanted to implement a D3 "auto-layout" feature for node-red, so I'm glad you reminded me!
As @drmibell suggested, the simplest way to implement this is using a force-directed graph... essentially, each node tries to get away from the others, but is tethered to those nodes that are linked. Obviously, this would not use the x.y coords to position the nodes, but it would make sense to use them for "relative" positioning between linked nodes.
That being said, there are endless ways to implement the layout -- for instance, some people want the flow to be left->right, while other want top->bottom. Either way, the goal would be to minimize the length of each link (arrow) which effectively ends up presenting a "readable" version of the flow.
If only I was retired and could spend my days working on cool stuff like this...
__
Steve
I don't believe that would work well for Node-RED since all nodes have the entry at the left and exits at the right. Force-directed graphs don't use that assumption I don't believe.
True, but not as much of an issue as you might think. The flow.json file specifies just one set of (x,y) coordinates for each node, presumably the position of the center of the node. The editor handles adjustments related to the size of the label, number of outputs, routing of wires, etc. (Actually, changes can cause nodes to overlap, requiring manual adjustment .) A placement algorithm (force-directed or other) only needs to place the center of the node as if all connections were made at that point, and the editor should handle the rest, just as when a flow is loaded from a file.
Yes, the nodes x and y are actually the center of the node. I think some placement algorithms should just have the rules for "sizing the node" based on number of outputs or based on the node name length.
What i did...
Filtered out the flows.json file to get nodes with x & y properties on Flow 1 only (subflows will be created by a user, so no need to format them).
Sorted the filtered node by number of output wires going out of the node (with most outputs first).
Defined node sizes, function to increase height and width based on number of outputs or node.name length ( i know that some of the nodes will display URL such as httpin node, mqtt nodes, influxdb node etc...)
Then used dagre to lay out the nodes as a directed graph (left to right, because less wires, more power )
Also , i set edges (wires) (based on the connections), defined the margins 20x20 (so no node is cropped by the top or left border)
Created the layout, mapped back the dagre-s node x & y output back to nodes in flow.json, and magically it works!
Tested with only this flow, because as i mentioned, i am converting a config file to flows file to help with scaling of fleet of RPI running node-red
Thanks for pointing me to force-directed graphs!
EDIT :
Here is another image of its layout capabilities (just testing)
Could this also be adapted into a feature that allows you to set a flow tab to "auto-layout" on an individual basis in the Node-RED editor? Often I'm very pick about how my nodes are positioned, but when prototyping a quick project it might be nice to have. It could also encourage more readable flows and screenshots of Node-RED posted online, if integrated into the "export nodes" dialog to have an option to select auto-layout before copy/pasting a quick flow online.
Rather than bloating Node-RED itself. How about having an extended plugin module instead? Then it could also potentially be expanded for different layout types if needed. A side-panel to control the layout could also be developed over time that could adjust things like grid sizing.
Will need more work to integrate this in a node-red, but unfortunately needed this for another project, and can't work on this...
But for anyone interested here is the file: https://pastebin.com/TJRFD3mg