1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add initial core:layout-flow action

This commit is contained in:
Nick O'Leary 2019-08-13 20:42:54 +01:00
parent 17d3a5840d
commit 0281a9c3d0
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9

View File

@ -108,6 +108,168 @@ RED.view.tools = (function() {
} }
} }
function layoutFlow() {
var selection = RED.view.selection();
if (!selection.nodes || selection.nodes.length !== 1) {
RED.notify("Select exactly one node");
return;
}
var ns = RED.nodes.getAllFlowNodes(selection.nodes[0]);
// Find Input node
var nodes = {};
var minRank = 0;
var stack = [];
var candidateInputs = {};
var candidateOutputs = {};
ns.forEach(function(n) {
candidateInputs[n.id] = n;
candidateOutputs[n.id] = n;
nodes[n.id] = {
n:n,
i:[],
o:[],
d:-1, // depth from start
r:-1, // rank order at that depth
downstream: 0
}
});
RED.nodes.eachLink(function(link) {
if (nodes[link.source.id] || nodes[link.target.id]) {
nodes[link.source.id].o.push(link.target.id);
nodes[link.target.id].i.push(link.source.id);
delete candidateInputs[link.target.id]
delete candidateOutputs[link.source.id]
}
})
var inputs = Object.keys(candidateInputs);
var outputs = Object.keys(candidateOutputs);
if (inputs.length > 1) {
RED.notify("Multiple start points - bailing")
return;
}
if (outputs.length === 0) {
RED.notify("No outputs - is this a big loop? Bailing");
return;
}
function applyDepth(id,d) {
if (nodes[id].d < d) {
nodes[id].d = d;
nodes[id].o.forEach(function(nid) {
applyDepth(nid,d+1);
})
}
}
applyDepth(inputs[0],0)
function calculateDownstream(id,downstream) {
nodes[id].downstream += downstream;
nodes[id].i.forEach(function(nid) {
calculateDownstream(nid, nodes[id].downstream+1);
})
}
outputs.forEach(function(id) {
calculateDownstream(id, 0)
})
var ranks = {};
function rankNodes(node) {
if (node.r === -1) {
ranks[node.d] = ranks[node.d] || [];
node.r = ranks[node.d].length;
ranks[node.d].push(node);
node.o.sort(function(a,b) {
return nodes[b].downstream - nodes[a].downstream
})
node.o.forEach(function(nid) {
rankNodes(nodes[nid])
})
}
}
rankNodes(nodes[inputs[0]]);
function shuffleRanks(node) {
var pushed = false;
if (node.o.length > 1) {
var outputs = node.o.slice(0);
outputs.sort(function(a,b) {
if (nodes[a].d === nodes[b].d) {
return nodes[a].r - nodes[b].r;
} else {
return nodes[b].d - nodes[a].d;
}
})
// outputs.forEach(function(o,i) { console.log(" ",i," + "+nodes[o].n.type," d:",nodes[o].d," r:",nodes[o].r)});
var rank = nodes[outputs[0]].r;
var depth = nodes[outputs[0]].d;
for (var i=1;i<outputs.length;i++) {
// console.log(outputs[i]);
var n = nodes[outputs[i]];
if (n.d !== depth && n.r === rank) {
// need to move n down one.
var r = n.r;
ns.forEach(function(_n) {
var nn = nodes[_n.id];
if (nn.d >= n.d && nn.d < depth && nn.r >= r) {
pushed = true;
nn.r++;
}
})
}
depth = n.d;
rank = n.r;
}
}
node.o.forEach(function(n) {
pushed = pushed || shuffleRanks(nodes[n])
})
return pushed;
}
var shuffle = function() {
if (shuffleRanks(nodes[inputs[0]])) {
shuffle();
}
}
shuffle();
var x = nodes[inputs[0]].n.x;
var y = nodes[inputs[0]].n.y;
var changedNodes = [];
ns.forEach(function(n) {
var d = nodes[n.id].d;
var r = nodes[n.id].r;
changedNodes.push({
n:n,
ox: n.x,
oy: n.y,
moved: n.moved
});
n.x = x + d*200;
n.y = y + r*50;
n.dirty = true;
// n.dirtyStatus = true;
// n.status = {
// text:"d"+d+" : r"+r+" : ds"+nodes[n.id].downstream
// }
});
if (changedNodes.length > 0) {
RED.history.push({t:"move",nodes:changedNodes,dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
RED.view.redraw(true);
}
}
return { return {
init: function() { init: function() {
RED.actions.add("core:align-selection-to-grid", alignToGrid); RED.actions.add("core:align-selection-to-grid", alignToGrid);
@ -121,6 +283,8 @@ RED.view.tools = (function() {
RED.actions.add("core:step-selection-right", function() { moveSelection(RED.view.gridSize(),0);}); RED.actions.add("core:step-selection-right", function() { moveSelection(RED.view.gridSize(),0);});
RED.actions.add("core:step-selection-down", function() { moveSelection(0,RED.view.gridSize());}); RED.actions.add("core:step-selection-down", function() { moveSelection(0,RED.view.gridSize());});
RED.actions.add("core:step-selection-left", function() { moveSelection(-RED.view.gridSize(),0);}); RED.actions.add("core:step-selection-left", function() { moveSelection(-RED.view.gridSize(),0);});
RED.actions.add("core:layout-flow", function() { layoutFlow() })
}, },
/** /**
* Aligns all selected nodes to the current grid * Aligns all selected nodes to the current grid