diff --git a/packages/core/src/components/Nodes/NodeWrapper.ts b/packages/core/src/components/Nodes/NodeWrapper.ts index 546ec96d2..b57c12a1e 100644 --- a/packages/core/src/components/Nodes/NodeWrapper.ts +++ b/packages/core/src/components/Nodes/NodeWrapper.ts @@ -226,6 +226,8 @@ const NodeWrapper = defineComponent({ } else { node.computedPosition = xyzPos } + + clampPosition() }, { flush: 'post', immediate: true }, ) diff --git a/packages/core/src/utils/drag.ts b/packages/core/src/utils/drag.ts index ccc107f2f..9af230d8e 100644 --- a/packages/core/src/utils/drag.ts +++ b/packages/core/src/utils/drag.ts @@ -9,7 +9,7 @@ import type { State, XYPosition, } from '../types' -import { ErrorCode, VueFlowError, clampPosition, isParentSelected } from '.' +import { ErrorCode, VueFlowError, clampPosition, clampPositionToParent, isParentSelected } from '.' export function hasSelector(target: Element, selector: string, node: Element): boolean { let current = target @@ -192,15 +192,23 @@ export function calcNextPosition( nodeExtent?: State['nodeExtent'], parentNode?: GraphNode, ) { + const currentExtent = node.extent || nodeExtent const extent = clampNodeExtent(node.dimensions, getExtent(node, triggerError, nodeExtent, parentNode)) const clampedPos = clampPosition(nextPosition, extent) + let computedPos = clampedPos + + if (parentNode && (currentExtent === 'parent' || (!Array.isArray(currentExtent) && currentExtent?.range === 'parent'))) { + console.log('clamp to parent') + computedPos = clampPositionToParent(clampedPos, node.dimensions, parentNode) + } + return { position: { x: clampedPos.x - (parentNode?.computedPosition.x || 0), y: clampedPos.y - (parentNode?.computedPosition.y || 0), }, - computedPosition: clampedPos, + computedPosition: computedPos, } } diff --git a/packages/core/src/utils/general.ts b/packages/core/src/utils/general.ts index 5bc728af9..4f920f5be 100644 --- a/packages/core/src/utils/general.ts +++ b/packages/core/src/utils/general.ts @@ -1,5 +1,6 @@ -import type { GraphNode, SnapGrid, XYPosition } from '../types' import type { UseDragEvent } from '../composables' +import type { Dimensions, GraphNode, SnapGrid, XYPosition } from '../types' +import { clampPosition } from './graph' export function isMouseEvent(event: MouseEvent | TouchEvent): event is MouseEvent { return 'clientX' in event @@ -36,3 +37,17 @@ export function snapPosition(position: XYPosition, snapGrid: SnapGrid = [1, 1]): y: snapGrid[1] * Math.round(position.y / snapGrid[1]), } } + +export function clampPositionToParent(childPosition: XYPosition, childDimensions: Dimensions, parent: GraphNode) { + const { width: parentWidth, height: parentHeight } = getNodeDimensions(parent) + const { x: parentX, y: parentY } = parent.computedPosition + + return clampPosition( + childPosition, + [ + [parentX, parentY], + [parentX + parentWidth, parentY + parentHeight], + ], + childDimensions, + ) +} diff --git a/packages/core/src/utils/graph.ts b/packages/core/src/utils/graph.ts index 209709b76..8a559b909 100644 --- a/packages/core/src/utils/graph.ts +++ b/packages/core/src/utils/graph.ts @@ -49,10 +49,10 @@ export function clamp(val: number, min = 0, max = 1) { return Math.min(Math.max(val, min), max) } -export function clampPosition(position: XYPosition, extent: CoordinateExtent): XYPosition { +export function clampPosition(position: XYPosition = { x: 0, y: 0 }, extent: CoordinateExtent, dimensions?: Partial) { return { - x: clamp(position.x, extent[0][0], extent[1][0]), - y: clamp(position.y, extent[0][1], extent[1][1]), + x: clamp(position.x, extent[0][0], extent[1][0] - (dimensions?.width ?? 0)), + y: clamp(position.y, extent[0][1], extent[1][1] - (dimensions?.height ?? 0)), } }