fix(vue-flow,nodes): use computed pos to calculate relative node pos
This commit is contained in:
@@ -6,7 +6,7 @@ import type { MaybeRef } from '@vueuse/core'
|
||||
import useVueFlow from './useVueFlow'
|
||||
import { handleNodeClick, pointToRendererPoint } from '~/utils'
|
||||
import type { NodeDragEvent, NodeDragItem, XYPosition } from '~/types'
|
||||
import { getDragItems, getEventHandlerParams, getParentNodePosition, hasSelector, updatePosition } from '~/utils/drag'
|
||||
import { getDragItems, getEventHandlerParams, hasSelector, updatePosition } from '~/utils/drag'
|
||||
|
||||
export type UseDragEvent = D3DragEvent<HTMLDivElement, null, SubjectPosition>
|
||||
|
||||
@@ -41,24 +41,21 @@ function useDrag(params: UseDragParams) {
|
||||
const dragging = ref(false)
|
||||
let dragItems = $ref<NodeDragItem[]>()
|
||||
let lastPos = $ref<Partial<XYPosition>>({ x: undefined, y: undefined })
|
||||
let parentPos = $ref<XYPosition>({ x: 0, y: 0 })
|
||||
let dragHandler = $ref<any>()
|
||||
|
||||
const getMousePosition = (event: UseDragEvent) => {
|
||||
const mousePos = pointToRendererPoint(
|
||||
const x = event.sourceEvent.touches ? event.sourceEvent.touches[0].clientX : event.sourceEvent.clientX
|
||||
const y = event.sourceEvent.touches ? event.sourceEvent.touches[0].clientY : event.sourceEvent.clientY
|
||||
|
||||
return pointToRendererPoint(
|
||||
{
|
||||
x: event.sourceEvent.clientX,
|
||||
y: event.sourceEvent.clientY,
|
||||
x,
|
||||
y,
|
||||
},
|
||||
viewport,
|
||||
snapToGrid,
|
||||
snapGrid,
|
||||
)
|
||||
|
||||
mousePos.x -= parentPos.x
|
||||
mousePos.y -= parentPos.y
|
||||
|
||||
return mousePos
|
||||
}
|
||||
|
||||
watch(
|
||||
@@ -73,8 +70,6 @@ function useDrag(params: UseDragParams) {
|
||||
} else {
|
||||
dragHandler = drag()
|
||||
.on('start', (event: UseDragEvent) => {
|
||||
parentPos = getParentNodePosition(node && node.parentNode ? getNode(node!.parentNode!) : undefined)
|
||||
|
||||
if (!selectNodesOnDrag && !multiSelectionActive && id) {
|
||||
if (!node?.selected) {
|
||||
removeSelectedElements()
|
||||
@@ -92,14 +87,12 @@ function useDrag(params: UseDragParams) {
|
||||
const [currentNode, nodes] = getEventHandlerParams({
|
||||
id,
|
||||
dragItems,
|
||||
node: node!,
|
||||
getNode: $$(getNode),
|
||||
})
|
||||
onStart(event.sourceEvent, currentNode, nodes)
|
||||
}
|
||||
})
|
||||
.on('drag', (event: UseDragEvent) => {
|
||||
parentPos = getParentNodePosition(node && node.parentNode ? getNode(node!.parentNode!) : undefined)
|
||||
|
||||
const mousePos = getMousePosition(event)
|
||||
|
||||
// skip events without movement
|
||||
@@ -109,14 +102,14 @@ function useDrag(params: UseDragParams) {
|
||||
updatePosition(n, mousePos, n.parentNode ? getNode(n.parentNode) : undefined, nodeExtent),
|
||||
)
|
||||
|
||||
updateNodePositions(dragItems)
|
||||
updateNodePositions(dragItems, true, true)
|
||||
dragging.value = true
|
||||
|
||||
if (onDrag) {
|
||||
const [currentNode, nodes] = getEventHandlerParams({
|
||||
id,
|
||||
dragItems,
|
||||
node: node!,
|
||||
getNode: $$(getNode),
|
||||
})
|
||||
onDrag(event.sourceEvent, currentNode, nodes)
|
||||
}
|
||||
@@ -125,10 +118,12 @@ function useDrag(params: UseDragParams) {
|
||||
event.on('end', (event) => {
|
||||
dragging.value = false
|
||||
if (onStop && dragItems) {
|
||||
updateNodePositions(dragItems, false, false)
|
||||
|
||||
const [currentNode, nodes] = getEventHandlerParams({
|
||||
id,
|
||||
dragItems,
|
||||
node: node!,
|
||||
getNode: $$(getNode),
|
||||
})
|
||||
onStop(event.sourceEvent, currentNode, nodes)
|
||||
}
|
||||
|
||||
@@ -30,16 +30,31 @@ import {
|
||||
} from '~/utils'
|
||||
|
||||
export default (state: State, getters: ComputedGetters): Actions => {
|
||||
const updateNodePositions: Actions['updateNodePositions'] = (dragItems) => {
|
||||
const updateNodePositions: Actions['updateNodePositions'] = (dragItems, changed, dragging) => {
|
||||
const changes: NodePositionChange[] = []
|
||||
|
||||
dragItems.forEach((node) => {
|
||||
const change: NodePositionChange = {
|
||||
const change: Partial<NodePositionChange> = {
|
||||
id: node.id,
|
||||
type: 'position',
|
||||
position: node.position,
|
||||
dragging,
|
||||
}
|
||||
changes.push(change)
|
||||
|
||||
if (changed) {
|
||||
change.computedPosition = node.position
|
||||
change.position = node.position
|
||||
|
||||
if (node.parentNode) {
|
||||
const parentNode = getters.getNode.value(node.parentNode)
|
||||
|
||||
change.position = {
|
||||
x: change.position.x - (parentNode?.computedPosition?.x ?? 0),
|
||||
y: change.position.y - (parentNode?.computedPosition?.y ?? 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changes.push(change as NodePositionChange)
|
||||
})
|
||||
|
||||
if (changes?.length) {
|
||||
|
||||
@@ -8,8 +8,6 @@ export interface NodeDragItem {
|
||||
position: XYPosition
|
||||
// distance from the mouse cursor to the node when start dragging
|
||||
distance: XYPosition
|
||||
// delta to previous position
|
||||
delta: XYPosition
|
||||
dimensions: Dimensions
|
||||
extent?: Node['extent']
|
||||
parentNode?: string
|
||||
@@ -25,7 +23,9 @@ export interface NodeDimensionChange {
|
||||
export interface NodePositionChange {
|
||||
id: string
|
||||
type: 'position'
|
||||
position?: XYPosition
|
||||
position: XYPosition
|
||||
computedPosition: XYPosition
|
||||
dragging: boolean
|
||||
}
|
||||
|
||||
export interface NodeSelectionChange {
|
||||
|
||||
@@ -113,7 +113,7 @@ export type SetState = (
|
||||
| Partial<FlowOptions & Omit<State, 'nodes' | 'edges' | 'modelValue'>>
|
||||
| ((state: State) => Partial<FlowOptions & Omit<State, 'nodes' | 'edges' | 'modelValue'>>),
|
||||
) => void
|
||||
export type UpdateNodePosition = (dragItems: NodeDragItem[]) => void
|
||||
export type UpdateNodePosition = (dragItems: NodeDragItem[], changed: boolean, dragging: boolean) => void
|
||||
export type UpdateNodeDimensions = (updates: UpdateNodeDimensionsParams[]) => void
|
||||
|
||||
export interface Actions {
|
||||
|
||||
@@ -97,6 +97,11 @@ export const applyChanges = <
|
||||
case 'position':
|
||||
if (isGraphNode(el)) {
|
||||
if (typeof change.position !== 'undefined') el.position = change.position
|
||||
|
||||
if (typeof change.computedPosition !== 'undefined') {
|
||||
el.computedPosition = { ...el.computedPosition, ...change.computedPosition }
|
||||
}
|
||||
|
||||
if (el.expandParent && el.parentNode) {
|
||||
const parent = elements.find((parent) => parent.id === el.parentNode)
|
||||
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import type { Ref } from 'vue'
|
||||
import { clampPosition, isParentSelected } from './graph'
|
||||
import type { CoordinateExtent, Getters, GraphNode, NodeDragItem, XYPosition } from '~/types'
|
||||
|
||||
export function getParentNodePosition(parent?: GraphNode): XYPosition {
|
||||
return {
|
||||
x: parent?.computedPosition?.x || 0,
|
||||
y: parent?.computedPosition?.y || 0,
|
||||
}
|
||||
}
|
||||
import type { ComputedGetters, CoordinateExtent, Getters, GraphNode, NodeDragItem, XYPosition } from '~/types'
|
||||
|
||||
export function hasSelector(target: Element, selector: string, node: Ref<Element>): boolean {
|
||||
let current = target
|
||||
@@ -32,14 +25,10 @@ export function getDragItems(
|
||||
.filter((n) => (n.selected || n.id === nodeId) && (!n.parentNode || !isParentSelected(n, getNode)))
|
||||
.map((n) => ({
|
||||
id: n.id,
|
||||
position: n.position,
|
||||
position: n.computedPosition || { x: 0, y: 0, z: 0 },
|
||||
distance: {
|
||||
x: mousePos.x - n.position.x,
|
||||
y: mousePos.y - n.position.y,
|
||||
},
|
||||
delta: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
x: mousePos.x - n.computedPosition?.x || 0,
|
||||
y: mousePos.y - n.computedPosition?.y || 0,
|
||||
},
|
||||
extent: n.extent,
|
||||
parentNode: n.parentNode,
|
||||
@@ -50,21 +39,17 @@ export function getDragItems(
|
||||
export function getEventHandlerParams({
|
||||
id,
|
||||
dragItems,
|
||||
node,
|
||||
getNode,
|
||||
}: {
|
||||
id?: string
|
||||
dragItems: NodeDragItem[]
|
||||
node: GraphNode
|
||||
getNode: ComputedGetters['getNode']
|
||||
}): [GraphNode, GraphNode[]] {
|
||||
const extendedDragItems: GraphNode[] = dragItems.map((n) => {
|
||||
const node = getNode.value(n.id)!
|
||||
|
||||
return {
|
||||
...node,
|
||||
position: n.position,
|
||||
computedPosition: {
|
||||
x: (node.computedPosition?.x || 0) + n.delta.x,
|
||||
y: (node.computedPosition?.y || 0) + n.delta.y,
|
||||
z: node.computedPosition.z,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -78,15 +63,18 @@ 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' && parent) {
|
||||
if (dragItem.parentNode && dragItem.dimensions.width && dragItem.dimensions.height) {
|
||||
currentExtent =
|
||||
parent.dimensions.width && parent.dimensions.height
|
||||
parent.computedPosition && parent.dimensions.width && parent.dimensions.height
|
||||
? [
|
||||
[0, 0],
|
||||
[parent.dimensions.width - dragItem.dimensions.width, parent.dimensions.height - dragItem.dimensions.height],
|
||||
[parent.computedPosition.x, parent.computedPosition.y],
|
||||
[
|
||||
parent.computedPosition.x + parent.dimensions.width - dragItem.dimensions.width,
|
||||
parent.computedPosition.y + parent.dimensions.height - dragItem.dimensions.height,
|
||||
],
|
||||
]
|
||||
: currentExtent
|
||||
}
|
||||
@@ -94,13 +82,7 @@ export function updatePosition(
|
||||
currentExtent = nodeExtent
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user