Merge pull request #214 from wbkd/develop
add horizontal flow, custom edges, interactive control
This commit is contained in:
@@ -199,6 +199,7 @@ edgeTypes={{
|
|||||||
|
|
||||||
You can now use type `special` for an edge.
|
You can now use type `special` for an edge.
|
||||||
The `straight`, `default` and `step` types will be still available except you overwrite one of them.
|
The `straight`, `default` and `step` types will be still available except you overwrite one of them.
|
||||||
|
There is an implementation of a custom edge in the [edges example](/example/src/Edges/index.js).
|
||||||
|
|
||||||
## Helper Functions
|
## Helper Functions
|
||||||
|
|
||||||
@@ -254,7 +255,7 @@ const GraphWithMiniMap = () => (
|
|||||||
|
|
||||||
### Controls
|
### Controls
|
||||||
|
|
||||||
The control panel contains a zoom-in, zoom-out and a fit-view button. You can use it by passing it as a children to your React Flow component:
|
The control panel contains a zoom-in, zoom-out, fit-view and a lock/unlock button. You can use it by passing it as a children to the React Flow component:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import ReactFlow, { Controls } from 'react-flow-renderer';
|
import ReactFlow, { Controls } from 'react-flow-renderer';
|
||||||
@@ -272,6 +273,9 @@ const GraphWithControls = () => (
|
|||||||
|
|
||||||
- `style`: css properties
|
- `style`: css properties
|
||||||
- `className`: class name
|
- `className`: class name
|
||||||
|
- `showZoom`: boolean - default: true
|
||||||
|
- `showFitView`: boolean - default: true
|
||||||
|
- `showInteractive`: boolean - default: true
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@@ -280,6 +284,7 @@ You can find all examples in the [example](example) folder or check out the live
|
|||||||
- [rich](https://react-flow.netlify.app/)
|
- [rich](https://react-flow.netlify.app/)
|
||||||
- [basic](https://react-flow.netlify.app/basic)
|
- [basic](https://react-flow.netlify.app/basic)
|
||||||
- [custom node](https://react-flow.netlify.app/custom-node)
|
- [custom node](https://react-flow.netlify.app/custom-node)
|
||||||
|
- [horizontal](https://react-flow.netlify.app/horizontal)
|
||||||
- [stress](https://react-flow.netlify.app/stress)
|
- [stress](https://react-flow.netlify.app/stress)
|
||||||
- [edges](https://react-flow.netlify.app/edges)
|
- [edges](https://react-flow.netlify.app/edges)
|
||||||
- [empty](https://react-flow.netlify.app/empty)
|
- [empty](https://react-flow.netlify.app/empty)
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M376 186h-20v-40c0-55-45-100-100-100S156 91 156 146v40h-20c-22.002 0-40 17.998-40 40v200c0 22.002 17.998 40 40 40h240c22.002 0 40-17.998 40-40V226c0-22.002-17.998-40-40-40zM256 368c-22.002 0-40-17.998-40-40s17.998-40 40-40 40 17.998 40 40-17.998 40-40 40zm62.002-182H193.998v-40c0-34.004 28.003-62.002 62.002-62.002 34.004 0 62.002 27.998 62.002 62.002v40z"/></svg>
|
||||||
|
After Width: | Height: | Size: 437 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="m376,187l-20,0l0,-40c0,-55 -45,-100 -100,-100c-54.002,23.996 -17.999,27.998 4,31.998c21.999,4 58.002,33.998 58.002,68.002l-0.002,0l0,40l-182,0c-22.002,0 -40,17.998 -40,40l0,200c0,22.002 17.998,40 40,40l240,0c22.002,0 40,-17.998 40,-40l0,-200c0,-22.002 -17.998,-40 -40,-40zm-120,182c-22.002,0 -40,-17.998 -40,-40s17.998,-40 40,-40s40,17.998 40,40s-17.998,40 -40,40z"/></svg>
|
||||||
|
After Width: | Height: | Size: 445 B |
@@ -13,7 +13,7 @@ describe('Empty Flow Rendering', () => {
|
|||||||
.get('.react-flow__selectionpane')
|
.get('.react-flow__selectionpane')
|
||||||
.trigger('mousedown', 'topLeft', { which: 1, force: true })
|
.trigger('mousedown', 'topLeft', { which: 1, force: true })
|
||||||
.trigger('mousemove', 'bottomRight', { which: 1 })
|
.trigger('mousemove', 'bottomRight', { which: 1 })
|
||||||
.trigger('mouseup', 'bottomRight', { force: true })
|
.trigger('mouseup', 'bottomRight', { force: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a control panel', () => {
|
it('renders a control panel', () => {
|
||||||
@@ -32,6 +32,10 @@ describe('Empty Flow Rendering', () => {
|
|||||||
cy.get('.react-flow__controls-fitview').click();
|
cy.get('.react-flow__controls-fitview').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses lock view control', () => {
|
||||||
|
cy.get('.react-flow__controls-interactive').click();
|
||||||
|
});
|
||||||
|
|
||||||
it('renders an empty mini map', () => {
|
it('renders an empty mini map', () => {
|
||||||
cy.get('.react-flow__minimap');
|
cy.get('.react-flow__minimap');
|
||||||
cy.get('.react-flow__minimap-node').should('not.exist');
|
cy.get('.react-flow__minimap-node').should('not.exist');
|
||||||
@@ -43,10 +47,7 @@ describe('Empty Flow Rendering', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('connects nodes', () => {
|
it('connects nodes', () => {
|
||||||
cy.get('.react-flow__node')
|
cy.get('.react-flow__node').first().find('.react-flow__handle.source').trigger('mousedown', { which: 1 });
|
||||||
.first()
|
|
||||||
.find('.react-flow__handle.source')
|
|
||||||
.trigger('mousedown', { which: 1 });
|
|
||||||
|
|
||||||
cy.get('.react-flow__node')
|
cy.get('.react-flow__node')
|
||||||
.last()
|
.last()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import ReactFlow, { removeElements, addEdge } from 'react-flow-renderer';
|
import Graph, { removeElements, addEdge } from 'react-flow-renderer';
|
||||||
|
|
||||||
const onNodeDragStop = node => console.log('drag stop', node);
|
const onNodeDragStop = node => console.log('drag stop', node);
|
||||||
const onLoad = graphInstance => console.log('graph loaded:', graphInstance);
|
const onLoad = graphInstance => console.log('graph loaded:', graphInstance);
|
||||||
@@ -11,7 +11,7 @@ const initialElements = [
|
|||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||||
{ id: 'e1-2', source: '1', target: '2', animated: true, label: 'edge text' },
|
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||||
{ id: 'e1-3', source: '1', target: '3' },
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ const BasicGraph = () => {
|
|||||||
const onConnect = (params) => setElements(els => addEdge(params, els));
|
const onConnect = (params) => setElements(els => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<Graph
|
||||||
elements={elements}
|
elements={elements}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
onElementClick={onElementClick}
|
onElementClick={onElementClick}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export default function CustomEdge({
|
||||||
|
id, sourceX, sourceY, targetX, targetY, label, style = {}
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<path id={id} style={style} className="react-flow__edge-path" d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`} />
|
||||||
|
<text>
|
||||||
|
<textPath href={`#${id}`} style={{ fontSize: '12px' }} startOffset="50%" textAnchor="middle">
|
||||||
|
{label}
|
||||||
|
</textPath>
|
||||||
|
</text>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -2,6 +2,8 @@ import React, { useState } from 'react';
|
|||||||
|
|
||||||
import ReactFlow, { removeElements, addEdge, MiniMap, Controls } from 'react-flow-renderer';
|
import ReactFlow, { removeElements, addEdge, MiniMap, Controls } from 'react-flow-renderer';
|
||||||
|
|
||||||
|
import CustomEdge from './CustomEdge';
|
||||||
|
|
||||||
const onNodeDragStop = node => console.log('drag stop', node);
|
const onNodeDragStop = node => console.log('drag stop', node);
|
||||||
const onElementClick = element => console.log('click', element);
|
const onElementClick = element => console.log('click', element);
|
||||||
const onLoad = (graph) => {
|
const onLoad = (graph) => {
|
||||||
@@ -9,14 +11,15 @@ const onLoad = (graph) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const initialElements = [
|
const initialElements = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Input Node 1' }, position: { x: 250, y: 0 } },
|
{ id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } },
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } },
|
{ id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } },
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
|
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
|
||||||
{ id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } },
|
{ id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } },
|
||||||
{ id: '5', data: { label: 'Node 5' }, position: { x: 450, y: 400 } },
|
{ id: '5', data: { label: 'Node 5' }, position: { x: 250, y: 400 } },
|
||||||
{ id: '6', type: 'output', data: { label: 'Output Node 5' }, position: { x: 250, y: 550 } },
|
{ id: '6', type: 'output', data: { label: 'Output 6' }, position: { x: 50, y: 550 } },
|
||||||
{ id: '7', type: 'output', data: { label: 'Output Node 6' }, position: { x: 550, y: 550 } },
|
{ id: '7', type: 'output', data: { label: 'Output 7' }, position: { x: 250, y: 550 } },
|
||||||
|
{ id: '8', type: 'output', data: { label: 'Output 8' }, position: { x: 525, y: 600 } },
|
||||||
{ id: 'e1-2', source: '1', target: '2', label: 'bezier edge' },
|
{ id: 'e1-2', source: '1', target: '2', label: 'bezier edge' },
|
||||||
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
||||||
{ id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' },
|
{ id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' },
|
||||||
@@ -24,6 +27,7 @@ const initialElements = [
|
|||||||
{ id: 'e3-5', source: '4', target: '5', animated: true, label: 'animated styled edge', style: { stroke: 'red' } },
|
{ id: 'e3-5', source: '4', target: '5', animated: true, label: 'animated styled edge', style: { stroke: 'red' } },
|
||||||
{ id: 'e5-6', source: '5', target: '6', label: 'styled label', labelStyle: { fill: 'red', fontWeight: 700 } },
|
{ id: 'e5-6', source: '5', target: '6', label: 'styled label', labelStyle: { fill: 'red', fontWeight: 700 } },
|
||||||
{ id: 'e5-7', source: '5', target: '7', label: 'label with styled bg', labelBgStyle: { fill: '#eee', fillOpacity: 0.7 } },
|
{ id: 'e5-7', source: '5', target: '7', label: 'label with styled bg', labelBgStyle: { fill: '#eee', fillOpacity: 0.7 } },
|
||||||
|
{ id: 'e5-8', source: '5', target: '8', type: 'custom', label: 'custom edge' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const EdgesFlow = () => {
|
const EdgesFlow = () => {
|
||||||
@@ -42,6 +46,9 @@ const EdgesFlow = () => {
|
|||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
snapToGrid={true}
|
snapToGrid={true}
|
||||||
|
edgeTypes={{
|
||||||
|
custom: CustomEdge
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<MiniMap />
|
<MiniMap />
|
||||||
<Controls />
|
<Controls />
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
import ReactFlow, { removeElements, addEdge } from 'react-flow-renderer';
|
||||||
|
|
||||||
|
const onLoad = (graph) => {
|
||||||
|
graph.fitView();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialElements = [
|
||||||
|
{ id: '1', sourcePosition: 'right', type: 'input', data: { label: 'Input' }, position: { x: 0, y: 80 } },
|
||||||
|
{ id: '2', sourcePosition: 'right', targetPosition: 'left', data: { label: 'A Node' }, position: { x: 250, y: 0 } },
|
||||||
|
{ id: '3', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Another node' }, position: { x: 250, y: 160 } },
|
||||||
|
{ id: '4', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Node 4' }, position: { x: 500, y: 80 } },
|
||||||
|
{ id: 'e1-2', source: '1', target: '2', animated: true, },
|
||||||
|
{ id: 'e1-3', source: '1', target: '3', animated: true, },
|
||||||
|
{ id: 'e1-4', source: '2', target: '4', label: 'edge label' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const HorizontalFlow = () => {
|
||||||
|
const [elements, setElements] = useState(initialElements);
|
||||||
|
const onElementsRemove = (elementsToRemove) =>
|
||||||
|
setElements(els => removeElements(elementsToRemove, els));
|
||||||
|
const onConnect = (params) => setElements(els => addEdge(params, els));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReactFlow
|
||||||
|
elements={elements}
|
||||||
|
onElementsRemove={onElementsRemove}
|
||||||
|
onConnect={onConnect}
|
||||||
|
onLoad={onLoad}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HorizontalFlow;
|
||||||
@@ -9,6 +9,7 @@ import Stress from './Stress';
|
|||||||
import Inactive from './Inactive';
|
import Inactive from './Inactive';
|
||||||
import Empty from './Empty';
|
import Empty from './Empty';
|
||||||
import Edges from './Edges';
|
import Edges from './Edges';
|
||||||
|
import Horizontal from './Horizontal';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
@@ -28,6 +29,10 @@ const routes = [{
|
|||||||
path: '/custom-node',
|
path: '/custom-node',
|
||||||
component: CustomNode,
|
component: CustomNode,
|
||||||
label: 'CustomNode'
|
label: 'CustomNode'
|
||||||
|
}, {
|
||||||
|
path: '/horizontal',
|
||||||
|
component: Horizontal,
|
||||||
|
label: 'Horizontal'
|
||||||
}, {
|
}, {
|
||||||
path: '/stress',
|
path: '/stress',
|
||||||
component: Stress,
|
component: Stress,
|
||||||
|
|||||||
+13
-12
@@ -9,6 +9,19 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/wbkd/react-flow.git"
|
"url": "https://github.com/wbkd/react-flow.git"
|
||||||
},
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "rollup -c --environment NODE_ENV:production",
|
||||||
|
"start": "rollup -w -c",
|
||||||
|
"dev": "npm run build && npm start & cd example && npm start",
|
||||||
|
"start:examples": "npm run build && cd example && npm start",
|
||||||
|
"dev:wait": "start-server-and-test start:examples http-get://localhost:3000",
|
||||||
|
"build:example": "npm install && npm run build && cd example && npm install && npm run build",
|
||||||
|
"cy:run": "cypress run",
|
||||||
|
"cy:open": "cypress open",
|
||||||
|
"cypress": "npm run dev:wait cy:open",
|
||||||
|
"test": "npm run dev:wait cy:run",
|
||||||
|
"release": "release-it"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welldone-software/why-did-you-render": "^4.2.0",
|
"@welldone-software/why-did-you-render": "^4.2.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
@@ -56,18 +69,6 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.13.1"
|
"react": "^16.13.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
|
||||||
"build": "rollup -c --environment NODE_ENV:production",
|
|
||||||
"start": "rollup -w -c",
|
|
||||||
"dev": "npm run build && npm start & cd example && npm start",
|
|
||||||
"dev:wait": "start-server-and-test dev http-get://localhost:3000",
|
|
||||||
"build:example": "npm install && npm run build && cd example && npm install && npm run build",
|
|
||||||
"cy:run": "cypress run",
|
|
||||||
"cy:open": "cypress open",
|
|
||||||
"cypress": "npm run dev:wait cy:open",
|
|
||||||
"test": "npm run dev:wait cy:run",
|
|
||||||
"release": "release-it"
|
|
||||||
},
|
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ const GraphView = memo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const size = getDimensions(rendererNode.current);
|
const size = getDimensions(rendererNode.current);
|
||||||
|
|
||||||
|
if (size.height === 0 || size.width === 0) {
|
||||||
|
throw new Error('The React Flow parent container needs a width and a height to render the graph.');
|
||||||
|
}
|
||||||
|
|
||||||
updateSize(size);
|
updateSize(size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
|||||||
const ReactFlow = ({
|
const ReactFlow = ({
|
||||||
style,
|
style,
|
||||||
onElementClick,
|
onElementClick,
|
||||||
elements,
|
elements = [],
|
||||||
children,
|
children,
|
||||||
nodeTypes,
|
nodeTypes,
|
||||||
edgeTypes,
|
edgeTypes,
|
||||||
|
|||||||
+2
-7
@@ -3,12 +3,7 @@ import ReactFlow from './container/ReactFlow';
|
|||||||
export default ReactFlow;
|
export default ReactFlow;
|
||||||
|
|
||||||
export { default as Handle } from './components/Handle';
|
export { default as Handle } from './components/Handle';
|
||||||
|
export { default as EdgeText } from './components/Edges/EdgeText';
|
||||||
export { MiniMap, Controls } from './plugins';
|
export { MiniMap, Controls } from './plugins';
|
||||||
|
|
||||||
export {
|
export { isNode, isEdge, removeElements, addEdge, getOutgoers } from './utils/graph';
|
||||||
isNode,
|
|
||||||
isEdge,
|
|
||||||
removeElements,
|
|
||||||
addEdge,
|
|
||||||
getOutgoers,
|
|
||||||
} from './utils/graph';
|
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ import React, { CSSProperties } from 'react';
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
||||||
|
import { useStoreState, useStoreActions } from '../../store/hooks';
|
||||||
|
|
||||||
import PlusIcon from '../../../assets/icons/plus.svg';
|
import PlusIcon from '../../../assets/icons/plus.svg';
|
||||||
import MinusIcon from '../../../assets/icons/minus.svg';
|
import MinusIcon from '../../../assets/icons/minus.svg';
|
||||||
import FitviewIcon from '../../../assets/icons/fitview.svg';
|
import FitviewIcon from '../../../assets/icons/fitview.svg';
|
||||||
|
import LockIcon from '../../../assets/icons/lock.svg';
|
||||||
|
import UnlockIcon from '../../../assets/icons/unlock.svg';
|
||||||
|
|
||||||
const baseStyle: CSSProperties = {
|
const baseStyle: CSSProperties = {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -13,11 +17,18 @@ const baseStyle: CSSProperties = {
|
|||||||
left: 10,
|
left: 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {}
|
interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
|
showZoom?: boolean;
|
||||||
|
showFitView?: boolean;
|
||||||
|
showInteractive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export default ({ style, className }: ControlProps) => {
|
export default ({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
||||||
const mapClasses: string = classnames('react-flow__controls', className);
|
const mapClasses: string = classnames('react-flow__controls', className);
|
||||||
|
|
||||||
|
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
||||||
|
const { isInteractive } = useStoreState(({ isInteractive }) => ({ isInteractive }));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={mapClasses}
|
className={mapClasses}
|
||||||
@@ -26,24 +37,29 @@ export default ({ style, className }: ControlProps) => {
|
|||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
{showZoom && (
|
||||||
className="react-flow__controls-button react-flow__controls-zoomin"
|
<>
|
||||||
onClick={zoomIn}
|
<div className="react-flow__controls-button react-flow__controls-zoomin" onClick={zoomIn}>
|
||||||
>
|
<PlusIcon />
|
||||||
<PlusIcon />
|
</div>
|
||||||
</div>
|
<div className="react-flow__controls-button react-flow__controls-zoomout" onClick={zoomOut}>
|
||||||
<div
|
<MinusIcon />
|
||||||
className="react-flow__controls-button react-flow__controls-zoomout"
|
</div>
|
||||||
onClick={zoomOut}
|
</>
|
||||||
>
|
)}
|
||||||
<MinusIcon />
|
{showFitView && (
|
||||||
</div>
|
<div className="react-flow__controls-button react-flow__controls-fitview" onClick={() => fitView()}>
|
||||||
<div
|
<FitviewIcon />
|
||||||
className="react-flow__controls-button react-flow__controls-fitview"
|
</div>
|
||||||
onClick={() => fitView()}
|
)}
|
||||||
>
|
{showInteractive && (
|
||||||
<FitviewIcon />
|
<div
|
||||||
</div>
|
className="react-flow__controls-button react-flow__controls-interactive"
|
||||||
|
onClick={() => setInteractive(!isInteractive)}
|
||||||
|
>
|
||||||
|
{isInteractive ? <UnlockIcon /> : <LockIcon />}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user