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