From 4cbbf97c965fc82cbb15f709dd1b7b23f12ff6cb Mon Sep 17 00:00:00 2001 From: moklick Date: Sat, 22 Aug 2020 17:24:50 +0200 Subject: [PATCH] feat(selection): add drag handlers closes #444 --- README.md | 3 ++ example/src/Overview/index.js | 6 ++++ src/components/NodesSelection/index.tsx | 37 +++++++++++++++++++++++-- src/container/GraphView/index.tsx | 14 +++++++++- src/container/ReactFlow/index.tsx | 9 ++++++ 5 files changed, 65 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 99977a9c..0025d701 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,9 @@ const BasicFlow = () => ; - `onMoveStart()`: called when user starts panning or zooming - `onMoveEnd()`: called when user ends panning or zooming - `onSelectionChange(elements: Elements)`: called when user selects one or multiple elements +- `onSelectionDragStart(evt: MouseEvent, nodes: Node[])`: called when user starts to drag a selection +- `onSelectionDrag(evt: MouseEvent, nodes: Node[])`: called when user drags a selection +- `onSelectionDragStop(evt: MouseEvent, nodes: Node[])`: called when user stops to drag a selection - `onPaneClick(event: MouseEvent)`: called when user clicks directly on the canvas - `onPaneContextMenu(event: MouseEvent)`: called when user does a right-click on the canvas diff --git a/example/src/Overview/index.js b/example/src/Overview/index.js index b08ede0a..045d5684 100644 --- a/example/src/Overview/index.js +++ b/example/src/Overview/index.js @@ -4,6 +4,9 @@ import ReactFlow, { removeElements, addEdge, MiniMap, Controls, Background, isNo const onNodeDragStart = (event, node) => console.log('drag start', node); const onNodeDragStop = (event, node) => console.log('drag stop', node); +const onSelectionDrag = (event, nodes) => console.log('selection drag', nodes); +const onSelectionDragStart = (event, nodes) => console.log('selection drag start', nodes); +const onSelectionDragStop = (event, nodes) => console.log('selection drag stop', nodes); const onElementClick = (event, element) => console.log(`${isNode(element) ? 'node' : 'edge'} click:`, element); const onSelectionChange = (elements) => console.log('selection change', elements); const onLoad = (reactFlowInstance) => { @@ -120,6 +123,9 @@ const OverviewFlow = () => { onConnect={onConnect} onNodeDragStart={onNodeDragStart} onNodeDragStop={onNodeDragStop} + onSelectionDragStart={onSelectionDragStart} + onSelectionDrag={onSelectionDrag} + onSelectionDragStop={onSelectionDragStop} onSelectionChange={onSelectionChange} onMoveEnd={onMoveEnd} onLoad={onLoad} diff --git a/src/components/NodesSelection/index.tsx b/src/components/NodesSelection/index.tsx index 48db9bf3..1aaa2053 100644 --- a/src/components/NodesSelection/index.tsx +++ b/src/components/NodesSelection/index.tsx @@ -3,7 +3,7 @@ * made a selectio with on or several nodes */ -import React, { useState } from 'react'; +import React, { useState, MouseEvent } from 'react'; import ReactDraggable from 'react-draggable'; import { useStoreState, useStoreActions } from '../../store/hooks'; @@ -27,7 +27,13 @@ function getStartPositions(nodes: Node[]): StartPositions { }, startPositions); } -export default () => { +export interface NodesSelectionProps { + onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void; + onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void; + onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void; +} + +export default ({ onSelectionDragStart, onSelectionDrag, onSelectionDragStop }: NodesSelectionProps) => { const [offset, setOffset] = useState({ x: 0, y: 0 }); const [startPositions, setStartPositions] = useState({}); @@ -61,6 +67,10 @@ export default () => { const nextStartPositions = getStartPositions(selectedNodes); + if (onSelectionDragStart) { + onSelectionDragStart(event, selectedNodes); + } + if (nextStartPositions) { setOffset({ x: offsetX, y: offsetY }); setStartPositions(nextStartPositions); @@ -74,7 +84,17 @@ export default () => { }; if (selectedElements) { - selectedElements.filter(isNode).forEach((node) => { + const selectedNodes = selectedElements ? selectedElements.filter(isNode) : []; + + if (onSelectionDrag) { + const selectionNodes = selectedNodes.map( + (selectedNode) => nodes.find((node) => node.id === selectedNode.id)! as Node + ); + + onSelectionDrag(event, selectionNodes); + } + + selectedNodes.forEach((node) => { const pos: XYPosition = { x: startPositions[node.id].x + scaledClient.x - selectedNodesBbox.x - offset.x - tX, y: startPositions[node.id].y + scaledClient.y - selectedNodesBbox.y - offset.y - tY, @@ -85,6 +105,16 @@ export default () => { } }; + const onStop = (event: MouseEvent) => { + if (selectedElements && onSelectionDragStop) { + const selectedNodes = selectedElements + ? selectedElements.filter(isNode).map((selectedNode) => nodes.find((node) => node.id === selectedNode.id)!) + : []; + + onSelectionDragStop(event, selectedNodes); + } + }; + return (
{ grid={grid} onStart={(event) => onStart(event as MouseEvent)} onDrag={(event) => onDrag(event as MouseEvent)} + onStop={(event) => onStop(event as MouseEvent)} >
void; onPaneClick?: (event: MouseEvent) => void; onPaneContextMenu?: (event: MouseEvent) => void; + onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void; + onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void; + onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void; selectionKeyCode: number; nodeTypes: NodeTypesType; edgeTypes: EdgeTypesType; @@ -84,6 +87,9 @@ const GraphView = ({ onNodeContextMenu, onNodeDragStart, onNodeDragStop, + onSelectionDragStart, + onSelectionDrag, + onSelectionDragStop, connectionLineType, connectionLineStyle, selectionKeyCode, @@ -262,7 +268,13 @@ const GraphView = ({ markerEndId={markerEndId} /> - {nodesSelectionActive && } + {nodesSelectionActive && ( + + )}
, 'on onMoveStart?: (flowTransform?: FlowTransform) => void; onMoveEnd?: (flowTransform?: FlowTransform) => void; onSelectionChange?: (elements: Elements | null) => void; + onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void; + onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void; + onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void; onPaneClick?: (event: MouseEvent) => void; onPaneContextMenu?: (event: MouseEvent) => void; nodeTypes: NodeTypesType; @@ -103,6 +106,9 @@ const ReactFlow = ({ onNodeDragStart, onNodeDragStop, onSelectionChange, + onSelectionDragStart, + onSelectionDrag, + onSelectionDragStop, connectionLineType, connectionLineStyle, deleteKeyCode, @@ -175,6 +181,9 @@ const ReactFlow = ({ paneMoveable={paneMoveable} onPaneClick={onPaneClick} onPaneContextMenu={onPaneContextMenu} + onSelectionDragStart={onSelectionDragStart} + onSelectionDrag={onSelectionDrag} + onSelectionDragStop={onSelectionDragStop} /> {onSelectionChange && } {children}