fix(graph): track node positions in real-time via nodeCanvasObject instead of stale snapshot
This commit is contained in:
@@ -183,14 +183,10 @@ function GraphPage() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Snapshot every simulated node's position once the force simulation settles.
|
// Track all node positions every render frame via nodeCanvasObject (which
|
||||||
const snapshotPositions = useCallback(() => {
|
// receives each node with its simulated x/y coords). This replaces the old
|
||||||
const nodes = graphRef.current?.graphData()?.nodes;
|
// snapshotPositions callback that relied on graphRef.graphData(), which is not
|
||||||
if (!nodes) return;
|
// exposed by react-force-graph-2d's ref.
|
||||||
for (const node of nodes) {
|
|
||||||
trackNodePosition(node);
|
|
||||||
}
|
|
||||||
}, [trackNodePosition]);
|
|
||||||
|
|
||||||
const handleSearch = useCallback(() => {
|
const handleSearch = useCallback(() => {
|
||||||
if (!search.trim() || !graphRef.current) return;
|
if (!search.trim() || !graphRef.current) return;
|
||||||
@@ -235,6 +231,7 @@ function GraphPage() {
|
|||||||
// Custom node renderer
|
// Custom node renderer
|
||||||
const nodeCanvasObject = useCallback(
|
const nodeCanvasObject = useCallback(
|
||||||
(node: any, ctx: CanvasRenderingContext2D, globalScale: number) => {
|
(node: any, ctx: CanvasRenderingContext2D, globalScale: number) => {
|
||||||
|
trackNodePosition(node);
|
||||||
const isHighlighted = highlightNodes.size === 0 || highlightNodes.has(node.id);
|
const isHighlighted = highlightNodes.size === 0 || highlightNodes.has(node.id);
|
||||||
const isHovered = hoveredNode?.id === node.id;
|
const isHovered = hoveredNode?.id === node.id;
|
||||||
const label = node.label || "";
|
const label = node.label || "";
|
||||||
@@ -259,7 +256,7 @@ function GraphPage() {
|
|||||||
const displayLabel = label.length > 15 ? label.slice(0, 15) + "…" : label;
|
const displayLabel = label.length > 15 ? label.slice(0, 15) + "…" : label;
|
||||||
ctx.fillText(displayLabel, node.x, node.y + radius + 2);
|
ctx.fillText(displayLabel, node.x, node.y + radius + 2);
|
||||||
},
|
},
|
||||||
[highlightNodes, hoveredNode]
|
[highlightNodes, hoveredNode, trackNodePosition]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Custom link renderer with arrows
|
// Custom link renderer with arrows
|
||||||
@@ -384,7 +381,6 @@ function GraphPage() {
|
|||||||
onNodeClick={handleNodeClick}
|
onNodeClick={handleNodeClick}
|
||||||
onNodeHover={handleNodeHover}
|
onNodeHover={handleNodeHover}
|
||||||
onNodeDrag={trackNodePosition}
|
onNodeDrag={trackNodePosition}
|
||||||
onEngineStop={snapshotPositions}
|
|
||||||
nodeRelSize={6}
|
nodeRelSize={6}
|
||||||
d3AlphaDecay={0.02}
|
d3AlphaDecay={0.02}
|
||||||
d3VelocityDecay={0.3}
|
d3VelocityDecay={0.3}
|
||||||
|
|||||||
Reference in New Issue
Block a user