feat(core): add nodeDragThreshold option
This commit is contained in:
@@ -38,6 +38,7 @@ export function useDrag(params: UseDragParams) {
|
|||||||
noDragClassName,
|
noDragClassName,
|
||||||
nodes,
|
nodes,
|
||||||
nodeExtent,
|
nodeExtent,
|
||||||
|
nodeDragThreshold,
|
||||||
viewport,
|
viewport,
|
||||||
autoPanOnNodeDrag,
|
autoPanOnNodeDrag,
|
||||||
nodesDraggable,
|
nodesDraggable,
|
||||||
@@ -65,6 +66,7 @@ export function useDrag(params: UseDragParams) {
|
|||||||
let lastPos: Partial<XYPosition> = { x: undefined, y: undefined }
|
let lastPos: Partial<XYPosition> = { x: undefined, y: undefined }
|
||||||
let mousePosition: XYPosition = { x: 0, y: 0 }
|
let mousePosition: XYPosition = { x: 0, y: 0 }
|
||||||
let dragEvent: MouseEvent | null = null
|
let dragEvent: MouseEvent | null = null
|
||||||
|
let dragStarted = false
|
||||||
|
|
||||||
let autoPanId = 0
|
let autoPanId = 0
|
||||||
let autoPanStarted = false
|
let autoPanStarted = false
|
||||||
@@ -147,41 +149,51 @@ export function useDrag(params: UseDragParams) {
|
|||||||
if (isDisabled) {
|
if (isDisabled) {
|
||||||
selection.on('.drag', null)
|
selection.on('.drag', null)
|
||||||
} else {
|
} else {
|
||||||
|
const startDrag = (event: UseDragEvent) => {
|
||||||
|
dragStarted = true
|
||||||
|
|
||||||
|
const node = findNode(id)
|
||||||
|
if (!selectNodesOnDrag.value && !multiSelectionActive.value && node) {
|
||||||
|
if (!node.selected) {
|
||||||
|
// we need to reset selected nodes when selectNodesOnDrag=false
|
||||||
|
removeSelectedElements()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node && toValue(selectable) && selectNodesOnDrag.value) {
|
||||||
|
handleNodeClick(
|
||||||
|
node,
|
||||||
|
multiSelectionActive.value,
|
||||||
|
addSelectedNodes,
|
||||||
|
removeSelectedElements,
|
||||||
|
nodesSelectionActive,
|
||||||
|
false,
|
||||||
|
nodeEl as HTMLDivElement,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pointerPos = getPointerPosition(event)
|
||||||
|
lastPos = pointerPos
|
||||||
|
dragItems = getDragItems(nodes.value, nodesDraggable.value, pointerPos, findNode, id)
|
||||||
|
|
||||||
|
if (dragItems.length) {
|
||||||
|
const [currentNode, nodes] = getEventHandlerParams({
|
||||||
|
id,
|
||||||
|
dragItems,
|
||||||
|
findNode,
|
||||||
|
})
|
||||||
|
|
||||||
|
onStart({ event: event.sourceEvent, node: currentNode, nodes })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dragHandler = drag()
|
dragHandler = drag()
|
||||||
.on('start', (event: UseDragEvent) => {
|
.on('start', (event: UseDragEvent) => {
|
||||||
const node = findNode(id)
|
if (nodeDragThreshold.value === 0) {
|
||||||
if (!selectNodesOnDrag.value && !multiSelectionActive.value && node) {
|
startDrag(event)
|
||||||
if (!node.selected) {
|
|
||||||
// we need to reset selected nodes when selectNodesOnDrag=false
|
|
||||||
removeSelectedElements()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node && toValue(selectable) && selectNodesOnDrag.value) {
|
lastPos = getPointerPosition(event)
|
||||||
handleNodeClick(
|
|
||||||
node,
|
|
||||||
multiSelectionActive.value,
|
|
||||||
addSelectedNodes,
|
|
||||||
removeSelectedElements,
|
|
||||||
nodesSelectionActive,
|
|
||||||
false,
|
|
||||||
nodeEl as HTMLDivElement,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const pointerPos = getPointerPosition(event)
|
|
||||||
lastPos = pointerPos
|
|
||||||
dragItems = getDragItems(nodes.value, nodesDraggable.value, pointerPos, findNode, id)
|
|
||||||
|
|
||||||
if (dragItems.length) {
|
|
||||||
const [currentNode, nodes] = getEventHandlerParams({
|
|
||||||
id,
|
|
||||||
dragItems,
|
|
||||||
findNode,
|
|
||||||
})
|
|
||||||
|
|
||||||
onStart({ event: event.sourceEvent, node: currentNode, nodes })
|
|
||||||
}
|
|
||||||
|
|
||||||
containerBounds = vueFlowRef.value?.getBoundingClientRect() || null
|
containerBounds = vueFlowRef.value?.getBoundingClientRect() || null
|
||||||
mousePosition = getEventPosition(event.sourceEvent, containerBounds!)
|
mousePosition = getEventPosition(event.sourceEvent, containerBounds!)
|
||||||
@@ -189,13 +201,23 @@ export function useDrag(params: UseDragParams) {
|
|||||||
.on('drag', (event: UseDragEvent) => {
|
.on('drag', (event: UseDragEvent) => {
|
||||||
const pointerPos = getPointerPosition(event)
|
const pointerPos = getPointerPosition(event)
|
||||||
|
|
||||||
if (!autoPanStarted && autoPanOnNodeDrag.value) {
|
if (!autoPanStarted && dragStarted && autoPanOnNodeDrag.value) {
|
||||||
autoPanStarted = true
|
autoPanStarted = true
|
||||||
autoPan()
|
autoPan()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dragStarted) {
|
||||||
|
const x = pointerPos.xSnapped - (lastPos.x ?? 0)
|
||||||
|
const y = pointerPos.ySnapped - (lastPos.y ?? 0)
|
||||||
|
const distance = Math.sqrt(x * x + y * y)
|
||||||
|
|
||||||
|
if (distance > nodeDragThreshold.value) {
|
||||||
|
startDrag(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// skip events without movement
|
// skip events without movement
|
||||||
if ((lastPos.x !== pointerPos.xSnapped || lastPos.y !== pointerPos.ySnapped) && dragItems.length) {
|
if ((lastPos.x !== pointerPos.xSnapped || lastPos.y !== pointerPos.ySnapped) && dragItems.length && dragStarted) {
|
||||||
dragEvent = event.sourceEvent as MouseEvent
|
dragEvent = event.sourceEvent as MouseEvent
|
||||||
mousePosition = getEventPosition(event.sourceEvent, containerBounds!)
|
mousePosition = getEventPosition(event.sourceEvent, containerBounds!)
|
||||||
|
|
||||||
@@ -203,8 +225,13 @@ export function useDrag(params: UseDragParams) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on('end', (event: UseDragEvent) => {
|
.on('end', (event: UseDragEvent) => {
|
||||||
|
if (!dragStarted) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
dragging.value = false
|
dragging.value = false
|
||||||
autoPanStarted = false
|
autoPanStarted = false
|
||||||
|
dragStarted = false
|
||||||
cancelAnimationFrame(autoPanId)
|
cancelAnimationFrame(autoPanId)
|
||||||
|
|
||||||
if (dragItems.length) {
|
if (dragItems.length) {
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ function defaultState(): State {
|
|||||||
nodesFocusable: true,
|
nodesFocusable: true,
|
||||||
nodesConnectable: true,
|
nodesConnectable: true,
|
||||||
nodesDraggable: true,
|
nodesDraggable: true,
|
||||||
|
nodeDragThreshold: 0,
|
||||||
elementsSelectable: true,
|
elementsSelectable: true,
|
||||||
selectNodesOnDrag: true,
|
selectNodesOnDrag: true,
|
||||||
multiSelectionActive: false,
|
multiSelectionActive: false,
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ export interface FlowProps {
|
|||||||
edgesUpdatable?: EdgeUpdatable
|
edgesUpdatable?: EdgeUpdatable
|
||||||
nodesDraggable?: boolean
|
nodesDraggable?: boolean
|
||||||
nodesConnectable?: boolean
|
nodesConnectable?: boolean
|
||||||
|
nodeDragThreshold?: number
|
||||||
elementsSelectable?: boolean
|
elementsSelectable?: boolean
|
||||||
selectNodesOnDrag?: boolean
|
selectNodesOnDrag?: boolean
|
||||||
/** move pane on drag, replaced prop `paneMovable` */
|
/** move pane on drag, replaced prop `paneMovable` */
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ export interface State extends Omit<FlowOptions, 'id' | 'modelValue'> {
|
|||||||
nodesFocusable: boolean
|
nodesFocusable: boolean
|
||||||
nodesDraggable: boolean
|
nodesDraggable: boolean
|
||||||
nodesConnectable: boolean
|
nodesConnectable: boolean
|
||||||
|
nodeDragThreshold: number
|
||||||
|
|
||||||
elementsSelectable: boolean
|
elementsSelectable: boolean
|
||||||
selectNodesOnDrag: boolean
|
selectNodesOnDrag: boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user