in packages/graph-explorer/src/components/Graph/hooks/useRunLayout.ts [23:91]
function useUpdateLayout({
cy,
layout,
additionalLayoutsConfig,
onLayoutUpdated,
useAnimation,
graphStructureVersion,
mounted,
}: UseUpdateLayout) {
const previousNodesRef = useRef(new Set<string>());
const previousLayoutRef = useRef(layout);
const previousGraphStructureVersionRef = useRef(graphStructureVersion);
useEffect(() => {
// Ensure Cytoscape is mounted and skip the first graph structure version
if (!cy || !layout || !mounted || graphStructureVersion === 0) {
return;
}
// Only lock the previous nodes if the layout is the same, the graph has been updated, and there is at least one node.
const shouldLock =
previousLayoutRef.current === layout &&
previousGraphStructureVersionRef.current !== graphStructureVersion &&
previousNodesRef.current.size > 0;
// Reduce the number of iterations over the node collection
const nodesInGraph = cy.nodes();
const nodesToLock = shouldLock
? nodesInGraph.filter(cyNode =>
previousNodesRef.current.has(cyNode.data().id)
)
: [];
if (shouldLock) {
// Lock all the previous nodes
cy.batch(() => {
nodesToLock.forEach(node => {
node.lock();
});
});
}
// Perform the layout for any new nodes
runLayout(cy, layout, additionalLayoutsConfig, useAnimation);
onLayoutUpdated?.(cy, layout);
if (shouldLock) {
// Unlock all the previous nodes
cy.batch(() => {
nodesToLock.forEach(node => {
node.unlock();
});
});
}
// Update the refs for previous state so we can compare the next time the graph is updated
previousLayoutRef.current = layout;
previousNodesRef.current = new Set(nodesInGraph.map(node => node.id()));
previousGraphStructureVersionRef.current = graphStructureVersion;
}, [
cy,
layout,
additionalLayoutsConfig,
useAnimation,
onLayoutUpdated,
graphStructureVersion,
mounted,
]);
}