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:
parent
17d3a5840d
commit
0281a9c3d0
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user