From 044095bda1f43c00fcf52986cf8834038c0d2f1b Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 11 Jul 2022 16:13:33 +0200 Subject: [PATCH] fix(onNodeDrag): show correct position closes #2246 --- example/src/Basic/index.tsx | 2 ++ example/src/Subflow/DebugNode.tsx | 4 ++-- example/src/Subflow/index.tsx | 3 +++ src/hooks/useDrag/index.ts | 1 + src/hooks/useDrag/utils.ts | 23 ++++++++++++++++++++--- src/store/index.ts | 10 +--------- src/types/nodes.ts | 2 +- 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/example/src/Basic/index.tsx b/example/src/Basic/index.tsx index 7f91818d..74d0f69b 100644 --- a/example/src/Basic/index.tsx +++ b/example/src/Basic/index.tsx @@ -9,6 +9,7 @@ import ReactFlow, { useReactFlow, } from 'react-flow-renderer'; +const onNodeDrag = (_: MouseEvent, node: Node) => console.log('drag', node); const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node); const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node); @@ -61,6 +62,7 @@ const BasicFlow = () => { defaultEdges={initialEdges} onNodeClick={onNodeClick} onNodeDragStop={onNodeDragStop} + onNodeDrag={onNodeDrag} className="react-flow-basic-example" minZoom={0.2} maxZoom={4} diff --git a/example/src/Subflow/DebugNode.tsx b/example/src/Subflow/DebugNode.tsx index f7cc4b36..e73631a0 100644 --- a/example/src/Subflow/DebugNode.tsx +++ b/example/src/Subflow/DebugNode.tsx @@ -11,7 +11,7 @@ const idStyle: CSSProperties = { left: 2, }; -const ColorSelectorNode: FC = ({ zIndex, xPos, yPos, id }) => { +const DebugNode: FC = ({ zIndex, xPos, yPos, id }) => { return ( <> @@ -24,4 +24,4 @@ const ColorSelectorNode: FC = ({ zIndex, xPos, yPos, id }) => { ); }; -export default memo(ColorSelectorNode); +export default memo(DebugNode); diff --git a/example/src/Subflow/index.tsx b/example/src/Subflow/index.tsx index 1d7c79d2..6b6c4799 100644 --- a/example/src/Subflow/index.tsx +++ b/example/src/Subflow/index.tsx @@ -15,6 +15,7 @@ import ReactFlow, { } from 'react-flow-renderer'; import DebugNode from './DebugNode'; +const onNodeDrag = (_: MouseEvent, node: Node, nodes: Node[]) => console.log('drag', node, nodes); const onNodeDragStop = (_: MouseEvent, node: Node, nodes: Node[]) => console.log('drag stop', node, nodes); const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node); const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge); @@ -82,6 +83,7 @@ const initialNodes: Node[] = [ position: { x: 25, y: 50 }, className: 'light', parentNode: '5', + extent: 'parent', }, { id: '5b', @@ -167,6 +169,7 @@ const Subflow = () => { onNodeClick={onNodeClick} onEdgeClick={onEdgeClick} onConnect={onConnect} + onNodeDrag={onNodeDrag} onNodeDragStop={onNodeDragStop} className="react-flow-basic-example" defaultZoom={1.5} diff --git a/src/hooks/useDrag/index.ts b/src/hooks/useDrag/index.ts index 15d365f8..b14ad14d 100644 --- a/src/hooks/useDrag/index.ts +++ b/src/hooks/useDrag/index.ts @@ -77,6 +77,7 @@ function useDrag({ } const pointerPos = getPointerPosition(event); + lastPos.current = pointerPos; dragItems.current = getDragItems(nodeInternals, pointerPos, nodeId); if (onStart && dragItems.current) { diff --git a/src/hooks/useDrag/utils.ts b/src/hooks/useDrag/utils.ts index cd0e0c41..9679a5c7 100644 --- a/src/hooks/useDrag/utils.ts +++ b/src/hooks/useDrag/utils.ts @@ -39,7 +39,8 @@ export function getDragItems(nodeInternals: NodeInternals, mousePos: XYPosition, .filter((n) => (n.selected || n.id === nodeId) && (!n.parentNode || !isParentSelected(n, nodeInternals))) .map((n) => ({ id: n.id, - position: n.positionAbsolute || { x: 0, y: 0 }, + position: n.position || { x: 0, y: 0 }, + positionAbsolute: n.positionAbsolute || { x: 0, y: 0 }, distance: { x: mousePos.x - (n.positionAbsolute?.x ?? 0), y: mousePos.y - (n.positionAbsolute?.y ?? 0), @@ -94,14 +95,28 @@ export function updatePosition( ]; } - dragItem.position = currentExtent ? clampPosition(nextPosition, currentExtent as CoordinateExtent) : nextPosition; + let parentPosition = { x: 0, y: 0 }; + + if (dragItem.parentNode) { + const parentNode = nodeInternals.get(dragItem.parentNode); + parentPosition = { x: parentNode?.positionAbsolute?.x ?? 0, y: parentNode?.positionAbsolute?.y ?? 0 }; + } + + dragItem.positionAbsolute = currentExtent + ? clampPosition(nextPosition, currentExtent as CoordinateExtent) + : nextPosition; + + dragItem.position = { + x: dragItem.positionAbsolute.x - parentPosition.x, + y: dragItem.positionAbsolute.y - parentPosition.y, + }; return dragItem; } // returns two params: // 1. the dragged node (or the first of the list, if we are dragging a node selection) -// 2. array of selected nodes (handy when multi selection is active) +// 2. array of selected nodes (for multi selections) export function getEventHandlerParams({ nodeId, dragItems, @@ -116,6 +131,8 @@ export function getEventHandlerParams({ return { ...node, + position: n.position, + positionAbsolute: n.positionAbsolute, }; }); diff --git a/src/store/index.ts b/src/store/index.ts index ccfdfecd..ddb09f7b 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -99,16 +99,8 @@ const createStore = () => }; if (positionChanged) { - change.positionAbsolute = node.position; + change.positionAbsolute = node.positionAbsolute; change.position = node.position; - - if (node.parentNode) { - const parentNode = nodeInternals.get(node.parentNode); - change.position = { - x: change.position.x - (parentNode?.positionAbsolute?.x ?? 0), - y: change.position.y - (parentNode?.positionAbsolute?.y ?? 0), - }; - } } return change; diff --git a/src/types/nodes.ts b/src/types/nodes.ts index 0045ae34..31712102 100644 --- a/src/types/nodes.ts +++ b/src/types/nodes.ts @@ -110,8 +110,8 @@ export type NodeBounds = XYPosition & { export type NodeDragItem = { id: string; - // relative node position position: XYPosition; + positionAbsolute: XYPosition; // distance from the mouse cursor to the node when start dragging distance: XYPosition; width?: number | null;