refactor(core): use pointer evts in pane and prevent cancel of selection

This commit is contained in:
braks
2024-07-01 09:44:55 +02:00
committed by Braks
parent ea75f8aac0
commit 4effbb0008
2 changed files with 60 additions and 71 deletions
+59 -71
View File
@@ -1,14 +1,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, toRef } from 'vue' import { ref, toRef, watch } from 'vue'
import UserSelection from '../../components/UserSelection/UserSelection.vue' import UserSelection from '../../components/UserSelection/UserSelection.vue'
import NodesSelection from '../../components/NodesSelection/NodesSelection.vue' import NodesSelection from '../../components/NodesSelection/NodesSelection.vue'
import type { GraphNode } from '../../types' import { type GraphNode, SelectionMode } from '../../types'
import { SelectionMode } from '../../types'
import { useKeyPress, useVueFlow } from '../../composables' import { useKeyPress, useVueFlow } from '../../composables'
import { getConnectedEdges, getNodesInside } from '../../utils' import { getConnectedEdges, getNodesInside } from '../../utils'
import { getMousePosition } from './utils' import { getMousePosition } from './utils'
const { isSelecting } = defineProps<{ isSelecting: boolean }>() const { isSelecting, selectionKeyPressed } = defineProps<{ isSelecting: boolean; selectionKeyPressed: boolean }>()
const { const {
vueFlowRef, vueFlowRef,
@@ -43,41 +42,44 @@ const containerBounds = ref<DOMRect>()
const hasActiveSelection = toRef(() => elementsSelectable.value && (isSelecting || userSelectionActive.value)) const hasActiveSelection = toRef(() => elementsSelectable.value && (isSelecting || userSelectionActive.value))
useKeyPress( // Used to prevent click events when the user lets go of the selectionKey during a selection
deleteKeyCode, const selectionInProgress = ref(false)
(keyPressed) => {
if (!keyPressed) { const deleteKeyPressed = useKeyPress(deleteKeyCode, { actInsideInputWithModifier: false })
return
const multiSelectKeyPressed = useKeyPress(multiSelectionKeyCode)
watch(deleteKeyPressed, (isKeyPressed) => {
if (!isKeyPressed) {
return
}
const nodesToRemove: GraphNode[] = []
for (const node of getNodes.value) {
if (!node.selected && node.parentNode && nodesToRemove.some((n) => n.id === node.parentNode)) {
nodesToRemove.push(node)
} else if (node.selected) {
nodesToRemove.push(node)
}
}
if (nodesToRemove || getSelectedEdges.value) {
if (getSelectedEdges.value.length > 0) {
removeEdges(getSelectedEdges.value)
} }
const nodesToRemove: GraphNode[] = [] if (nodesToRemove.length > 0) {
for (const node of getNodes.value) { removeNodes(nodesToRemove)
if (!node.selected && node.parentNode && nodesToRemove.some((n) => n.id === node.parentNode)) {
nodesToRemove.push(node)
} else if (node.selected) {
nodesToRemove.push(node)
}
} }
if (nodesToRemove || getSelectedEdges.value) { nodesSelectionActive.value = false
if (getSelectedEdges.value.length > 0) {
removeEdges(getSelectedEdges.value)
}
if (nodesToRemove.length > 0) { removeSelectedElements()
removeNodes(nodesToRemove) }
} })
nodesSelectionActive.value = false watch(multiSelectKeyPressed, (isKeyPressed) => {
multiSelectionActive.value = isKeyPressed
removeSelectedElements()
}
},
{ actInsideInputWithModifier: false },
)
useKeyPress(multiSelectionKeyCode, (keyPressed) => {
multiSelectionActive.value = keyPressed
}) })
function resetUserSelection() { function resetUserSelection() {
@@ -89,7 +91,8 @@ function resetUserSelection() {
} }
function onClick(event: MouseEvent) { function onClick(event: MouseEvent) {
if (event.target !== container.value || hasActiveSelection.value) { if (selectionInProgress.value || event.target !== container.value || hasActiveSelection.value) {
selectionInProgress.value = false
return return
} }
@@ -121,8 +124,9 @@ function onWheel(event: WheelEvent) {
emits.paneScroll(event) emits.paneScroll(event)
} }
function onMouseDown(event: MouseEvent) { function onPointerDown(event: PointerEvent) {
containerBounds.value = vueFlowRef.value!.getBoundingClientRect() containerBounds.value = vueFlowRef.value?.getBoundingClientRect()
container.value?.setPointerCapture(event.pointerId)
if ( if (
!hasActiveSelection.value || !hasActiveSelection.value ||
@@ -153,26 +157,19 @@ function onMouseDown(event: MouseEvent) {
emits.selectionStart(event) emits.selectionStart(event)
} }
function onMouseMove(event: MouseEvent) { function onPointerMove(event: PointerEvent) {
if (!hasActiveSelection.value) { if (!hasActiveSelection.value) {
return emits.paneMouseMove(event) return emits.paneMouseMove(event)
} }
if (!isSelecting || !containerBounds.value || !userSelectionRect.value) { if (!containerBounds.value || !userSelectionRect.value) {
return return
} }
if (!userSelectionActive.value) { selectionInProgress.value = true
userSelectionActive.value = true
}
if (nodesSelectionActive.value) {
nodesSelectionActive.value = false
}
const mousePos = getMousePosition(event, containerBounds.value) const mousePos = getMousePosition(event, containerBounds.value)
const startX = userSelectionRect.value.startX ?? 0 const { startX = 0, startY = 0 } = userSelectionRect.value
const startY = userSelectionRect.value.startY ?? 0
const nextUserSelectRect = { const nextUserSelectRect = {
...userSelectionRect.value, ...userSelectionRect.value,
@@ -187,6 +184,7 @@ function onMouseMove(event: MouseEvent) {
userSelectionRect.value, userSelectionRect.value,
viewport.value, viewport.value,
selectionMode.value === SelectionMode.Partial, selectionMode.value === SelectionMode.Partial,
true,
) )
const selectedEdges = getConnectedEdges(selectedNodes, getEdges.value) const selectedEdges = getConnectedEdges(selectedNodes, getEdges.value)
@@ -199,14 +197,12 @@ function onMouseMove(event: MouseEvent) {
addSelectedElements([...selectedNodes, ...selectedEdges]) addSelectedElements([...selectedNodes, ...selectedEdges])
} }
function onMouseUp(event: MouseEvent) { function onPointerUp(event: PointerEvent) {
if (!hasActiveSelection.value) { if (!hasActiveSelection.value || event.button !== 0) {
return return
} }
if (event.button !== 0) { container.value?.releasePointerCapture(event.pointerId)
return
}
// We only want to trigger click functions when in selection mode if // We only want to trigger click functions when in selection mode if
// the user did not move the mouse. // the user did not move the mouse.
@@ -219,22 +215,15 @@ function onMouseUp(event: MouseEvent) {
resetUserSelection() resetUserSelection()
emits.selectionEnd(event) emits.selectionEnd(event)
// If the user kept holding the selectionKey during the selection,
// we need to reset the selectionInProgress, so the next click event is not prevented
if (selectionKeyPressed) {
selectionInProgress.value = false
}
} }
function onMouseLeave(event: MouseEvent) { function onPointerEnter(event: PointerEvent) {
if (!hasActiveSelection.value) {
return emits.paneMouseLeave(event)
}
if (userSelectionActive.value) {
nodesSelectionActive.value = prevSelectedNodesCount.value > 0
emits.selectionEnd?.(event)
}
resetUserSelection()
}
function onMouseEnter(event: MouseEvent) {
if (hasActiveSelection.value) { if (hasActiveSelection.value) {
return return
} }
@@ -258,11 +247,10 @@ export default {
@click="onClick" @click="onClick"
@contextmenu="onContextMenu" @contextmenu="onContextMenu"
@wheel.passive="onWheel" @wheel.passive="onWheel"
@mouseenter="onMouseEnter" @pointerenter="onPointerEnter"
@mousedown="onMouseDown" @pointerdown="onPointerDown"
@mousemove="onMouseMove" @pointermove="onPointerMove"
@mouseup="onMouseUp" @pointerup="onPointerUp"
@mouseleave="onMouseLeave"
> >
<slot /> <slot />
<UserSelection v-if="userSelectionActive && userSelectionRect" :user-selection-rect="userSelectionRect" /> <UserSelection v-if="userSelectionActive && userSelectionRect" :user-selection-rect="userSelectionRect" />
@@ -403,6 +403,7 @@ export default {
<div ref="viewportRef" class="vue-flow__viewport vue-flow__container"> <div ref="viewportRef" class="vue-flow__viewport vue-flow__container">
<Pane <Pane
:is-selecting="isSelecting" :is-selecting="isSelecting"
:selection-key-pressed="selectionKeyPressed"
:class="{ connecting: !!connectionStartHandle, dragging: paneDragging, draggable: shouldPanOnDrag }" :class="{ connecting: !!connectionStartHandle, dragging: paneDragging, draggable: shouldPanOnDrag }"
> >
<Transform> <Transform>