chore(core): cleanup pane (#1507)
* chore(core): cleanup pane * chore(core): cleanup actions
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
import { ref, toRef, watch } from 'vue'
|
||||
import UserSelection from '../../components/UserSelection/UserSelection.vue'
|
||||
import NodesSelection from '../../components/NodesSelection/NodesSelection.vue'
|
||||
import type { NodeChange } from '../../types'
|
||||
import { SelectionMode } from '../../types'
|
||||
import { useKeyPress, useVueFlow } from '../../composables'
|
||||
import { getConnectedEdges, getNodesInside } from '../../utils'
|
||||
import { getEventPosition, getNodesInside, getSelectionChanges } from '../../utils'
|
||||
import { getMousePosition } from './utils'
|
||||
|
||||
const { isSelecting, selectionKeyPressed } = defineProps<{ isSelecting: boolean; selectionKeyPressed: boolean }>()
|
||||
@@ -12,7 +13,6 @@ const { isSelecting, selectionKeyPressed } = defineProps<{ isSelecting: boolean;
|
||||
const {
|
||||
vueFlowRef,
|
||||
getNodes,
|
||||
getEdges,
|
||||
viewport,
|
||||
emits,
|
||||
userSelectionActive,
|
||||
@@ -21,7 +21,6 @@ const {
|
||||
userSelectionRect,
|
||||
elementsSelectable,
|
||||
nodesSelectionActive,
|
||||
addSelectedElements,
|
||||
getSelectedEdges,
|
||||
getSelectedNodes,
|
||||
removeNodes,
|
||||
@@ -30,6 +29,8 @@ const {
|
||||
deleteKeyCode,
|
||||
multiSelectionKeyCode,
|
||||
multiSelectionActive,
|
||||
edgeLookup,
|
||||
nodeLookup,
|
||||
} = useVueFlow()
|
||||
|
||||
const container = ref<HTMLDivElement | null>(null)
|
||||
@@ -40,6 +41,8 @@ const prevSelectedEdgesCount = ref(0)
|
||||
|
||||
const containerBounds = ref<DOMRect>()
|
||||
|
||||
const edgeIdLookup = ref<Map<string, Set<string>>>(new Map())
|
||||
|
||||
const hasActiveSelection = toRef(() => elementsSelectable.value && (isSelecting || userSelectionActive.value))
|
||||
|
||||
// Used to prevent click events when the user lets go of the selectionKey during a selection
|
||||
@@ -65,6 +68,16 @@ watch(multiSelectKeyPressed, (isKeyPressed) => {
|
||||
multiSelectionActive.value = isKeyPressed
|
||||
})
|
||||
|
||||
function wrapHandler(handler: Function, containerRef: HTMLDivElement | null) {
|
||||
return (event: MouseEvent) => {
|
||||
if (event.target !== containerRef) {
|
||||
return
|
||||
}
|
||||
|
||||
handler?.(event)
|
||||
}
|
||||
}
|
||||
|
||||
function resetUserSelection() {
|
||||
userSelectionActive.value = false
|
||||
userSelectionRect.value = null
|
||||
@@ -74,7 +87,7 @@ function resetUserSelection() {
|
||||
}
|
||||
|
||||
function onClick(event: MouseEvent) {
|
||||
if (selectionInProgress.value || event.target !== container.value || hasActiveSelection.value) {
|
||||
if (selectionInProgress.value) {
|
||||
selectionInProgress.value = false
|
||||
return
|
||||
}
|
||||
@@ -87,10 +100,6 @@ function onClick(event: MouseEvent) {
|
||||
}
|
||||
|
||||
function onContextMenu(event: MouseEvent) {
|
||||
if (event.target !== container.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Array.isArray(panOnDrag.value) && panOnDrag.value?.includes(2)) {
|
||||
event.preventDefault()
|
||||
return
|
||||
@@ -100,27 +109,32 @@ function onContextMenu(event: MouseEvent) {
|
||||
}
|
||||
|
||||
function onWheel(event: WheelEvent) {
|
||||
if (event.target !== container.value) {
|
||||
return
|
||||
}
|
||||
|
||||
emits.paneScroll(event)
|
||||
}
|
||||
|
||||
function onPointerDown(event: PointerEvent) {
|
||||
if (!hasActiveSelection.value) {
|
||||
return emits.paneMouseMove(event)
|
||||
}
|
||||
|
||||
containerBounds.value = vueFlowRef.value?.getBoundingClientRect()
|
||||
container.value?.setPointerCapture(event.pointerId)
|
||||
|
||||
if (!elementsSelectable || !isSelecting || event.button !== 0 || event.target !== container.value || !containerBounds.value) {
|
||||
if (
|
||||
!elementsSelectable.value ||
|
||||
!isSelecting ||
|
||||
event.button !== 0 ||
|
||||
event.target !== container.value ||
|
||||
!containerBounds.value
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const { x, y } = getMousePosition(event, containerBounds.value)
|
||||
|
||||
edgeIdLookup.value = new Map()
|
||||
|
||||
for (const [id, edge] of edgeLookup.value) {
|
||||
edgeIdLookup.value.set(edge.source, edgeIdLookup.value.get(edge.source)?.add(id) || new Set([id]))
|
||||
edgeIdLookup.value.set(edge.target, edgeIdLookup.value.get(edge.target)?.add(id) || new Set([id]))
|
||||
}
|
||||
|
||||
removeSelectedElements()
|
||||
|
||||
userSelectionRect.value = {
|
||||
@@ -138,43 +152,62 @@ function onPointerDown(event: PointerEvent) {
|
||||
}
|
||||
|
||||
function onPointerMove(event: PointerEvent) {
|
||||
if (!hasActiveSelection.value) {
|
||||
return emits.paneMouseMove(event)
|
||||
}
|
||||
|
||||
if (!containerBounds.value || !userSelectionRect.value) {
|
||||
return
|
||||
}
|
||||
|
||||
selectionInProgress.value = true
|
||||
|
||||
const mousePos = getMousePosition(event, containerBounds.value)
|
||||
const { x: mouseX, y: mouseY } = getEventPosition(event, containerBounds.value)
|
||||
const { startX = 0, startY = 0 } = userSelectionRect.value
|
||||
|
||||
const nextUserSelectRect = {
|
||||
...userSelectionRect.value,
|
||||
x: mousePos.x < startX ? mousePos.x : startX,
|
||||
y: mousePos.y < startY ? mousePos.y : startY,
|
||||
width: Math.abs(mousePos.x - startX),
|
||||
height: Math.abs(mousePos.y - startY),
|
||||
startX,
|
||||
startY,
|
||||
x: mouseX < startX ? mouseX : startX,
|
||||
y: mouseY < startY ? mouseY : startY,
|
||||
width: Math.abs(mouseX - startX),
|
||||
height: Math.abs(mouseY - startY),
|
||||
}
|
||||
|
||||
const selectedNodes = getNodesInside(
|
||||
getNodes.value,
|
||||
userSelectionRect.value,
|
||||
nextUserSelectRect,
|
||||
viewport.value,
|
||||
selectionMode.value === SelectionMode.Partial,
|
||||
true,
|
||||
)
|
||||
|
||||
const selectedEdges = getConnectedEdges(selectedNodes, getEdges.value)
|
||||
const selectedEdgeIds = new Set<string>()
|
||||
const selectedNodeIds = new Set<string>()
|
||||
|
||||
prevSelectedNodesCount.value = selectedNodes.length
|
||||
prevSelectedEdgesCount.value = selectedEdges.length
|
||||
for (const selectedNode of selectedNodes) {
|
||||
selectedNodeIds.add(selectedNode.id)
|
||||
|
||||
const edgeIds = edgeIdLookup.value.get(selectedNode.id)
|
||||
|
||||
if (edgeIds) {
|
||||
for (const edgeId of edgeIds) {
|
||||
selectedEdgeIds.add(edgeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prevSelectedNodesCount.value !== selectedNodeIds.size) {
|
||||
prevSelectedNodesCount.value = selectedNodeIds.size
|
||||
const changes = getSelectionChanges(nodeLookup.value, selectedNodeIds, true) as NodeChange[]
|
||||
emits.nodesChange(changes)
|
||||
}
|
||||
|
||||
if (prevSelectedEdgesCount.value !== selectedEdgeIds.size) {
|
||||
prevSelectedEdgesCount.value = selectedEdgeIds.size
|
||||
const changes = getSelectionChanges(edgeLookup.value, selectedEdgeIds)
|
||||
emits.edgesChange(changes)
|
||||
}
|
||||
|
||||
userSelectionRect.value = nextUserSelectRect
|
||||
|
||||
addSelectedElements([...selectedNodes, ...selectedEdges])
|
||||
userSelectionActive.value = true
|
||||
nodesSelectionActive.value = false
|
||||
}
|
||||
|
||||
function onPointerUp(event: PointerEvent) {
|
||||
@@ -184,10 +217,6 @@ function onPointerUp(event: PointerEvent) {
|
||||
|
||||
container.value?.releasePointerCapture(event.pointerId)
|
||||
|
||||
if (!hasActiveSelection.value) {
|
||||
return
|
||||
}
|
||||
|
||||
// We only want to trigger click functions when in selection mode if
|
||||
// the user did not move the mouse.
|
||||
if (!userSelectionActive.value && userSelectionRect.value && event.target === container.value) {
|
||||
@@ -206,14 +235,6 @@ function onPointerUp(event: PointerEvent) {
|
||||
selectionInProgress.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onPointerEnter(event: PointerEvent) {
|
||||
if (hasActiveSelection.value) {
|
||||
return
|
||||
}
|
||||
|
||||
emits.paneMouseEnter(event)
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -228,13 +249,14 @@ export default {
|
||||
ref="container"
|
||||
class="vue-flow__pane vue-flow__container"
|
||||
:class="{ selection: isSelecting }"
|
||||
@click="onClick"
|
||||
@contextmenu="onContextMenu"
|
||||
@wheel.passive="onWheel"
|
||||
@pointerenter="onPointerEnter"
|
||||
@pointerdown="onPointerDown"
|
||||
@pointermove="onPointerMove"
|
||||
@pointerup="onPointerUp"
|
||||
@click="(event) => (hasActiveSelection ? undefined : wrapHandler(onClick, container)(event))"
|
||||
@contextmenu="wrapHandler(onContextMenu, container)($event)"
|
||||
@wheel.passive="wrapHandler(onWheel, container)($event)"
|
||||
@pointerenter="(event) => (hasActiveSelection ? undefined : emits.paneMouseEnter(event))"
|
||||
@pointerdown="(event) => (hasActiveSelection ? onPointerDown(event) : emits.paneMouseMove(event))"
|
||||
@pointermove="(event) => (hasActiveSelection ? onPointerMove(event) : emits.paneMouseMove(event))"
|
||||
@pointerup="(event) => (hasActiveSelection ? onPointerUp(event) : undefined)"
|
||||
@pointerleave="emits.paneMouseLeave($event)"
|
||||
>
|
||||
<slot />
|
||||
<UserSelection v-if="userSelectionActive && userSelectionRect" :user-selection-rect="userSelectionRect" />
|
||||
|
||||
Reference in New Issue
Block a user