-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from pyiron/automatic_positioning
Automatic positioning
- Loading branch information
Showing
3 changed files
with
152 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { useEffect } from 'react'; | ||
import ELK from 'elkjs/lib/elk.bundled.js'; | ||
import { useNodesInitialized, useReactFlow } from '@xyflow/react'; | ||
// import { saveAs } from 'file-saver'; | ||
|
||
|
||
// elk layouting options can be found here: | ||
// https://www.eclipse.org/elk/reference/algorithms/org-eclipse-elk-layered.html | ||
|
||
|
||
// uses elkjs to give each node a layouted position | ||
export const getLayoutedNodes2 = async (nodes, edges) => { | ||
const layoutOptions = { | ||
'elk.algorithm': 'layered', | ||
'elk.direction': 'RIGHT', | ||
'elk.layered.spacing.edgeNodeBetweenLayers': '40', | ||
'elk.spacing.nodeNode': '40', | ||
'elk.layered.nodePlacement.strategy': 'SIMPLE', | ||
}; | ||
|
||
console.log("nodes layout: ", nodes); | ||
console.log("edges layout: ", edges); | ||
const elk = new ELK(); | ||
|
||
const graph = { | ||
id: 'root', | ||
layoutOptions, | ||
children: nodes.map((n) => { | ||
const targetPorts = n.data.target_labels.map((label) => ({ | ||
id: `${n.id}_in_${label}`, | ||
|
||
// ⚠️ it's important to let elk know on which side the port is | ||
// in this example targets are on the left (WEST) and sources on the right (EAST) | ||
properties: { | ||
side: 'WEST', | ||
}, | ||
})); | ||
|
||
const sourcePorts = n.data.source_labels.map((label) => ({ | ||
id: `${n.id}_out_${label}`, | ||
properties: { | ||
side: 'EAST', | ||
}, | ||
})); | ||
|
||
return { | ||
id: n.id, | ||
width: n.style.width_unitless ?? 240, | ||
height: n.style.height_unitless ?? 100, | ||
// ⚠️ we need to tell elk that the ports are fixed, in order to reduce edge crossings | ||
properties: { | ||
'org.eclipse.elk.portConstraints': 'FIXED_ORDER', | ||
// 'org.eclipse.elk.layered.portSortingStrategy': 'UP_DOWN', | ||
}, | ||
// we are also passing the id, so we can also handle edges without a sourceHandle or targetHandle option | ||
ports: [ ...targetPorts.reverse(), ...sourcePorts.reverse()], | ||
}; | ||
}), | ||
edges: edges.map((e) => ({ | ||
id: e.id, | ||
sources: [`${e.source}_out_${e.sourceHandle}`], | ||
targets: [`${e.target}_in_${e.targetHandle}`], | ||
})), | ||
}; | ||
|
||
// const blob = new Blob([JSON.stringify(graph)], {type: "text/plain;charset=utf-8"}); | ||
// saveAs(blob, 'output.json'); | ||
|
||
console.log("Graph: ", graph); | ||
const layoutedGraph = await elk.layout(graph); | ||
console.log("layoutedGraph: ", layoutedGraph); | ||
|
||
const layoutedNodes = nodes.map((node) => { | ||
const layoutedNode = layoutedGraph.children?.find( | ||
(lgNode) => lgNode.id === node.id, | ||
); | ||
|
||
return { | ||
...node, | ||
position: { | ||
x: layoutedNode?.x ?? 0, | ||
y: layoutedNode?.y ?? 0, | ||
}, | ||
}; | ||
}); | ||
console.log("layoutedGraphNodes: ", layoutedNodes); | ||
|
||
return layoutedNodes; | ||
}; | ||
|
||
export default function useLayoutNodes() { | ||
const nodesInitialized = useNodesInitialized(); | ||
const { getNodes, getEdges, setNodes, fitView } = useReactFlow(); | ||
|
||
useEffect(() => { | ||
if (nodesInitialized) { | ||
const layoutNodes = async () => { | ||
const layoutedNodes = await getLayoutedNodes( | ||
getNodes(), | ||
getEdges(), | ||
); | ||
|
||
setNodes(layoutedNodes); | ||
setTimeout(() => fitView(), 0); | ||
}; | ||
|
||
layoutNodes(); | ||
} | ||
}, [nodesInitialized, getNodes, getEdges, setNodes, fitView]); | ||
|
||
return null; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters