diff --git a/packages/react/src/container/Pane/index.tsx b/packages/react/src/container/Pane/index.tsx index 0c0eb122..17fe91b3 100644 --- a/packages/react/src/container/Pane/index.tsx +++ b/packages/react/src/container/Pane/index.tsx @@ -69,6 +69,8 @@ export function Pane({ const prevSelectedNodesCount = useRef(0); const prevSelectedEdgesCount = useRef(0); const containerBounds = useRef(); + const edgeIdLookup = useRef>>(new Map()); + const { userSelectionActive, elementsSelectable, dragging } = useStore(selector, shallow); const resetUserSelection = () => { @@ -96,7 +98,7 @@ export function Pane({ const onWheel = onPaneScroll ? (event: React.WheelEvent) => onPaneScroll(event) : undefined; const onMouseDown = (event: ReactMouseEvent): void => { - const { resetSelectedElements, domNode } = store.getState(); + const { resetSelectedElements, domNode, edgeLookup } = store.getState(); containerBounds.current = domNode?.getBoundingClientRect(); if ( @@ -109,6 +111,13 @@ export function Pane({ return; } + edgeIdLookup.current = new Map(); + + for (const [id, edge] of edgeLookup) { + edgeIdLookup.current.set(edge.source, edgeIdLookup.current.get(edge.source)?.add(id) || new Set([id])); + edgeIdLookup.current.set(edge.target, edgeIdLookup.current.get(edge.target)?.add(id) || new Set([id])); + } + const { x, y } = getEventPosition(event.nativeEvent, containerBounds.current); resetSelectedElements(); @@ -130,22 +139,21 @@ export function Pane({ const onMouseMove = (event: ReactMouseEvent): void => { const { userSelectionRect, edgeLookup, transform, nodeOrigin, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState(); + if (!isSelecting || !containerBounds.current || !userSelectionRect) { return; } - store.setState({ userSelectionActive: true, nodesSelectionActive: false }); - - const mousePos = getEventPosition(event.nativeEvent, containerBounds.current); - const startX = userSelectionRect.startX ?? 0; - const startY = userSelectionRect.startY ?? 0; + const { x: mouseX, y: mouseY } = getEventPosition(event.nativeEvent, containerBounds.current); + const { startX, startY } = userSelectionRect; const nextUserSelectRect = { - ...userSelectionRect, - 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( @@ -163,8 +171,10 @@ export function Pane({ for (const selectedNode of selectedNodes) { selectedNodeIds.add(selectedNode.id); - for (const [edgeId, edge] of edgeLookup) { - if (edge.source === selectedNode.id || edge.target === selectedNode.id) { + const edgeIds = edgeIdLookup.current.get(selectedNode.id); + + if (edgeIds) { + for (const edgeId of edgeIds) { selectedEdgeIds.add(edgeId); } } @@ -184,6 +194,8 @@ export function Pane({ store.setState({ userSelectionRect: nextUserSelectRect, + userSelectionActive: true, + nodesSelectionActive: false, }); }; diff --git a/packages/react/src/utils/changes.ts b/packages/react/src/utils/changes.ts index 44af2451..69b220f6 100644 --- a/packages/react/src/utils/changes.ts +++ b/packages/react/src/utils/changes.ts @@ -184,8 +184,8 @@ export function getSelectionChanges( ): NodeSelectionChange[] | EdgeSelectionChange[] { const changes: NodeSelectionChange[] | EdgeSelectionChange[] = []; - for (const [, item] of items) { - const willBeSelected = selectedIds.has(item.id); + for (const [id, item] of items) { + const willBeSelected = selectedIds.has(id); // we don't want to set all items to selected=false on the first selection if (!(item.selected === undefined && !willBeSelected) && item.selected !== willBeSelected) { diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 67a7c365..7611056c 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -92,11 +92,10 @@ export function adoptUserNodes( const selectedNodeZ: number = options?.elevateNodesOnSelect ? 1000 : 0; nodes.forEach((userNode) => { - const currentStoreNode = tmpLookup.get(userNode.id); + let internalNode = tmpLookup.get(userNode.id); - let internalNode = currentStoreNode!; - if (options.checkEquality && userNode === currentStoreNode?.internals.userNode) { - nodeLookup.set(userNode.id, currentStoreNode); + if (options.checkEquality && userNode === internalNode?.internals.userNode) { + nodeLookup.set(userNode.id, internalNode); } else { internalNode = { ...options.defaults, @@ -107,7 +106,7 @@ export function adoptUserNodes( }, internals: { positionAbsolute: userNode.position, - handleBounds: currentStoreNode?.internals.handleBounds, + handleBounds: internalNode?.internals.handleBounds, z: (isNumeric(userNode.zIndex) ? userNode.zIndex : 0) + (userNode.selected ? selectedNodeZ : 0), userNode, },