mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			4456-fix-g
			...
			auto-layou
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 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 { | ||||
|         init: function() { | ||||
|             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-down", function() { moveSelection(0,RED.view.gridSize());}); | ||||
|             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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user