@@ -509,8 +509,8 @@ The React Flow wrapper has the className `react-flow`. If you want to change the
|
|||||||
### Used Class Names
|
### Used Class Names
|
||||||
|
|
||||||
* `.react-flow` - Outer container
|
* `.react-flow` - Outer container
|
||||||
* `.react-flow__renderer` - Inner container
|
* `.react-flow__renderer` - Flow container, used for zooming and panning
|
||||||
* `.react-flow__zoompane` - Zoom & pan pane
|
* `.react-flow__pane` - Background Pane for click and wheel events, previously `.react-flow__zoompane`
|
||||||
* `.react-flow__selectionpane` - Selection pane
|
* `.react-flow__selectionpane` - Selection pane
|
||||||
* `.react-flow__selection` - User selection
|
* `.react-flow__selection` - User selection
|
||||||
* `.react-flow__edges` - Edges wrapper
|
* `.react-flow__edges` - Edges wrapper
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ describe('Basic Flow Rendering', () => {
|
|||||||
// for d3 we have to pass the window to the event
|
// for d3 we have to pass the window to the event
|
||||||
// https://github.com/cypress-io/cypress/issues/3441
|
// https://github.com/cypress-io/cypress/issues/3441
|
||||||
cy.window().then((win) => {
|
cy.window().then((win) => {
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.trigger('mousedown', 'topLeft', { which: 1, view: win })
|
.trigger('mousedown', 'topLeft', { which: 1, view: win })
|
||||||
.trigger('mousemove', 'bottomLeft')
|
.trigger('mousemove', 'bottomLeft')
|
||||||
.trigger('mouseup', { force: true, view: win })
|
.trigger('mouseup', { force: true, view: win })
|
||||||
@@ -133,7 +133,7 @@ describe('Basic Flow Rendering', () => {
|
|||||||
it('zooms the pane', () => {
|
it('zooms the pane', () => {
|
||||||
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
|
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.trigger('wheel', 'topLeft', { deltaY: -200 })
|
.trigger('wheel', 'topLeft', { deltaY: -200 })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ describe('Controls Testing', () => {
|
|||||||
// for d3 we have to pass the window to the event
|
// for d3 we have to pass the window to the event
|
||||||
// https://github.com/cypress-io/cypress/issues/3441
|
// https://github.com/cypress-io/cypress/issues/3441
|
||||||
cy.window().then((win) => {
|
cy.window().then((win) => {
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.trigger('mousedown', 'topLeft', { which: 1, view: win })
|
.trigger('mousedown', 'topLeft', { which: 1, view: win })
|
||||||
.trigger('mousemove', 'bottomLeft')
|
.trigger('mousemove', 'bottomLeft')
|
||||||
.trigger('mouseup', { force: true, view: win })
|
.trigger('mouseup', { force: true, view: win })
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ describe('Empty Flow Rendering', () => {
|
|||||||
.trigger('mousedown', 'topLeft', { which: 1, force: true })
|
.trigger('mousedown', 'topLeft', { which: 1, force: true })
|
||||||
.trigger('mousemove', 'bottomLeft', { which: 1 })
|
.trigger('mousemove', 'bottomLeft', { which: 1 })
|
||||||
.trigger('mouseup', 'bottomLeft', { force: true });
|
.trigger('mouseup', 'bottomLeft', { force: true });
|
||||||
|
|
||||||
|
cy.get('body').type('{shift}', { release: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an empty mini map', () => {
|
it('renders an empty mini map', () => {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ describe('Interaction Flow Rendering', () => {
|
|||||||
it('tries to zoom by scroll', () => {
|
it('tries to zoom by scroll', () => {
|
||||||
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
|
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.dblclick()
|
.dblclick()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
@@ -63,7 +63,7 @@ describe('Interaction Flow Rendering', () => {
|
|||||||
it('tries to zoom by double click', () => {
|
it('tries to zoom by double click', () => {
|
||||||
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
|
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.trigger('wheel', 'topLeft', { deltaY: -200 })
|
.trigger('wheel', 'topLeft', { deltaY: -200 })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
@@ -122,7 +122,7 @@ describe('Interaction Flow Rendering', () => {
|
|||||||
it('zooms by scroll', () => {
|
it('zooms by scroll', () => {
|
||||||
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
|
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.trigger('wheel', 'topLeft', { deltaY: 200 })
|
.trigger('wheel', 'topLeft', { deltaY: 200 })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
@@ -137,7 +137,7 @@ describe('Interaction Flow Rendering', () => {
|
|||||||
it('zooms by double click', () => {
|
it('zooms by double click', () => {
|
||||||
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleBeforeZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
|
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.dblclick()
|
.dblclick()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
const styleAfterZoom = Cypress.$('.react-flow__nodes').css('transform');
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ describe('Minimap Testing', () => {
|
|||||||
const viewBoxBeforeZoom = Cypress.$('.react-flow__minimap').attr('viewBox');
|
const viewBoxBeforeZoom = Cypress.$('.react-flow__minimap').attr('viewBox');
|
||||||
const maskPathBeforeZoom = Cypress.$('.react-flow__minimap-mask').attr('d');
|
const maskPathBeforeZoom = Cypress.$('.react-flow__minimap-mask').attr('d');
|
||||||
|
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.trigger('wheel', 'topLeft', { deltaY: -200 })
|
.trigger('wheel', 'topLeft', { deltaY: -200 })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const viewBoxAfterZoom = Cypress.$('.react-flow__minimap').attr('viewBox');
|
const viewBoxAfterZoom = Cypress.$('.react-flow__minimap').attr('viewBox');
|
||||||
@@ -53,7 +53,7 @@ describe('Minimap Testing', () => {
|
|||||||
// for d3 we have to pass the window to the event
|
// for d3 we have to pass the window to the event
|
||||||
// https://github.com/cypress-io/cypress/issues/3441
|
// https://github.com/cypress-io/cypress/issues/3441
|
||||||
cy.window().then((win) => {
|
cy.window().then((win) => {
|
||||||
cy.get('.react-flow__zoompane')
|
cy.get('.react-flow__renderer')
|
||||||
.trigger('mousedown', 'topLeft', { which: 1, view: win })
|
.trigger('mousedown', 'topLeft', { which: 1, view: win })
|
||||||
.trigger('mousemove', 'bottomLeft')
|
.trigger('mousemove', 'bottomLeft')
|
||||||
.trigger('mouseup', { force: true, view: win })
|
.trigger('mouseup', { force: true, view: win })
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import ReactFlow, { removeElements, addEdge, MiniMap, Controls, Background, isNo
|
|||||||
|
|
||||||
const onNodeDragStart = (event, node) => console.log('drag start', node);
|
const onNodeDragStart = (event, node) => console.log('drag start', node);
|
||||||
const onNodeDragStop = (event, node) => console.log('drag stop', node);
|
const onNodeDragStop = (event, node) => console.log('drag stop', node);
|
||||||
|
const onPaneClick = (event) => console.log('pane click', event);
|
||||||
|
const onPaneScroll = (event) => console.log('pane scroll', event);
|
||||||
|
const onPaneContextMenu = (event) => console.log('pane context menu', event);
|
||||||
const onSelectionDrag = (event, nodes) => console.log('selection drag', nodes);
|
const onSelectionDrag = (event, nodes) => console.log('selection drag', nodes);
|
||||||
const onSelectionDragStart = (event, nodes) => console.log('selection drag start', nodes);
|
const onSelectionDragStart = (event, nodes) => console.log('selection drag start', nodes);
|
||||||
const onSelectionDragStop = (event, nodes) => console.log('selection drag stop', nodes);
|
const onSelectionDragStop = (event, nodes) => console.log('selection drag stop', nodes);
|
||||||
@@ -125,6 +128,9 @@ const OverviewFlow = () => {
|
|||||||
onElementClick={onElementClick}
|
onElementClick={onElementClick}
|
||||||
onElementsRemove={onElementsRemove}
|
onElementsRemove={onElementsRemove}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
|
onPaneClick={onPaneClick}
|
||||||
|
onPaneScroll={onPaneScroll}
|
||||||
|
onPaneContextMenu={onPaneContextMenu}
|
||||||
onNodeDragStart={onNodeDragStart}
|
onNodeDragStart={onNodeDragStart}
|
||||||
onNodeDragStop={onNodeDragStop}
|
onNodeDragStop={onNodeDragStop}
|
||||||
onSelectionDragStart={onSelectionDragStart}
|
onSelectionDragStart={onSelectionDragStart}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type UserSelectionProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function getMousePosition(event: React.MouseEvent): XYPosition | void {
|
function getMousePosition(event: React.MouseEvent): XYPosition | void {
|
||||||
const reactFlowNode = document.querySelector('.react-flow');
|
const reactFlowNode = (event.target as Element).closest('.react-flow');
|
||||||
if (!reactFlowNode) {
|
if (!reactFlowNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -51,6 +51,7 @@ export default memo(({ selectionKeyPressed }: UserSelectionProps) => {
|
|||||||
const setUserSelection = useStoreActions((actions) => actions.setUserSelection);
|
const setUserSelection = useStoreActions((actions) => actions.setUserSelection);
|
||||||
const updateUserSelection = useStoreActions((actions) => actions.updateUserSelection);
|
const updateUserSelection = useStoreActions((actions) => actions.updateUserSelection);
|
||||||
const unsetUserSelection = useStoreActions((actions) => actions.unsetUserSelection);
|
const unsetUserSelection = useStoreActions((actions) => actions.unsetUserSelection);
|
||||||
|
const unsetNodesSelection = useStoreActions((actions) => actions.unsetNodesSelection);
|
||||||
const renderUserSelectionPane = selectionActive || selectionKeyPressed;
|
const renderUserSelectionPane = selectionActive || selectionKeyPressed;
|
||||||
|
|
||||||
if (!elementsSelectable || !renderUserSelectionPane) {
|
if (!elementsSelectable || !renderUserSelectionPane) {
|
||||||
@@ -81,12 +82,18 @@ export default memo(({ selectionKeyPressed }: UserSelectionProps) => {
|
|||||||
|
|
||||||
const onMouseUp = () => unsetUserSelection();
|
const onMouseUp = () => unsetUserSelection();
|
||||||
|
|
||||||
|
const onMouseLeave = () => {
|
||||||
|
unsetUserSelection();
|
||||||
|
unsetNodesSelection();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="react-flow__selectionpane"
|
className="react-flow__selectionpane"
|
||||||
onMouseDown={onMouseDown}
|
onMouseDown={onMouseDown}
|
||||||
onMouseMove={onMouseMove}
|
onMouseMove={onMouseMove}
|
||||||
onMouseUp={onMouseUp}
|
onMouseUp={onMouseUp}
|
||||||
|
onMouseLeave={onMouseLeave}
|
||||||
>
|
>
|
||||||
<SelectionRect />
|
<SelectionRect />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import React, { useCallback, useRef, memo, ReactNode, WheelEvent, MouseEvent } from 'react';
|
||||||
|
import { useStoreActions, useStoreState } from '../../store/hooks';
|
||||||
|
|
||||||
|
import useResizeHandler from '../../hooks/useResizeHandler';
|
||||||
|
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
||||||
|
import useD3Zoom from '../../hooks/useD3Zoom';
|
||||||
|
import useKeyPress from '../../hooks/useKeyPress';
|
||||||
|
|
||||||
|
import { GraphViewProps } from '../GraphView';
|
||||||
|
import UserSelection from '../../components/UserSelection';
|
||||||
|
import NodesSelection from '../../components/NodesSelection';
|
||||||
|
|
||||||
|
interface FlowRendererProps
|
||||||
|
extends Omit<
|
||||||
|
GraphViewProps,
|
||||||
|
| 'elements'
|
||||||
|
| 'snapToGrid'
|
||||||
|
| 'nodeTypes'
|
||||||
|
| 'edgeTypes'
|
||||||
|
| 'snapGrid'
|
||||||
|
| 'connectionLineType'
|
||||||
|
| 'arrowHeadColor'
|
||||||
|
| 'onlyRenderVisibleNodes'
|
||||||
|
> {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FlowRenderer = ({
|
||||||
|
children,
|
||||||
|
onPaneClick,
|
||||||
|
onPaneContextMenu,
|
||||||
|
onPaneScroll,
|
||||||
|
onElementsRemove,
|
||||||
|
deleteKeyCode,
|
||||||
|
onMove,
|
||||||
|
onMoveStart,
|
||||||
|
onMoveEnd,
|
||||||
|
selectionKeyCode,
|
||||||
|
zoomOnScroll,
|
||||||
|
zoomOnDoubleClick,
|
||||||
|
paneMoveable,
|
||||||
|
defaultPosition,
|
||||||
|
defaultZoom,
|
||||||
|
translateExtent,
|
||||||
|
onSelectionDragStart,
|
||||||
|
onSelectionDrag,
|
||||||
|
onSelectionDragStop,
|
||||||
|
onSelectionContextMenu,
|
||||||
|
}: FlowRendererProps) => {
|
||||||
|
const zoomPane = useRef<HTMLDivElement>(null);
|
||||||
|
const unsetNodesSelection = useStoreActions((actions) => actions.unsetNodesSelection);
|
||||||
|
const nodesSelectionActive = useStoreState((state) => state.nodesSelectionActive);
|
||||||
|
const selectionKeyPressed = useKeyPress(selectionKeyCode);
|
||||||
|
|
||||||
|
useResizeHandler(zoomPane);
|
||||||
|
useGlobalKeyHandler({ onElementsRemove, deleteKeyCode });
|
||||||
|
|
||||||
|
useD3Zoom({
|
||||||
|
zoomPane,
|
||||||
|
onMove,
|
||||||
|
onMoveStart,
|
||||||
|
onMoveEnd,
|
||||||
|
selectionKeyPressed,
|
||||||
|
zoomOnScroll,
|
||||||
|
zoomOnDoubleClick,
|
||||||
|
paneMoveable,
|
||||||
|
defaultPosition,
|
||||||
|
defaultZoom,
|
||||||
|
translateExtent,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onClick = useCallback(
|
||||||
|
(event: MouseEvent) => {
|
||||||
|
onPaneClick?.(event);
|
||||||
|
unsetNodesSelection();
|
||||||
|
},
|
||||||
|
[onPaneClick]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onContextMenu = useCallback(
|
||||||
|
(event: MouseEvent) => {
|
||||||
|
onPaneContextMenu?.(event);
|
||||||
|
},
|
||||||
|
[onPaneContextMenu]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onWheel = useCallback(
|
||||||
|
(event: WheelEvent) => {
|
||||||
|
onPaneScroll?.(event);
|
||||||
|
},
|
||||||
|
[onPaneScroll]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="react-flow__renderer" ref={zoomPane}>
|
||||||
|
{children}
|
||||||
|
<UserSelection selectionKeyPressed={selectionKeyPressed} />
|
||||||
|
{nodesSelectionActive && (
|
||||||
|
<NodesSelection
|
||||||
|
onSelectionDragStart={onSelectionDragStart}
|
||||||
|
onSelectionDrag={onSelectionDrag}
|
||||||
|
onSelectionDragStop={onSelectionDragStop}
|
||||||
|
onSelectionContextMenu={onSelectionContextMenu}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="react-flow__pane" onClick={onClick} onContextMenu={onContextMenu} onWheel={onWheel} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
FlowRenderer.displayName = 'FlowRenderer';
|
||||||
|
|
||||||
|
export default memo(FlowRenderer);
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
import React, { useEffect, useRef, useCallback, memo, CSSProperties, MouseEvent, WheelEvent } from 'react';
|
import React, { useEffect, useRef, memo, CSSProperties, MouseEvent, WheelEvent } from 'react';
|
||||||
|
|
||||||
import { useStoreState, useStoreActions, useStore } from '../../store/hooks';
|
import { useStoreState, useStoreActions, useStore } from '../../store/hooks';
|
||||||
|
import FlowRenderer from '../FlowRenderer';
|
||||||
import NodeRenderer from '../NodeRenderer';
|
import NodeRenderer from '../NodeRenderer';
|
||||||
import EdgeRenderer from '../EdgeRenderer';
|
import EdgeRenderer from '../EdgeRenderer';
|
||||||
import UserSelection from '../../components/UserSelection';
|
|
||||||
import NodesSelection from '../../components/NodesSelection';
|
|
||||||
import useKeyPress from '../../hooks/useKeyPress';
|
|
||||||
import useD3Zoom from '../../hooks/useD3Zoom';
|
|
||||||
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
|
||||||
import useElementUpdater from '../../hooks/useElementUpdater';
|
import useElementUpdater from '../../hooks/useElementUpdater';
|
||||||
import useResizeHandler from '../../hooks/useResizeHandler';
|
|
||||||
import { onLoadProject, onLoadGetElements } from '../../utils/graph';
|
import { onLoadProject, onLoadGetElements } from '../../utils/graph';
|
||||||
import {
|
import {
|
||||||
Elements,
|
Elements,
|
||||||
@@ -130,11 +125,7 @@ const GraphView = ({
|
|||||||
onPaneContextMenu,
|
onPaneContextMenu,
|
||||||
}: GraphViewProps) => {
|
}: GraphViewProps) => {
|
||||||
const isInitialised = useRef<boolean>(false);
|
const isInitialised = useRef<boolean>(false);
|
||||||
const zoomPane = useRef<HTMLDivElement>(null);
|
|
||||||
const rendererNode = useRef<HTMLDivElement>(null);
|
|
||||||
const d3Initialised = useStoreState((state) => state.d3Initialised);
|
const d3Initialised = useStoreState((state) => state.d3Initialised);
|
||||||
const nodesSelectionActive = useStoreState((state) => state.nodesSelectionActive);
|
|
||||||
const unsetNodesSelection = useStoreActions((actions) => actions.unsetNodesSelection);
|
|
||||||
const setOnConnect = useStoreActions((actions) => actions.setOnConnect);
|
const setOnConnect = useStoreActions((actions) => actions.setOnConnect);
|
||||||
const setOnConnectStart = useStoreActions((actions) => actions.setOnConnectStart);
|
const setOnConnectStart = useStoreActions((actions) => actions.setOnConnectStart);
|
||||||
const setOnConnectStop = useStoreActions((actions) => actions.setOnConnectStop);
|
const setOnConnectStop = useStoreActions((actions) => actions.setOnConnectStop);
|
||||||
@@ -153,26 +144,8 @@ const GraphView = ({
|
|||||||
const zoomTo = useStoreActions((actions) => actions.zoomTo);
|
const zoomTo = useStoreActions((actions) => actions.zoomTo);
|
||||||
const currentStore = useStore();
|
const currentStore = useStore();
|
||||||
|
|
||||||
useResizeHandler(rendererNode);
|
|
||||||
useGlobalKeyHandler({ onElementsRemove, deleteKeyCode });
|
|
||||||
useElementUpdater(elements);
|
useElementUpdater(elements);
|
||||||
|
|
||||||
const selectionKeyPressed = useKeyPress(selectionKeyCode);
|
|
||||||
|
|
||||||
useD3Zoom({
|
|
||||||
zoomPane,
|
|
||||||
onMove,
|
|
||||||
onMoveStart,
|
|
||||||
onMoveEnd,
|
|
||||||
selectionKeyPressed,
|
|
||||||
zoomOnScroll,
|
|
||||||
zoomOnDoubleClick,
|
|
||||||
paneMoveable,
|
|
||||||
defaultPosition,
|
|
||||||
defaultZoom,
|
|
||||||
translateExtent,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isInitialised.current && d3Initialised) {
|
if (!isInitialised.current && d3Initialised) {
|
||||||
if (onLoad) {
|
if (onLoad) {
|
||||||
@@ -192,28 +165,6 @@ const GraphView = ({
|
|||||||
}
|
}
|
||||||
}, [d3Initialised, onLoad]);
|
}, [d3Initialised, onLoad]);
|
||||||
|
|
||||||
const onZoomPaneClick = useCallback(
|
|
||||||
(event: React.MouseEvent) => {
|
|
||||||
onPaneClick?.(event);
|
|
||||||
unsetNodesSelection();
|
|
||||||
},
|
|
||||||
[onPaneClick]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onZoomPaneContextMenu = useCallback(
|
|
||||||
(event: React.MouseEvent) => {
|
|
||||||
onPaneContextMenu?.(event);
|
|
||||||
},
|
|
||||||
[onPaneContextMenu]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onZoomPaneScroll = useCallback(
|
|
||||||
(event: WheelEvent) => {
|
|
||||||
onPaneScroll?.(event);
|
|
||||||
},
|
|
||||||
[onPaneScroll]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onConnect) {
|
if (onConnect) {
|
||||||
setOnConnect(onConnect);
|
setOnConnect(onConnect);
|
||||||
@@ -287,7 +238,27 @@ const GraphView = ({
|
|||||||
}, [translateExtent]);
|
}, [translateExtent]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="react-flow__renderer" ref={rendererNode}>
|
<FlowRenderer
|
||||||
|
onPaneClick={onPaneClick}
|
||||||
|
onPaneContextMenu={onPaneContextMenu}
|
||||||
|
onPaneScroll={onPaneScroll}
|
||||||
|
onElementsRemove={onElementsRemove}
|
||||||
|
deleteKeyCode={deleteKeyCode}
|
||||||
|
selectionKeyCode={selectionKeyCode}
|
||||||
|
onMove={onMove}
|
||||||
|
onMoveStart={onMoveStart}
|
||||||
|
onMoveEnd={onMoveEnd}
|
||||||
|
zoomOnScroll={zoomOnScroll}
|
||||||
|
zoomOnDoubleClick={zoomOnDoubleClick}
|
||||||
|
paneMoveable={paneMoveable}
|
||||||
|
defaultPosition={defaultPosition}
|
||||||
|
defaultZoom={defaultZoom}
|
||||||
|
translateExtent={translateExtent}
|
||||||
|
onSelectionDragStart={onSelectionDragStart}
|
||||||
|
onSelectionDrag={onSelectionDrag}
|
||||||
|
onSelectionDragStop={onSelectionDragStop}
|
||||||
|
onSelectionContextMenu={onSelectionContextMenu}
|
||||||
|
>
|
||||||
<NodeRenderer
|
<NodeRenderer
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
onElementClick={onElementClick}
|
onElementClick={onElementClick}
|
||||||
@@ -311,23 +282,7 @@ const GraphView = ({
|
|||||||
markerEndId={markerEndId}
|
markerEndId={markerEndId}
|
||||||
connectionLineComponent={connectionLineComponent}
|
connectionLineComponent={connectionLineComponent}
|
||||||
/>
|
/>
|
||||||
<UserSelection selectionKeyPressed={selectionKeyPressed} />
|
</FlowRenderer>
|
||||||
{nodesSelectionActive && (
|
|
||||||
<NodesSelection
|
|
||||||
onSelectionDragStart={onSelectionDragStart}
|
|
||||||
onSelectionDrag={onSelectionDrag}
|
|
||||||
onSelectionDragStop={onSelectionDragStop}
|
|
||||||
onSelectionContextMenu={onSelectionContextMenu}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
className="react-flow__zoompane"
|
|
||||||
onClick={onZoomPaneClick}
|
|
||||||
onContextMenu={onZoomPaneContextMenu}
|
|
||||||
onWheel={onZoomPaneScroll}
|
|
||||||
ref={zoomPane}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+15
-1
@@ -107,6 +107,20 @@ export default ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (d3Zoom) {
|
if (d3Zoom) {
|
||||||
d3Zoom.filter((event: any) => {
|
d3Zoom.filter((event: any) => {
|
||||||
|
if (selectionKeyPressed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only allow zoom on nodes
|
||||||
|
if (event.target.closest('.react-flow__node') && event.type !== 'wheel') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only allow zoom on user selection
|
||||||
|
if (event.target.closest('.react-flow__nodesselection') && event.type !== 'wheel') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!paneMoveable) {
|
if (!paneMoveable) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -122,5 +136,5 @@ export default ({
|
|||||||
return !event.ctrlKey && !event.button;
|
return !event.ctrlKey && !event.button;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [d3Zoom, zoomOnScroll, zoomOnDoubleClick, paneMoveable]);
|
}, [d3Zoom, zoomOnScroll, zoomOnDoubleClick, paneMoveable, selectionKeyPressed]);
|
||||||
};
|
};
|
||||||
|
|||||||
+7
-3
@@ -6,7 +6,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__renderer,
|
.react-flow__renderer,
|
||||||
.react-flow__zoompane,
|
.react-flow__pane,
|
||||||
.react-flow__selectionpane {
|
.react-flow__selectionpane {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -15,12 +15,16 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__zoompane {
|
.react-flow__pane {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.react-flow__renderer {
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
.react-flow__selectionpane {
|
.react-flow__selectionpane {
|
||||||
z-index: 2;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__selection {
|
.react-flow__selection {
|
||||||
|
|||||||
Reference in New Issue
Block a user