Merge branch 'main' into refactor/redux
This commit is contained in:
@@ -37,8 +37,10 @@ const FlowRenderer = ({
|
||||
onMoveEnd,
|
||||
selectionKeyCode,
|
||||
multiSelectionKeyCode,
|
||||
zoomActivationKeyCode,
|
||||
elementsSelectable,
|
||||
zoomOnScroll,
|
||||
zoomOnPinch,
|
||||
panOnScroll,
|
||||
panOnScrollSpeed,
|
||||
panOnScrollMode,
|
||||
@@ -91,6 +93,7 @@ const FlowRenderer = ({
|
||||
selectionKeyPressed={selectionKeyPressed}
|
||||
elementsSelectable={elementsSelectable}
|
||||
zoomOnScroll={zoomOnScroll}
|
||||
zoomOnPinch={zoomOnPinch}
|
||||
panOnScroll={panOnScroll}
|
||||
panOnScrollSpeed={panOnScrollSpeed}
|
||||
panOnScrollMode={panOnScrollMode}
|
||||
@@ -99,6 +102,7 @@ const FlowRenderer = ({
|
||||
defaultPosition={defaultPosition}
|
||||
defaultZoom={defaultZoom}
|
||||
translateExtent={translateExtent}
|
||||
zoomActivationKeyCode={zoomActivationKeyCode}
|
||||
>
|
||||
{children}
|
||||
<UserSelection selectionKeyPressed={selectionKeyPressed} />
|
||||
|
||||
@@ -40,6 +40,7 @@ const GraphView = ({
|
||||
onNodeMouseLeave,
|
||||
onNodeContextMenu,
|
||||
onNodeDragStart,
|
||||
onNodeDrag,
|
||||
onNodeDragStop,
|
||||
onSelectionDragStart,
|
||||
onSelectionDrag,
|
||||
@@ -51,6 +52,7 @@ const GraphView = ({
|
||||
connectionLineComponent,
|
||||
selectionKeyCode,
|
||||
multiSelectionKeyCode,
|
||||
zoomActivationKeyCode,
|
||||
onElementsRemove,
|
||||
deleteKeyCode,
|
||||
onConnect,
|
||||
@@ -69,9 +71,11 @@ const GraphView = ({
|
||||
defaultZoom,
|
||||
defaultPosition,
|
||||
translateExtent,
|
||||
nodeExtent,
|
||||
arrowHeadColor,
|
||||
markerEndId,
|
||||
zoomOnScroll,
|
||||
zoomOnPinch,
|
||||
panOnScroll,
|
||||
panOnScrollSpeed,
|
||||
panOnScrollMode,
|
||||
@@ -95,6 +99,7 @@ const GraphView = ({
|
||||
const setMinZoom = useStoreActions((actions) => actions.setMinZoom);
|
||||
const setMaxZoom = useStoreActions((actions) => actions.setMaxZoom);
|
||||
const setTranslateExtent = useStoreActions((actions) => actions.setTranslateExtent);
|
||||
const setNodeExtent = useStoreActions((actions) => actions.setNodeExtent);
|
||||
const setConnectionMode = useStoreActions((actions) => actions.setConnectionMode);
|
||||
const currentStore = useStore();
|
||||
const { zoomIn, zoomOut, zoomTo, transform, fitView, initialized } = useZoomPanHelper();
|
||||
@@ -190,6 +195,12 @@ const GraphView = ({
|
||||
}
|
||||
}, [translateExtent]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof nodeExtent !== 'undefined') {
|
||||
setNodeExtent(nodeExtent);
|
||||
}
|
||||
}, [nodeExtent]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof connectionMode !== 'undefined') {
|
||||
setConnectionMode(connectionMode);
|
||||
@@ -205,11 +216,13 @@ const GraphView = ({
|
||||
deleteKeyCode={deleteKeyCode}
|
||||
selectionKeyCode={selectionKeyCode}
|
||||
multiSelectionKeyCode={multiSelectionKeyCode}
|
||||
zoomActivationKeyCode={zoomActivationKeyCode}
|
||||
elementsSelectable={elementsSelectable}
|
||||
onMove={onMove}
|
||||
onMoveStart={onMoveStart}
|
||||
onMoveEnd={onMoveEnd}
|
||||
zoomOnScroll={zoomOnScroll}
|
||||
zoomOnPinch={zoomOnPinch}
|
||||
zoomOnDoubleClick={zoomOnDoubleClick}
|
||||
panOnScroll={panOnScroll}
|
||||
panOnScrollSpeed={panOnScrollSpeed}
|
||||
@@ -231,6 +244,7 @@ const GraphView = ({
|
||||
onNodeMouseLeave={onNodeMouseLeave}
|
||||
onNodeContextMenu={onNodeContextMenu}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
onNodeDrag={onNodeDrag}
|
||||
onNodeDragStart={onNodeDragStart}
|
||||
selectNodesOnDrag={selectNodesOnDrag}
|
||||
snapToGrid={snapToGrid}
|
||||
|
||||
@@ -3,7 +3,6 @@ import React, { memo, useMemo, ComponentType, MouseEvent } from 'react';
|
||||
import { getNodesInside, isNode } from '../../utils/graph';
|
||||
import { useStoreState, useStoreActions } from '../../store/hooks';
|
||||
import { Node, NodeTypesType, WrapNodeProps, Edge } from '../../types';
|
||||
|
||||
interface NodeRendererProps {
|
||||
nodeTypes: NodeTypesType;
|
||||
selectNodesOnDrag: boolean;
|
||||
@@ -13,6 +12,7 @@ interface NodeRendererProps {
|
||||
onNodeMouseLeave?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeContextMenu?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeDragStart?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeDrag?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeDragStop?: (event: MouseEvent, node: Node) => void;
|
||||
snapToGrid: boolean;
|
||||
snapGrid: [number, number];
|
||||
@@ -94,6 +94,7 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
onMouseLeave={props.onNodeMouseLeave}
|
||||
onContextMenu={props.onNodeContextMenu}
|
||||
onNodeDragStart={props.onNodeDragStart}
|
||||
onNodeDrag={props.onNodeDrag}
|
||||
onNodeDragStop={props.onNodeDragStop}
|
||||
scale={transform[2]}
|
||||
selected={selectedElements?.some(({ id }) => id === node.id) || false}
|
||||
|
||||
@@ -30,9 +30,11 @@ import {
|
||||
KeyCode,
|
||||
PanOnScrollMode,
|
||||
OnEdgeUpdateFunc,
|
||||
NodeExtent,
|
||||
} from '../../types';
|
||||
|
||||
import '../../style.css';
|
||||
import '../../theme-default.css';
|
||||
|
||||
const defaultNodeTypes = {
|
||||
input: InputNode,
|
||||
@@ -56,6 +58,7 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
onNodeMouseLeave?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeContextMenu?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeDragStart?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeDrag?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeDragStop?: (event: MouseEvent, node: Node) => void;
|
||||
onConnect?: (connection: Edge | Connection) => void;
|
||||
onConnectStart?: OnConnectStartFunc;
|
||||
@@ -82,6 +85,7 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
deleteKeyCode?: KeyCode;
|
||||
selectionKeyCode?: KeyCode;
|
||||
multiSelectionKeyCode?: KeyCode;
|
||||
zoomActivationKeyCode?: KeyCode;
|
||||
snapToGrid?: boolean;
|
||||
snapGrid?: [number, number];
|
||||
onlyRenderVisibleElements?: boolean;
|
||||
@@ -95,9 +99,11 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
defaultZoom?: number;
|
||||
defaultPosition?: [number, number];
|
||||
translateExtent?: TranslateExtent;
|
||||
nodeExtent?: NodeExtent;
|
||||
arrowHeadColor?: string;
|
||||
markerEndId?: string;
|
||||
zoomOnScroll?: boolean;
|
||||
zoomOnPinch?: boolean;
|
||||
panOnScroll?: boolean;
|
||||
panOnScrollSpeed?: number;
|
||||
panOnScrollMode?: PanOnScrollMode;
|
||||
@@ -125,6 +131,7 @@ const ReactFlow = ({
|
||||
onNodeMouseLeave,
|
||||
onNodeContextMenu,
|
||||
onNodeDragStart,
|
||||
onNodeDrag,
|
||||
onNodeDragStop,
|
||||
onSelectionChange,
|
||||
onSelectionDragStart,
|
||||
@@ -138,6 +145,7 @@ const ReactFlow = ({
|
||||
deleteKeyCode = 'Backspace',
|
||||
selectionKeyCode = 'Shift',
|
||||
multiSelectionKeyCode = 'Meta',
|
||||
zoomActivationKeyCode = 'Meta',
|
||||
snapToGrid = false,
|
||||
snapGrid = [15, 15],
|
||||
onlyRenderVisibleElements = true,
|
||||
@@ -150,9 +158,11 @@ const ReactFlow = ({
|
||||
defaultZoom = 1,
|
||||
defaultPosition = [0, 0],
|
||||
translateExtent,
|
||||
nodeExtent,
|
||||
arrowHeadColor = '#b1b1b7',
|
||||
markerEndId,
|
||||
zoomOnScroll = true,
|
||||
zoomOnPinch = true,
|
||||
panOnScroll = false,
|
||||
panOnScrollSpeed = 0.5,
|
||||
panOnScrollMode = PanOnScrollMode.Free,
|
||||
@@ -183,6 +193,7 @@ const ReactFlow = ({
|
||||
onNodeMouseLeave={onNodeMouseLeave}
|
||||
onNodeContextMenu={onNodeContextMenu}
|
||||
onNodeDragStart={onNodeDragStart}
|
||||
onNodeDrag={onNodeDrag}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
nodeTypes={nodeTypesParsed}
|
||||
edgeTypes={edgeTypesParsed}
|
||||
@@ -194,6 +205,7 @@ const ReactFlow = ({
|
||||
onElementsRemove={onElementsRemove}
|
||||
deleteKeyCode={deleteKeyCode}
|
||||
multiSelectionKeyCode={multiSelectionKeyCode}
|
||||
zoomActivationKeyCode={zoomActivationKeyCode}
|
||||
onConnect={onConnect}
|
||||
onConnectStart={onConnectStart}
|
||||
onConnectStop={onConnectStop}
|
||||
@@ -210,9 +222,11 @@ const ReactFlow = ({
|
||||
defaultZoom={defaultZoom}
|
||||
defaultPosition={defaultPosition}
|
||||
translateExtent={translateExtent}
|
||||
nodeExtent={nodeExtent}
|
||||
arrowHeadColor={arrowHeadColor}
|
||||
markerEndId={markerEndId}
|
||||
zoomOnScroll={zoomOnScroll}
|
||||
zoomOnPinch={zoomOnPinch}
|
||||
zoomOnDoubleClick={zoomOnDoubleClick}
|
||||
panOnScroll={panOnScroll}
|
||||
panOnScrollSpeed={panOnScrollSpeed}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import React, { useEffect, useRef, ReactNode } from 'react';
|
||||
|
||||
import { zoom, zoomIdentity } from 'd3-zoom';
|
||||
import { select } from 'd3-selection';
|
||||
import { clamp } from '../../utils';
|
||||
import { select, pointer } from 'd3-selection';
|
||||
|
||||
import { clamp } from '../../utils';
|
||||
import useKeyPress from '../../hooks/useKeyPress';
|
||||
import useResizeHandler from '../../hooks/useResizeHandler';
|
||||
import { useStoreState, useStoreActions, useStore } from '../../store/hooks';
|
||||
import { FlowTransform, TranslateExtent, PanOnScrollMode } from '../../types';
|
||||
import { FlowTransform, TranslateExtent, PanOnScrollMode, KeyCode } from '../../types';
|
||||
|
||||
interface ZoomPaneProps {
|
||||
selectionKeyPressed: boolean;
|
||||
elementsSelectable?: boolean;
|
||||
zoomOnScroll?: boolean;
|
||||
zoomOnPinch?: boolean;
|
||||
panOnScroll?: boolean;
|
||||
panOnScrollSpeed?: number;
|
||||
panOnScrollMode?: PanOnScrollMode;
|
||||
@@ -23,6 +24,7 @@ interface ZoomPaneProps {
|
||||
onMove?: (flowTransform?: FlowTransform) => void;
|
||||
onMoveStart?: (flowTransform?: FlowTransform) => void;
|
||||
onMoveEnd?: (flowTransform?: FlowTransform) => void;
|
||||
zoomActivationKeyCode?: KeyCode;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
@@ -42,6 +44,7 @@ const ZoomPane = ({
|
||||
onMoveStart,
|
||||
onMoveEnd,
|
||||
zoomOnScroll = true,
|
||||
zoomOnPinch = true,
|
||||
panOnScroll = false,
|
||||
panOnScrollSpeed = 0.5,
|
||||
panOnScrollMode = PanOnScrollMode.Free,
|
||||
@@ -52,6 +55,7 @@ const ZoomPane = ({
|
||||
defaultPosition = [0, 0],
|
||||
defaultZoom = 1,
|
||||
translateExtent,
|
||||
zoomActivationKeyCode,
|
||||
children,
|
||||
}: ZoomPaneProps) => {
|
||||
const zoomPane = useRef<HTMLDivElement>(null);
|
||||
@@ -65,6 +69,8 @@ const ZoomPane = ({
|
||||
const initD3Zoom = useStoreActions((actions) => actions.initD3Zoom);
|
||||
const updateTransform = useStoreActions((actions) => actions.updateTransform);
|
||||
|
||||
const zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode);
|
||||
|
||||
useResizeHandler(zoomPane);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -93,13 +99,24 @@ const ZoomPane = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (d3Selection && d3Zoom) {
|
||||
if (panOnScroll) {
|
||||
if (panOnScroll && !zoomActivationKeyPressed) {
|
||||
d3Selection
|
||||
.on('wheel', (event: any) => {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
const currentZoom = d3Selection.property('__zoom').k || 1;
|
||||
|
||||
if (event.ctrlKey && zoomOnPinch) {
|
||||
const point = pointer(event);
|
||||
// taken from https://github.com/d3/d3-zoom/blob/master/src/zoom.js
|
||||
const pinchDelta = -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * 10;
|
||||
const zoom = currentZoom * Math.pow(2, pinchDelta);
|
||||
d3Zoom.scaleTo(d3Selection, zoom, point);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// increase scroll speed in firefox
|
||||
// firefox: deltaMode === 1; chrome: deltaMode === 0
|
||||
const deltaNormalize = event.deltaMode === 1 ? 20 : 1;
|
||||
@@ -117,7 +134,7 @@ const ZoomPane = ({
|
||||
d3Selection.on('wheel', null).on('wheel.zoom', d3ZoomHandler);
|
||||
}
|
||||
}
|
||||
}, [panOnScroll, panOnScrollMode, d3Selection, d3Zoom, d3ZoomHandler]);
|
||||
}, [panOnScroll, panOnScrollMode, d3Selection, d3Zoom, d3ZoomHandler, zoomActivationKeyPressed, zoomOnPinch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (d3Zoom) {
|
||||
@@ -173,8 +190,11 @@ const ZoomPane = ({
|
||||
useEffect(() => {
|
||||
if (d3Zoom) {
|
||||
d3Zoom.filter((event: any) => {
|
||||
const zoomScroll = zoomActivationKeyPressed || zoomOnScroll;
|
||||
const pinchZoom = zoomOnPinch && event.ctrlKey;
|
||||
|
||||
// if all interactions are disabled, we prevent all zoom events
|
||||
if (!paneMoveable && !zoomOnScroll && !panOnScroll && !zoomOnDoubleClick) {
|
||||
if (!paneMoveable && !zoomScroll && !panOnScroll && !zoomOnDoubleClick && !zoomOnPinch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -205,8 +225,12 @@ const ZoomPane = ({
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!zoomOnPinch && event.ctrlKey && event.type === 'wheel') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// when there is no scroll handling enabled, we prevent all wheel events
|
||||
if (!zoomOnScroll && !panOnScroll && event.type === 'wheel') {
|
||||
if (!zoomScroll && !panOnScroll && !pinchZoom && event.type === 'wheel') {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -219,7 +243,17 @@ const ZoomPane = ({
|
||||
return (!event.ctrlKey || event.type === 'wheel') && !event.button;
|
||||
});
|
||||
}
|
||||
}, [d3Zoom, zoomOnScroll, panOnScroll, zoomOnDoubleClick, paneMoveable, selectionKeyPressed, elementsSelectable]);
|
||||
}, [
|
||||
d3Zoom,
|
||||
zoomOnScroll,
|
||||
zoomOnPinch,
|
||||
panOnScroll,
|
||||
zoomOnDoubleClick,
|
||||
paneMoveable,
|
||||
selectionKeyPressed,
|
||||
elementsSelectable,
|
||||
zoomActivationKeyPressed,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="react-flow__renderer react-flow__zoompane" ref={zoomPane}>
|
||||
|
||||
Reference in New Issue
Block a user