diff --git a/src/container/EdgeRenderer/index.tsx b/src/container/EdgeRenderer/index.tsx
index e3ba07bd..5de86c49 100644
--- a/src/container/EdgeRenderer/index.tsx
+++ b/src/container/EdgeRenderer/index.tsx
@@ -216,7 +216,7 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
const width = useStoreState((state) => state.width);
const height = useStoreState((state) => state.height);
- const { connectionLineStyle, connectionLineType, arrowHeadColor, connectionLineComponent } = props;
+ const { connectionLineType, arrowHeadColor, connectionLineStyle, connectionLineComponent } = props;
if (!width) {
return null;
diff --git a/src/container/GraphView/index.tsx b/src/container/GraphView/index.tsx
index 88272045..321f2853 100644
--- a/src/container/GraphView/index.tsx
+++ b/src/container/GraphView/index.tsx
@@ -63,20 +63,20 @@ export interface GraphViewProps {
snapToGrid: boolean;
snapGrid: [number, number];
onlyRenderVisibleNodes: boolean;
- nodesDraggable: boolean;
- nodesConnectable: boolean;
- elementsSelectable: boolean;
- selectNodesOnDrag: boolean;
- minZoom: number;
- maxZoom: number;
+ nodesDraggable?: boolean;
+ nodesConnectable?: boolean;
+ elementsSelectable?: boolean;
+ selectNodesOnDrag?: boolean;
+ minZoom?: number;
+ maxZoom?: number;
defaultZoom: number;
defaultPosition: [number, number];
translateExtent?: TranslateExtent;
arrowHeadColor: string;
markerEndId?: string;
- zoomOnScroll: boolean;
- zoomOnDoubleClick: boolean;
- paneMoveable: boolean;
+ zoomOnScroll?: boolean;
+ zoomOnDoubleClick?: boolean;
+ paneMoveable?: boolean;
}
const GraphView = ({
@@ -114,7 +114,7 @@ const GraphView = ({
nodesDraggable,
nodesConnectable,
elementsSelectable,
- selectNodesOnDrag,
+ selectNodesOnDrag = true,
minZoom,
maxZoom,
defaultZoom,
@@ -140,39 +140,19 @@ const GraphView = ({
const setOnConnectStop = useStoreActions((actions) => actions.setOnConnectStop);
const setOnConnectEnd = useStoreActions((actions) => actions.setOnConnectEnd);
const setSnapGrid = useStoreActions((actions) => actions.setSnapGrid);
+ const setSnapToGrid = useStoreActions((actions) => actions.setSnapToGrid);
const setNodesDraggable = useStoreActions((actions) => actions.setNodesDraggable);
const setNodesConnectable = useStoreActions((actions) => actions.setNodesConnectable);
const setElementsSelectable = useStoreActions((actions) => actions.setElementsSelectable);
const setInitTransform = useStoreActions((actions) => actions.setInitTransform);
- const setMinMaxZoom = useStoreActions((actions) => actions.setMinMaxZoom);
+ const setMinZoom = useStoreActions((actions) => actions.setMinZoom);
+ const setMaxZoom = useStoreActions((actions) => actions.setMaxZoom);
const setTranslateExtent = useStoreActions((actions) => actions.setTranslateExtent);
const fitView = useStoreActions((actions) => actions.fitView);
const zoom = useStoreActions((actions) => actions.zoom);
const zoomTo = useStoreActions((actions) => actions.zoomTo);
const currentStore = useStore();
- 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]
- );
-
useResizeHandler(rendererNode);
useGlobalKeyHandler({ onElementsRemove, deleteKeyCode });
useElementUpdater(elements);
@@ -212,6 +192,28 @@ const GraphView = ({
}
}, [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(() => {
if (onConnect) {
setOnConnect(onConnect);
@@ -237,24 +239,46 @@ const GraphView = ({
}, [onConnectEnd]);
useEffect(() => {
- setSnapGrid({ snapToGrid, snapGrid });
- }, [snapToGrid, snapGrid]);
+ if (typeof snapToGrid !== 'undefined') {
+ setSnapToGrid(snapToGrid);
+ }
+ }, [snapToGrid]);
useEffect(() => {
- setNodesDraggable(nodesDraggable);
+ if (typeof snapGrid !== 'undefined') {
+ setSnapGrid(snapGrid);
+ }
+ }, [snapGrid]);
+
+ useEffect(() => {
+ if (typeof nodesDraggable !== 'undefined') {
+ setNodesDraggable(nodesDraggable);
+ }
}, [nodesDraggable]);
useEffect(() => {
- setNodesConnectable(nodesConnectable);
+ if (typeof nodesConnectable !== 'undefined') {
+ setNodesConnectable(nodesConnectable);
+ }
}, [nodesConnectable]);
useEffect(() => {
- setElementsSelectable(elementsSelectable);
+ if (typeof elementsSelectable !== 'undefined') {
+ setElementsSelectable(elementsSelectable);
+ }
}, [elementsSelectable]);
useEffect(() => {
- setMinMaxZoom({ minZoom, maxZoom });
- }, [minZoom, maxZoom]);
+ if (typeof minZoom !== 'undefined') {
+ setMinZoom(minZoom);
+ }
+ }, [minZoom]);
+
+ useEffect(() => {
+ if (typeof maxZoom !== 'undefined') {
+ setMaxZoom(maxZoom);
+ }
+ }, [maxZoom]);
useEffect(() => {
if (typeof translateExtent !== 'undefined') {
diff --git a/src/container/NodeRenderer/index.tsx b/src/container/NodeRenderer/index.tsx
index bf99ac32..66125c1d 100644
--- a/src/container/NodeRenderer/index.tsx
+++ b/src/container/NodeRenderer/index.tsx
@@ -14,9 +14,9 @@ interface NodeRendererProps {
onNodeContextMenu?: (event: MouseEvent, node: Node) => void;
onNodeDragStart?: (event: MouseEvent, node: Node) => void;
onNodeDragStop?: (event: MouseEvent, node: Node) => void;
- onlyRenderVisibleNodes?: boolean;
- snapToGrid?: boolean;
- snapGrid?: [number, number];
+ onlyRenderVisibleNodes: boolean;
+ snapToGrid: boolean;
+ snapGrid: [number, number];
}
function renderNode(
@@ -75,7 +75,7 @@ function renderNode(
);
}
-const NodeRenderer = ({ onlyRenderVisibleNodes = true, ...props }: NodeRendererProps) => {
+const NodeRenderer = (props: NodeRendererProps) => {
const nodes = useStoreState((s) => s.nodes);
const transform = useStoreState((s) => s.transform);
const selectedElements = useStoreState((s) => s.selectedElements);
@@ -88,7 +88,7 @@ const NodeRenderer = ({ onlyRenderVisibleNodes = true, ...props }: NodeRendererP
transform: `translate(${transform[0]}px,${transform[1]}px) scale(${transform[2]})`,
};
- const renderNodes = onlyRenderVisibleNodes ? getNodesInside(nodes, viewportBox, transform, true) : nodes;
+ const renderNodes = props.onlyRenderVisibleNodes ? getNodesInside(nodes, viewportBox, transform, true) : nodes;
return (
diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx
index e92fa364..0593fa8f 100644
--- a/src/container/ReactFlow/index.tsx
+++ b/src/container/ReactFlow/index.tsx
@@ -36,6 +36,19 @@ import {
import '../../style.css';
+const defaultNodeTypes = {
+ input: InputNode,
+ default: DefaultNode,
+ output: OutputNode,
+};
+
+const defaultEdgeTypes = {
+ default: BezierEdge,
+ straight: StraightEdge,
+ step: StepEdge,
+ smoothstep: SmoothStepEdge,
+};
+
export interface ReactFlowProps extends Omit
, 'onLoad'> {
elements: Elements;
onElementClick?: (event: MouseEvent, element: Node | Edge) => void;
@@ -62,40 +75,38 @@ export interface ReactFlowProps extends Omit, 'on
onPaneScroll?: (event?: WheelEvent) => void;
onPaneClick?: (event: MouseEvent) => void;
onPaneContextMenu?: (event: MouseEvent) => void;
- nodeTypes: NodeTypesType;
- edgeTypes: EdgeTypesType;
- connectionLineType: ConnectionLineType;
+ nodeTypes?: NodeTypesType;
+ edgeTypes?: EdgeTypesType;
+ connectionLineType?: ConnectionLineType;
connectionLineStyle?: CSSProperties;
connectionLineComponent?: ConnectionLineComponent;
- deleteKeyCode: number;
- selectionKeyCode: number;
- snapToGrid: boolean;
- snapGrid: [number, number];
- onlyRenderVisibleNodes: boolean;
- nodesDraggable: boolean;
- nodesConnectable: boolean;
- elementsSelectable: boolean;
- selectNodesOnDrag: boolean;
- paneMoveable: boolean;
- minZoom: number;
- maxZoom: number;
- defaultZoom: number;
- defaultPosition: [number, number];
+ deleteKeyCode?: number;
+ selectionKeyCode?: number;
+ snapToGrid?: boolean;
+ snapGrid?: [number, number];
+ onlyRenderVisibleNodes?: boolean;
+ nodesDraggable?: boolean;
+ nodesConnectable?: boolean;
+ elementsSelectable?: boolean;
+ selectNodesOnDrag?: boolean;
+ paneMoveable?: boolean;
+ minZoom?: number;
+ maxZoom?: number;
+ defaultZoom?: number;
+ defaultPosition?: [number, number];
translateExtent?: TranslateExtent;
- arrowHeadColor: string;
+ arrowHeadColor?: string;
markerEndId?: string;
- zoomOnScroll: boolean;
- zoomOnDoubleClick: boolean;
+ zoomOnScroll?: boolean;
+ zoomOnDoubleClick?: boolean;
}
const ReactFlow = ({
- style,
- onElementClick,
elements = [],
className,
- children,
- nodeTypes,
- edgeTypes,
+ nodeTypes = defaultNodeTypes,
+ edgeTypes = defaultEdgeTypes,
+ onElementClick,
onLoad,
onMove,
onMoveStart,
@@ -116,38 +127,40 @@ const ReactFlow = ({
onSelectionDrag,
onSelectionDragStop,
onSelectionContextMenu,
- connectionLineType,
+ connectionLineType = ConnectionLineType.Bezier,
connectionLineStyle,
connectionLineComponent,
- deleteKeyCode,
- selectionKeyCode,
- snapToGrid,
- snapGrid,
- onlyRenderVisibleNodes,
+ deleteKeyCode = 8,
+ selectionKeyCode = 16,
+ snapToGrid = false,
+ snapGrid = [15, 15],
+ onlyRenderVisibleNodes = true,
+ selectNodesOnDrag = true,
nodesDraggable,
nodesConnectable,
elementsSelectable,
- selectNodesOnDrag,
minZoom,
maxZoom,
- defaultZoom,
- defaultPosition,
+ defaultZoom = 1,
+ defaultPosition = [0, 0],
translateExtent,
- arrowHeadColor,
+ arrowHeadColor = '#b1b1b7',
markerEndId,
- zoomOnScroll,
- zoomOnDoubleClick,
- paneMoveable,
+ zoomOnScroll = true,
+ zoomOnDoubleClick = true,
+ paneMoveable = true,
onPaneClick,
onPaneScroll,
onPaneContextMenu,
+ children,
+ ...rest
}: ReactFlowProps) => {
- const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), [nodeTypes]);
- const edgeTypesParsed = useMemo(() => createEdgeTypes(edgeTypes), [edgeTypes]);
+ const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), []);
+ const edgeTypesParsed = useMemo(() => createEdgeTypes(edgeTypes), []);
const reactFlowClasses = cc(['react-flow', className]);
return (
-
+
;
selectionKeyPressed: boolean;
- zoomOnScroll: boolean;
- zoomOnDoubleClick: boolean;
- paneMoveable: boolean;
- defaultPosition: [number, number];
- defaultZoom: number;
+ zoomOnScroll?: boolean;
+ zoomOnDoubleClick?: boolean;
+ paneMoveable?: boolean;
+ defaultPosition?: [number, number];
+ defaultZoom?: number;
translateExtent?: TranslateExtent;
onMove?: (flowTransform?: FlowTransform) => void;
onMoveStart?: (flowTransform?: FlowTransform) => void;
@@ -33,12 +33,12 @@ export default ({
onMove,
onMoveStart,
onMoveEnd,
- zoomOnScroll,
- zoomOnDoubleClick,
+ zoomOnScroll = true,
+ zoomOnDoubleClick = true,
selectionKeyPressed,
- paneMoveable,
- defaultPosition,
- defaultZoom,
+ paneMoveable = true,
+ defaultPosition = [0, 0],
+ defaultZoom = 1,
translateExtent,
}: UseD3ZoomParams): void => {
const prevTransform = useRef({ x: 0, y: 0, zoom: 0 });
diff --git a/src/store/index.ts b/src/store/index.ts
index 1e3e743a..2d9fadb7 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -28,6 +28,7 @@ import {
NodeDiffUpdate,
FitViewParams,
TranslateExtent,
+ SnapGrid,
} from '../types';
type TransformXYK = {
@@ -41,16 +42,6 @@ type NodeDimensionUpdate = {
nodeElement: HTMLDivElement;
};
-type SetMinMaxZoom = {
- minZoom: number;
- maxZoom: number;
-};
-
-type SetSnapGrid = {
- snapToGrid: boolean;
- snapGrid: [number, number];
-};
-
type InitD3 = {
zoomPane: Element;
defaultPosition: [number, number];
@@ -85,7 +76,7 @@ export interface StoreModel {
connectionPosition: XYPosition;
snapToGrid: boolean;
- snapGrid: [number, number];
+ snapGrid: SnapGrid;
nodesDraggable: boolean;
nodesConnectable: boolean;
@@ -124,11 +115,13 @@ export interface StoreModel {
initD3: Action;
- setMinMaxZoom: Action;
+ setMinZoom: Action;
+ setMaxZoom: Action;
setTranslateExtent: Action;
- setSnapGrid: Action;
+ setSnapToGrid: Action;
+ setSnapGrid: Action;
setConnectionPosition: Action;
@@ -187,7 +180,7 @@ export const storeModel: StoreModel = {
connectionHandleType: 'source',
connectionPosition: { x: 0, y: 0 },
- snapGrid: [16, 16],
+ snapGrid: [15, 15],
snapToGrid: false,
nodesDraggable: true,
@@ -395,12 +388,19 @@ export const storeModel: StoreModel = {
state.d3Initialised = true;
}),
- setMinMaxZoom: action((state, { minZoom, maxZoom }) => {
+ setMinZoom: action((state, minZoom) => {
state.minZoom = minZoom;
- state.maxZoom = maxZoom;
if (state.d3Zoom) {
- state.d3Zoom.scaleExtent([minZoom, maxZoom]);
+ state.d3Zoom.scaleExtent([minZoom, state.maxZoom]);
+ }
+ }),
+
+ setMaxZoom: action((state, maxZoom) => {
+ state.minZoom = maxZoom;
+
+ if (state.d3Zoom) {
+ state.d3Zoom.scaleExtent([state.minZoom, maxZoom]);
}
}),
@@ -421,9 +421,13 @@ export const storeModel: StoreModel = {
state.connectionHandleType = connectionHandleType;
}),
- setSnapGrid: action((state, { snapToGrid, snapGrid }) => {
+ setSnapToGrid: action((state, snapToGrid) => {
state.snapToGrid = snapToGrid;
- state.snapGrid = snapGrid;
+ }),
+
+ setSnapGrid: action((state, snapGrid) => {
+ state.snapGrid[0] = snapGrid[0];
+ state.snapGrid[1] = snapGrid[1];
}),
setInteractive: action((state, isInteractive) => {
diff --git a/src/types/index.ts b/src/types/index.ts
index 4fd58470..83307d6d 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -32,6 +32,8 @@ export interface Box extends XYPosition {
y2: number;
}
+export type SnapGrid = [number, number];
+
export interface Node {
id: ElementId;
position: XYPosition;
@@ -214,7 +216,7 @@ export interface WrapNodeProps {
isHidden?: boolean;
isInitialized?: boolean;
snapToGrid?: boolean;
- snapGrid?: [number, number];
+ snapGrid?: SnapGrid;
isDragging?: boolean;
}