Merge pull request #4790 from xyflow/fix/node-drag
Fix node drag while zooming
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
'@xyflow/system': patch
|
||||||
|
'@xyflow/react': patch
|
||||||
|
'@xyflow/svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix node dragging & resizing while zooming on flow that does not cover whole browser window.
|
||||||
@@ -56,13 +56,14 @@ function ResizeControl({
|
|||||||
domNode: resizeControlRef.current,
|
domNode: resizeControlRef.current,
|
||||||
nodeId: id,
|
nodeId: id,
|
||||||
getStoreItems: () => {
|
getStoreItems: () => {
|
||||||
const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin } = store.getState();
|
const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin, domNode } = store.getState();
|
||||||
return {
|
return {
|
||||||
nodeLookup,
|
nodeLookup,
|
||||||
transform,
|
transform,
|
||||||
snapGrid,
|
snapGrid,
|
||||||
snapToGrid,
|
snapToGrid,
|
||||||
nodeOrigin,
|
nodeOrigin,
|
||||||
|
paneDomNode: domNode,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onChange: (change: XYResizerChange, childChanges: XYResizerChildChange[]) => {
|
onChange: (change: XYResizerChange, childChanges: XYResizerChildChange[]) => {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
let className: $$Props['class'] = '';
|
let className: $$Props['class'] = '';
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
||||||
const { nodeLookup, snapGrid, viewport, nodes, nodeOrigin } = useStore();
|
const { nodeLookup, snapGrid, viewport, nodes, nodeOrigin, domNode } = useStore();
|
||||||
|
|
||||||
const contextNodeId = getContext<string>('svelteflow__node_id');
|
const contextNodeId = getContext<string>('svelteflow__node_id');
|
||||||
$: id = typeof nodeId === 'string' ? nodeId : contextNodeId;
|
$: id = typeof nodeId === 'string' ? nodeId : contextNodeId;
|
||||||
@@ -65,7 +65,8 @@
|
|||||||
transform: [$viewport.x, $viewport.y, $viewport.zoom],
|
transform: [$viewport.x, $viewport.y, $viewport.zoom],
|
||||||
snapGrid: $snapGrid ?? undefined,
|
snapGrid: $snapGrid ?? undefined,
|
||||||
snapToGrid: !!$snapGrid,
|
snapToGrid: !!$snapGrid,
|
||||||
nodeOrigin: $nodeOrigin
|
nodeOrigin: $nodeOrigin,
|
||||||
|
paneDomNode: $domNode
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onChange: (change: XYResizerChange, childChanges: XYResizerChildChange[]) => {
|
onChange: (change: XYResizerChange, childChanges: XYResizerChildChange[]) => {
|
||||||
|
|||||||
@@ -5,14 +5,18 @@ export type GetPointerPositionParams = {
|
|||||||
transform: Transform;
|
transform: Transform;
|
||||||
snapGrid?: SnapGrid;
|
snapGrid?: SnapGrid;
|
||||||
snapToGrid?: boolean;
|
snapToGrid?: boolean;
|
||||||
|
containerBounds: DOMRect | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getPointerPosition(
|
export function getPointerPosition(
|
||||||
event: MouseEvent | TouchEvent,
|
event: MouseEvent | TouchEvent,
|
||||||
{ snapGrid = [0, 0], snapToGrid = false, transform }: GetPointerPositionParams
|
{ snapGrid = [0, 0], snapToGrid = false, transform, containerBounds }: GetPointerPositionParams
|
||||||
): XYPosition & { xSnapped: number; ySnapped: number } {
|
): XYPosition & { xSnapped: number; ySnapped: number } {
|
||||||
const { x, y } = getEventPosition(event);
|
const { x, y } = getEventPosition(event);
|
||||||
const pointerPos = pointToRendererPoint({ x, y }, transform);
|
const pointerPos = pointToRendererPoint(
|
||||||
|
{ x: x - (containerBounds?.left ?? 0), y: y - (containerBounds?.top ?? 0) },
|
||||||
|
transform
|
||||||
|
);
|
||||||
const { x: xSnapped, y: ySnapped } = snapToGrid ? snapPosition(pointerPos, snapGrid) : pointerPos;
|
const { x: xSnapped, y: ySnapped } = snapToGrid ? snapPosition(pointerPos, snapGrid) : pointerPos;
|
||||||
|
|
||||||
// we need the snapped position in order to be able to skip unnecessary drag events
|
// we need the snapped position in order to be able to skip unnecessary drag events
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
onNodeMouseDown?.(nodeId);
|
onNodeMouseDown?.(nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid, containerBounds });
|
||||||
lastPos = pointerPos;
|
lastPos = pointerPos;
|
||||||
dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);
|
dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);
|
||||||
|
|
||||||
@@ -281,6 +281,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
.clickDistance(nodeClickDistance)
|
.clickDistance(nodeClickDistance)
|
||||||
.on('start', (event: UseDragEvent) => {
|
.on('start', (event: UseDragEvent) => {
|
||||||
const { domNode, nodeDragThreshold, transform, snapGrid, snapToGrid } = getStoreItems();
|
const { domNode, nodeDragThreshold, transform, snapGrid, snapToGrid } = getStoreItems();
|
||||||
|
containerBounds = domNode?.getBoundingClientRect() || null;
|
||||||
|
|
||||||
abortDrag = false;
|
abortDrag = false;
|
||||||
|
|
||||||
@@ -288,14 +289,13 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
startDrag(event);
|
startDrag(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid, containerBounds });
|
||||||
lastPos = pointerPos;
|
lastPos = pointerPos;
|
||||||
containerBounds = domNode?.getBoundingClientRect() || null;
|
|
||||||
mousePosition = getEventPosition(event.sourceEvent, containerBounds!);
|
mousePosition = getEventPosition(event.sourceEvent, containerBounds!);
|
||||||
})
|
})
|
||||||
.on('drag', (event: UseDragEvent) => {
|
.on('drag', (event: UseDragEvent) => {
|
||||||
const { autoPanOnNodeDrag, transform, snapGrid, snapToGrid, nodeDragThreshold, nodeLookup } = getStoreItems();
|
const { autoPanOnNodeDrag, transform, snapGrid, snapToGrid, nodeDragThreshold, nodeLookup } = getStoreItems();
|
||||||
const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid, containerBounds });
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(event.sourceEvent.type === 'touchmove' && event.sourceEvent.touches.length > 1) ||
|
(event.sourceEvent.type === 'touchmove' && event.sourceEvent.touches.length > 1) ||
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ type XYResizerParams = {
|
|||||||
snapGrid?: [number, number];
|
snapGrid?: [number, number];
|
||||||
snapToGrid: boolean;
|
snapToGrid: boolean;
|
||||||
nodeOrigin: NodeOrigin;
|
nodeOrigin: NodeOrigin;
|
||||||
|
paneDomNode: HTMLDivElement | null;
|
||||||
};
|
};
|
||||||
onChange: (changes: XYResizerChange, childChanges: XYResizerChildChange[]) => void;
|
onChange: (changes: XYResizerChange, childChanges: XYResizerChildChange[]) => void;
|
||||||
onEnd?: () => void;
|
onEnd?: () => void;
|
||||||
@@ -109,6 +110,7 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X
|
|||||||
const controlDirection = getControlDirection(controlPosition);
|
const controlDirection = getControlDirection(controlPosition);
|
||||||
|
|
||||||
let node: InternalNodeBase | undefined = undefined;
|
let node: InternalNodeBase | undefined = undefined;
|
||||||
|
let containerBounds: DOMRect | null = null;
|
||||||
let childNodes: XYResizerChildChange[] = [];
|
let childNodes: XYResizerChildChange[] = [];
|
||||||
let parentNode: InternalNodeBase | undefined = undefined; // Needed to fix expandParent
|
let parentNode: InternalNodeBase | undefined = undefined; // Needed to fix expandParent
|
||||||
let parentExtent: CoordinateExtent | undefined = undefined;
|
let parentExtent: CoordinateExtent | undefined = undefined;
|
||||||
@@ -116,14 +118,20 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X
|
|||||||
|
|
||||||
const dragHandler = drag<HTMLDivElement, unknown>()
|
const dragHandler = drag<HTMLDivElement, unknown>()
|
||||||
.on('start', (event: ResizeDragEvent) => {
|
.on('start', (event: ResizeDragEvent) => {
|
||||||
const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin } = getStoreItems();
|
const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin, paneDomNode } = getStoreItems();
|
||||||
node = nodeLookup.get(nodeId);
|
node = nodeLookup.get(nodeId);
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
containerBounds = paneDomNode?.getBoundingClientRect() ?? null;
|
||||||
|
const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, {
|
||||||
|
transform,
|
||||||
|
snapGrid,
|
||||||
|
snapToGrid,
|
||||||
|
containerBounds,
|
||||||
|
});
|
||||||
|
|
||||||
prevValues = {
|
prevValues = {
|
||||||
width: node.measured.width ?? 0,
|
width: node.measured.width ?? 0,
|
||||||
@@ -178,7 +186,13 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X
|
|||||||
})
|
})
|
||||||
.on('drag', (event: ResizeDragEvent) => {
|
.on('drag', (event: ResizeDragEvent) => {
|
||||||
const { transform, snapGrid, snapToGrid, nodeOrigin: storeNodeOrigin } = getStoreItems();
|
const { transform, snapGrid, snapToGrid, nodeOrigin: storeNodeOrigin } = getStoreItems();
|
||||||
const pointerPosition = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
|
||||||
|
const pointerPosition = getPointerPosition(event.sourceEvent, {
|
||||||
|
transform,
|
||||||
|
snapGrid,
|
||||||
|
snapToGrid,
|
||||||
|
containerBounds,
|
||||||
|
});
|
||||||
const childChanges: XYResizerChildChange[] = [];
|
const childChanges: XYResizerChildChange[] = [];
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
|
|||||||
Reference in New Issue
Block a user