From 26795be7fbfb3da2e87232fc2eadc1aea4e92ab8 Mon Sep 17 00:00:00 2001 From: Moritz Klack Date: Wed, 1 Jun 2022 12:55:36 +0200 Subject: [PATCH] fix(subflows): use abs positions for internal calculations (#2189) * refactor(dragging): only use absolute positions * refactor(drag): handle node extent * refactor(drag-handler): return latest data * refactor(use-drag): cleanup fixes #2181 --- example/src/Overview/index.tsx | 4 ++-- src/hooks/useDrag/index.ts | 9 ++------ src/hooks/useDrag/utils.ts | 40 ++++++++++------------------------ src/store/index.ts | 9 ++++++++ src/types/changes.ts | 1 + src/types/nodes.ts | 2 -- src/utils/changes.ts | 4 ++++ 7 files changed, 29 insertions(+), 40 deletions(-) diff --git a/example/src/Overview/index.tsx b/example/src/Overview/index.tsx index ce8e774d..8da8a372 100644 --- a/example/src/Overview/index.tsx +++ b/example/src/Overview/index.tsx @@ -141,7 +141,7 @@ const initialEdges: Edge[] = [ ]; const connectionLineStyle: CSSProperties = { stroke: '#ddd' }; -const snapGrid: SnapGrid = [16, 16]; +const snapGrid: SnapGrid = [25, 25]; const nodeStrokeColor = (n: Node): string => { if (n.style?.background) return n.style.background as string; @@ -203,7 +203,7 @@ const OverviewFlow = () => { > - + ); }; diff --git a/src/hooks/useDrag/index.ts b/src/hooks/useDrag/index.ts index 8f0d6011..01f1c48c 100644 --- a/src/hooks/useDrag/index.ts +++ b/src/hooks/useDrag/index.ts @@ -4,8 +4,8 @@ import { select } from 'd3-selection'; import { useStoreApi } from '../../store'; import { pointToRendererPoint } from '../../utils/graph'; -import { NodeDragItem, NodeDragHandler, XYPosition } from '../../types'; -import { getDragItems, getEventHandlerParams, getParentNodePosition, hasSelector, updatePosition } from './utils'; +import { NodeDragItem, NodeDragHandler } from '../../types'; +import { getDragItems, getEventHandlerParams, hasSelector, updatePosition } from './utils'; import { handleNodeClick } from '../../components/Nodes/utils'; export type UseDragEvent = D3DragEvent; @@ -40,7 +40,6 @@ function useDrag({ const store = useStoreApi(); const dragItems = useRef(); const lastPos = useRef<{ x: number | null; y: number | null }>({ x: null, y: null }); - const parentPos = useRef({ x: 0, y: 0 }); // returns the pointer position projected to the RF coordinate system const getPointerPosition = useCallback(({ sourceEvent }: UseDragEvent) => { @@ -49,9 +48,6 @@ function useDrag({ const y = sourceEvent.touches ? sourceEvent.touches[0].clientY : sourceEvent.clientY; const pointerPos = pointToRendererPoint({ x, y }, transform, snapToGrid, snapGrid); - pointerPos.x -= parentPos.current.x; - pointerPos.y -= parentPos.current.y; - return pointerPos; }, []); @@ -65,7 +61,6 @@ function useDrag({ const dragHandler = drag() .on('start', (event: UseDragEvent) => { const { nodeInternals, multiSelectionActive, unselectNodesAndEdges } = store.getState(); - parentPos.current = getParentNodePosition(nodeInternals, nodeId); if (!selectNodesOnDrag && !multiSelectionActive && nodeId) { if (!nodeInternals.get(nodeId)?.selected) { diff --git a/src/hooks/useDrag/utils.ts b/src/hooks/useDrag/utils.ts index 8e5fb117..480be034 100644 --- a/src/hooks/useDrag/utils.ts +++ b/src/hooks/useDrag/utils.ts @@ -21,16 +21,6 @@ export function isParentSelected(node: Node, nodeInternals: NodeInternals): bool return isParentSelected(parentNode, nodeInternals); } -export function getParentNodePosition(nodeInternals: NodeInternals, nodeId?: string): XYPosition { - const parentNodeId = nodeId ? nodeInternals.get(nodeId)?.parentNode : null; - const parentNode = parentNodeId ? nodeInternals.get(parentNodeId) : null; - - return { - x: parentNode?.positionAbsolute?.x || 0, - y: parentNode?.positionAbsolute?.y || 0, - }; -} - export function hasSelector(target: Element, selector: string, nodeRef: RefObject): boolean { let current = target; @@ -49,10 +39,10 @@ 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.position, + position: n.positionAbsolute || { x: 0, y: 0 }, distance: { - x: mousePos.x - n.position.x, - y: mousePos.y - n.position.y, + x: mousePos.x - (n.positionAbsolute?.x ?? 0), + y: mousePos.y - (n.positionAbsolute?.y ?? 0), }, delta: { x: 0, @@ -72,16 +62,19 @@ export function updatePosition( nodeExtent?: CoordinateExtent ): NodeDragItem { let currentExtent = dragItem.extent || nodeExtent; - let nextPosition = { x: mousePos.x - dragItem.distance.x, y: mousePos.y - dragItem.distance.y }; + const nextPosition = { x: mousePos.x - dragItem.distance.x, y: mousePos.y - dragItem.distance.y }; if (dragItem.extent === 'parent') { if (dragItem.parentNode && dragItem.width && dragItem.height) { const parent = nodeInternals.get(dragItem.parentNode); currentExtent = - parent?.width && parent?.height + parent?.positionAbsolute && parent?.width && parent?.height ? [ - [0, 0], - [parent.width - dragItem.width, parent.height - dragItem.height], + [parent.positionAbsolute.x, parent.positionAbsolute.y], + [ + parent.positionAbsolute.x + parent.width - dragItem.width, + parent.positionAbsolute.y + parent.height - dragItem.height, + ], ] : currentExtent; } else { @@ -93,13 +86,7 @@ export function updatePosition( } } - nextPosition = currentExtent ? clampPosition(nextPosition, currentExtent as CoordinateExtent) : nextPosition; - - dragItem.delta = { - x: nextPosition.x - dragItem.position.x, - y: nextPosition.y - dragItem.position.y, - }; - dragItem.position = nextPosition; + dragItem.position = currentExtent ? clampPosition(nextPosition, currentExtent as CoordinateExtent) : nextPosition; return dragItem; } @@ -121,11 +108,6 @@ export function getEventHandlerParams({ return { ...node, - position: n.position, - positionAbsolute: { - x: (node.positionAbsolute?.x || 0) + n.delta.x, - y: (node.positionAbsolute?.y || 0) + n.delta.y, - }, }; }); diff --git a/src/store/index.ts b/src/store/index.ts index cfcd63b8..ccfdfecd 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -99,7 +99,16 @@ const createStore = () => }; if (positionChanged) { + change.positionAbsolute = node.position; 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/changes.ts b/src/types/changes.ts index b5eddaf6..498261ba 100644 --- a/src/types/changes.ts +++ b/src/types/changes.ts @@ -12,6 +12,7 @@ export type NodePositionChange = { id: string; type: 'position'; position?: XYPosition; + positionAbsolute?: XYPosition; dragging?: boolean; }; diff --git a/src/types/nodes.ts b/src/types/nodes.ts index d73b0c97..ae0bb6f7 100644 --- a/src/types/nodes.ts +++ b/src/types/nodes.ts @@ -115,8 +115,6 @@ export type NodeDragItem = { position: XYPosition; // distance from the mouse cursor to the node when start dragging distance: XYPosition; - // delta to previous position - delta: XYPosition; width?: number | null; height?: number | null; extent?: 'parent' | CoordinateExtent; diff --git a/src/utils/changes.ts b/src/utils/changes.ts index de0771c1..76bc716e 100644 --- a/src/utils/changes.ts +++ b/src/utils/changes.ts @@ -67,6 +67,10 @@ function applyChanges(changes: any[], elements: any[]): any[] { updateItem.position = currentChange.position; } + if (typeof currentChange.positionAbsolute !== 'undefined') { + updateItem.positionAbsolute = currentChange.positionAbsolute; + } + if (typeof currentChange.dragging !== 'undefined') { updateItem.dragging = currentChange.dragging; }