Merge pull request #466 from wbkd/develop

Develop
This commit is contained in:
Moritz
2020-08-28 20:57:18 +02:00
committed by GitHub
11 changed files with 163 additions and 88 deletions

View File

@@ -97,6 +97,9 @@ const BasicFlow = () => <ReactFlow elements={elements} />;
- `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
@@ -230,6 +233,10 @@ Your custom nodes are wrapped so that the basic functions like dragging or selec
- `sourcePosition`: string
- `targetPosition`: string
### Prevent dragging
If you have controls inside your custom node that should not drag the node you can add the class name `nodrag`.
## Handle Component
We export a `Handle` component as a helper for your custom nodes:
@@ -422,6 +429,7 @@ const FlowWithMiniMap = () => (
- `nodeColor`: string or function - If you pass a color as a string all nodes will get that color. If you pass a function you can return a color depending on the passed node.
- `nodeBorderRadius`: number
- `nodeClassName`: string or function for adding an additional class to the nodes inside the mini map
- `maskColor`: string
- `style`: css properties
- `className`: additional class name
@@ -568,6 +576,11 @@ Returns all direct child nodes of the passed node
`getOutgoers = (node: Node, elements: Elements): Node[]`
### getConnectedEdges
Returns all edges that are connected to the passed nodes
`getConnectedEdges = (nodes: Node[], edges: Edge[]): Edge[]`
You can use these function as seen in [this example](/example/src/Overview/index.js#L40-L41) or use your own ones.

View File

@@ -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}

139
package-lock.json generated
View File

@@ -57,16 +57,16 @@
}
},
"@babel/core": {
"version": "7.11.1",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz",
"integrity": "sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==",
"version": "7.11.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz",
"integrity": "sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.11.0",
"@babel/generator": "^7.11.4",
"@babel/helper-module-transforms": "^7.11.0",
"@babel/helpers": "^7.10.4",
"@babel/parser": "^7.11.1",
"@babel/parser": "^7.11.4",
"@babel/template": "^7.10.4",
"@babel/traverse": "^7.11.0",
"@babel/types": "^7.11.0",
@@ -90,9 +90,9 @@
}
},
"@babel/generator": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz",
"integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==",
"version": "7.11.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz",
"integrity": "sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g==",
"dev": true,
"requires": {
"@babel/types": "^7.11.0",
@@ -191,9 +191,9 @@
}
},
"@babel/parser": {
"version": "7.11.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.3.tgz",
"integrity": "sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA==",
"version": "7.11.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz",
"integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA==",
"dev": true
},
"@babel/template": {
@@ -1531,9 +1531,9 @@
}
},
"@babel/parser": {
"version": "7.11.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.3.tgz",
"integrity": "sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA==",
"version": "7.11.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz",
"integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA==",
"dev": true
},
"@babel/template": {
@@ -4240,9 +4240,9 @@
}
},
"@octokit/types": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.4.0.tgz",
"integrity": "sha512-D/uotqF69M50OIlwMqgyIg9PuLT2daOiBAYF0P40I2ekFA2ESwwBY5dxZe/UhXdPvIbNKDzuZmQrO7rMpuFbcg==",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.4.1.tgz",
"integrity": "sha512-OlMlSySBJoJ6uozkr/i03nO5dlYQyE05vmQNZhAh9MyO4DPBP88QlwsDVLmVjIMFssvIZB6WO0ctIGMRG+xsJQ==",
"dev": true,
"requires": {
"@types/node": ">= 8"
@@ -4277,9 +4277,9 @@
}
},
"@sindresorhus/is": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.1.tgz",
"integrity": "sha512-tLnujxFtfH7F+i5ghUfgGlJsvyCKvUnSMFMlWybFdX9/DdX8svb4Zwx1gV0gkkVCHXtmPSetoAR3QlKfOld6Tw==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.2.tgz",
"integrity": "sha512-JiX9vxoKMmu8Y3Zr2RVathBL1Cdu4Nt4MuNWemt1Nc06A0RAin9c5FArkhGsyMBWfCu4zj+9b+GxtjAnE4qqLQ==",
"dev": true
},
"@svgr/babel-plugin-add-jsx-attribute": {
@@ -6952,70 +6952,69 @@
}
},
"d3-color": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz",
"integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg=="
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
"integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
},
"d3-dispatch": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.5.tgz",
"integrity": "sha512-vwKx+lAqB1UuCeklr6Jh1bvC4SZgbSqbkGBLClItFBIYH4vqDJCA7qfoy14lXmJdnBOdxndAMxjCbImJYW7e6g=="
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz",
"integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA=="
},
"d3-drag": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.4.tgz",
"integrity": "sha512-ICPurDETFAelF1CTHdIyiUM4PsyZLaM+7oIBhmyP+cuVjze5vDZ8V//LdOFjg0jGnFIZD/Sfmk0r95PSiu78rw==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz",
"integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==",
"requires": {
"d3-dispatch": "1",
"d3-selection": "1"
"d3-dispatch": "1 - 2",
"d3-selection": "2"
}
},
"d3-ease": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.5.tgz",
"integrity": "sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ=="
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz",
"integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ=="
},
"d3-interpolate": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.3.2.tgz",
"integrity": "sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
"integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
"requires": {
"d3-color": "1"
"d3-color": "1 - 2"
}
},
"d3-selection": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
"integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz",
"integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA=="
},
"d3-timer": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.9.tgz",
"integrity": "sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg=="
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz",
"integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA=="
},
"d3-transition": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.2.0.tgz",
"integrity": "sha512-VJ7cmX/FPIPJYuaL2r1o1EMHLttvoIuZhhuAlRoOxDzogV8iQS6jYulDm3xEU3TqL80IZIhI551/ebmCMrkvhw==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz",
"integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==",
"requires": {
"d3-color": "1",
"d3-dispatch": "1",
"d3-ease": "1",
"d3-interpolate": "1",
"d3-selection": "^1.1.0",
"d3-timer": "1"
"d3-color": "1 - 2",
"d3-dispatch": "1 - 2",
"d3-ease": "1 - 2",
"d3-interpolate": "1 - 2",
"d3-timer": "1 - 2"
}
},
"d3-zoom": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz",
"integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz",
"integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==",
"requires": {
"d3-dispatch": "1",
"d3-drag": "1",
"d3-interpolate": "1",
"d3-selection": "1",
"d3-transition": "1"
"d3-dispatch": "1 - 2",
"d3-drag": "2",
"d3-interpolate": "1 - 2",
"d3-selection": "2",
"d3-transition": "2"
}
},
"dashdash": {
@@ -11038,9 +11037,9 @@
}
},
"release-it": {
"version": "13.6.8",
"resolved": "https://registry.npmjs.org/release-it/-/release-it-13.6.8.tgz",
"integrity": "sha512-LY3dZEzAVRBdie0DMG0kdV4DWMTVPM+hvc5O5EmY0qIf+zPuMVu9QXS19La6KBhCI4kVhpwm7VZ8B7YMXTBKLA==",
"version": "13.6.9",
"resolved": "https://registry.npmjs.org/release-it/-/release-it-13.6.9.tgz",
"integrity": "sha512-bZEJBMCHiBPzKVZzCTYaGo+lYpunsX1/LSL1bO5RJ2+7G1glC91G5KIs29zgfHJEQfzE0q3tTEVV+b6gscGKvw==",
"dev": true,
"requires": {
"@iarna/toml": "2.2.5",
@@ -11354,9 +11353,9 @@
}
},
"rollup": {
"version": "2.26.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.4.tgz",
"integrity": "sha512-6+qsGuP0MXGd7vlYmk72utm1MrgZj5GfXibGL+cRkKQ9+ZL/BnFThDl0D5bcl7AqlzMjAQXRAwZX1HVm22M/4Q==",
"version": "2.26.5",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.5.tgz",
"integrity": "sha512-rCyFG3ZtQdnn9YwfuAVH0l/Om34BdO5lwCA0W6Hq+bNB21dVEBbCRxhaHOmu1G7OBFDWytbzAC104u7rxHwGjA==",
"dev": true,
"requires": {
"fsevents": "~2.1.2"
@@ -12364,9 +12363,9 @@
}
},
"typescript": {
"version": "3.9.7",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
"integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==",
"dev": true
},
"uglify-js": {

View File

@@ -27,15 +27,15 @@
"dependencies": {
"@welldone-software/why-did-you-render": "^4.3.1",
"classcat": "^4.1.0",
"d3-selection": "^1.4.2",
"d3-zoom": "^1.8.3",
"d3-selection": "^2.0.0",
"d3-zoom": "^2.0.0",
"easy-peasy": "^3.3.1",
"fast-deep-equal": "^3.1.3",
"react-draggable": "^4.4.3",
"resize-observer": "^1.0.0"
},
"devDependencies": {
"@babel/core": "^7.11.1",
"@babel/core": "^7.11.4",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"@svgr/rollup": "^5.4.0",
@@ -51,8 +51,8 @@
"prettier": "2.0.5",
"prop-types": "^15.7.2",
"react": "^16.13.1",
"release-it": "^13.6.8",
"rollup": "^2.26.4",
"release-it": "^13.6.9",
"rollup": "^2.26.5",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-bundle-size": "^1.0.3",
"rollup-plugin-commonjs": "^10.1.0",
@@ -66,7 +66,7 @@
"rollup-plugin-typescript2": "^0.27.2",
"rollup-plugin-uglify": "^6.0.4",
"start-server-and-test": "^1.11.3",
"typescript": "^3.9.7"
"typescript": "^4.0.2"
},
"peerDependencies": {
"react": "^16.13.1"

View File

@@ -1,4 +1,5 @@
import React, { memo, CSSProperties } from 'react';
import cc from 'classcat';
interface MiniMapNodeProps {
x: number;
@@ -6,17 +7,18 @@ interface MiniMapNodeProps {
width: number;
height: number;
color: string;
className: string;
borderRadius: number;
style?: CSSProperties;
}
const MiniMapNode = ({ x, y, width, height, style, color, borderRadius }: MiniMapNodeProps) => {
const MiniMapNode = ({ x, y, width, height, style, color, className, borderRadius }: MiniMapNodeProps) => {
const { background, backgroundColor } = style || {};
const fill = (color || background || backgroundColor) as string;
return (
<rect
className="react-flow__minimap-node"
className={cc(['react-flow__minimap-node', className])}
x={x}
y={y}
rx={borderRadius}

View File

@@ -12,6 +12,7 @@ type StringFunc = (node: Node) => string;
interface MiniMapProps extends React.HTMLAttributes<SVGSVGElement> {
nodeColor?: string | StringFunc;
nodeClassName?: string | StringFunc;
nodeBorderRadius?: number;
maskColor?: string;
}
@@ -23,6 +24,7 @@ const MiniMap = ({
style = { backgroundColor: '#f8f8f8' },
className,
nodeColor = '#ddd',
nodeClassName = '',
nodeBorderRadius = 5,
maskColor = 'rgba(10, 10, 10, .25)',
}: MiniMapProps) => {
@@ -35,6 +37,7 @@ const MiniMap = ({
const elementWidth = (style.width || defaultWidth)! as number;
const elementHeight = (style.height || defaultHeight)! as number;
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
const nodeClassNameFunc = (nodeClassName instanceof Function ? nodeClassName : () => nodeClassName) as StringFunc;
const hasNodes = nodes && nodes.length;
const bb = getRectOfNodes(nodes);
const viewBB: Rect = {
@@ -73,6 +76,7 @@ const MiniMap = ({
width={node.__rf.width}
height={node.__rf.height}
style={node.style}
className={nodeClassNameFunc(node)}
color={nodeColorFunc(node)}
borderRadius={nodeBorderRadius}
/>

View File

@@ -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<XYPosition>({ x: 0, y: 0 });
const [startPositions, setStartPositions] = useState<StartPositions>({});
@@ -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 (
<div
className="react-flow__nodesselection"
@@ -97,6 +127,7 @@ export default () => {
grid={grid}
onStart={(event) => onStart(event as MouseEvent)}
onDrag={(event) => onDrag(event as MouseEvent)}
onStop={(event) => onStop(event as MouseEvent)}
>
<div
className="react-flow__nodesselection-rect"

View File

@@ -46,6 +46,9 @@ export interface GraphViewProps {
onMoveEnd?: (flowTransform?: FlowTransform) => 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}
/>
<UserSelection selectionKeyPressed={selectionKeyPressed} />
{nodesSelectionActive && <NodesSelection />}
{nodesSelectionActive && (
<NodesSelection
onSelectionDragStart={onSelectionDragStart}
onSelectionDrag={onSelectionDrag}
onSelectionDragStop={onSelectionDragStop}
/>
)}
<div
className="react-flow__zoompane"
onClick={onZoomPaneClick}

View File

@@ -53,6 +53,9 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, '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 && <SelectionListener onSelectionChange={onSelectionChange} />}
{children}

View File

@@ -1,5 +1,4 @@
import { useEffect, useRef, MutableRefObject } from 'react';
import { event } from 'd3-selection';
import { useStoreState, useStoreActions } from '../store/hooks';
import { FlowTransform } from '../types';
@@ -53,7 +52,7 @@ export default ({
if (selectionKeyPressed) {
d3Zoom.on('zoom', null);
} else {
d3Zoom.on('zoom', () => {
d3Zoom.on('zoom', (event: any) => {
updateTransform(event.transform);
if (onMove) {
@@ -68,7 +67,7 @@ export default ({
useEffect(() => {
if (d3Zoom) {
if (onMoveStart) {
d3Zoom.on('start', () => {
d3Zoom.on('start', (event: any) => {
if (viewChanged(prevTransform.current, event.transform)) {
const flowTransform = eventToFlowTransform(event.transform);
prevTransform.current = flowTransform;
@@ -85,7 +84,7 @@ export default ({
useEffect(() => {
if (d3Zoom) {
if (onMoveEnd) {
d3Zoom.on('end', () => {
d3Zoom.on('end', (event: any) => {
if (viewChanged(prevTransform.current, event.transform)) {
const flowTransform = eventToFlowTransform(event.transform);
prevTransform.current = flowTransform;
@@ -101,7 +100,7 @@ export default ({
useEffect(() => {
if (d3Zoom) {
d3Zoom.filter(() => {
d3Zoom.filter((event: any) => {
if (!paneMoveable) {
return false;
}

View File

@@ -8,7 +8,7 @@ export { getBezierPath } from './components/Edges/BezierEdge';
export { getSmoothStepPath } from './components/Edges/SmoothStepEdge';
export { getMarkerEnd, getCenter as getEdgeCenter } from './components/Edges/utils';
export { isNode, isEdge, removeElements, addEdge, getOutgoers } from './utils/graph';
export { isNode, isEdge, removeElements, addEdge, getOutgoers, getConnectedEdges } from './utils/graph';
export * from './additional-components';
export * from './types';