I have been trying to achieve a feature in reactflow such that when a node is selected from the toolbar, it will move along with the cursor to a position where is it going to be dropped. The problem I have here is that, when the cursor is moving, the selected/picked node does not align perfectly with it. It either lags or leads the cursor.
Here is the function I implemented to listened to mouse and event and update the node’s position to match the position of the cursor.
const onMoveCursor = useCallback(
// if a node is selected, move it around with the cursor
(event: React.MouseEvent) => {
if (pickedNode && nodeType) {
setNodes((prevNodes) => {
return prevNodes.map((nd) => {
if (nd.id === pickedNode?.id) {
updateNodeInternals(nd.id);
return { ...nd, position: { x: event.clientX - 200, y: event.clientY - 50 } };
}
return nd;
});
});
}
}, // eslint-disable-next-line react-hooks/exhaustive-deps
[pickedNode, nodeType]
);
<ReactFlow
nodeTypes={nodeTypes}
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onReconnect={onReconnect}
onMouseMove={onMoveCursor}
onClick={onDrop}
onConnectStart={onConnectStart}
onInit={setRfInstance}
connectionMode={"loose" as ConnectionMode}
defaultEdgeOptions={defaultEdgeOptions}
onNodeDrag={onNodeDrag}
>
{showTips && <QuickTips />}
<Controls
position="bottom-right"
onInteractiveChange={(prev) => {
dispatch({ type: "SET_READ_ONLY", payload: !prev });
}}
/>
<Background variant={backgroundType} gap={12} />
<ElementPanel />
</ReactFlow>
The function that is responsible for picking a node from the toolbar when a node tool is clicked is:
const handleClick = () => {
if (type === "node") {
// set the node type
dispatch({ payload: name as nodeTypes, type: "SET_NODE_TYPE" });
// add the node to workspace
const nodeID = `node${nodes.length + 1}`;
const node: Node = {
id: nodeID,
data: { label: { color: name === "text" || name === "link" ? "black" : "white", text: name } },
position: { x: 1, y: 1 },
type: name,
};
// @ts-ignore
setNodes([...nodes, node]);
// pick the new node
dispatch({ type: "SET_PICKED_NODE", payload: node });
} else if (type === "edge") {
dispatch({ payload: name as edgeTypes, type: "SET_EDGE_TYPE" });
}
};