refactor(elements): split edges and nodes

This commit is contained in:
moklick
2021-02-11 18:45:05 +01:00
parent 201a35dec2
commit ba5286a105
12 changed files with 166 additions and 190 deletions
+2
View File
@@ -65,6 +65,8 @@ const CustomNodeFlow = () => {
const onConnect = (params) => const onConnect = (params) =>
setElements((els) => addEdge({ ...params, animated: true, style: { stroke: '#fff' } }, els)); setElements((els) => addEdge({ ...params, animated: true, style: { stroke: '#fff' } }, els));
console.log('example', elements);
return ( return (
<ReactFlow <ReactFlow
elements={elements} elements={elements}
+1 -2
View File
@@ -2,10 +2,9 @@ import React from 'react';
import { useStoreState, useStoreActions, isNode } from 'react-flow-renderer'; import { useStoreState, useStoreActions, isNode } from 'react-flow-renderer';
const Sidebar = () => { const Sidebar = () => {
const elements = useStoreState((store) => store.elements); const nodes = useStoreState((store) => store.nodes);
const transform = useStoreState((store) => store.transform); const transform = useStoreState((store) => store.transform);
const setSelectedElements = useStoreActions((actions) => actions.setSelectedElements); const setSelectedElements = useStoreActions((actions) => actions.setSelectedElements);
const nodes = elements.filter(isNode);
const selectAll = () => { const selectAll = () => {
setSelectedElements(nodes.map((node) => ({ id: node.id, type: node.type }))); setSelectedElements(nodes.map((node) => ({ id: node.id, type: node.type })));
+2 -3
View File
@@ -2,7 +2,7 @@ import React, { memo } from 'react';
import cc from 'classcat'; import cc from 'classcat';
import { useStoreState } from '../../store/hooks'; import { useStoreState } from '../../store/hooks';
import { getRectOfNodes, getBoundsofRects, isNode } from '../../utils/graph'; import { getRectOfNodes, getBoundsofRects } from '../../utils/graph';
import { Node, Rect } from '../../types'; import { Node, Rect } from '../../types';
import MiniMapNode from './MiniMapNode'; import MiniMapNode from './MiniMapNode';
@@ -33,8 +33,7 @@ const MiniMap = ({
const containerWidth = useStoreState((s) => s.width); const containerWidth = useStoreState((s) => s.width);
const containerHeight = useStoreState((s) => s.height); const containerHeight = useStoreState((s) => s.height);
const [tX, tY, tScale] = useStoreState((s) => s.transform); const [tX, tY, tScale] = useStoreState((s) => s.transform);
const elements = useStoreState((s) => s.elements); const nodes = useStoreState((s) => s.nodes);
const nodes = elements.filter(isNode);
const mapClasses = cc(['react-flow__minimap', className]); const mapClasses = cc(['react-flow__minimap', className]);
const elementWidth = (style?.width || defaultWidth)! as number; const elementWidth = (style?.width || defaultWidth)! as number;
+1 -2
View File
@@ -29,8 +29,7 @@ export default ({
const selectedElements = useStoreState((state) => state.selectedElements); const selectedElements = useStoreState((state) => state.selectedElements);
const snapToGrid = useStoreState((state) => state.snapToGrid); const snapToGrid = useStoreState((state) => state.snapToGrid);
const snapGrid = useStoreState((state) => state.snapGrid); const snapGrid = useStoreState((state) => state.snapGrid);
const elements = useStoreState((state) => state.elements); const nodes = useStoreState((state) => state.nodes);
const nodes = elements.filter(isNode);
const updateNodePosDiff = useStoreActions((actions) => actions.updateNodePosDiff); const updateNodePosDiff = useStoreActions((actions) => actions.updateNodePosDiff);
+3 -5
View File
@@ -2,7 +2,7 @@ import React, { memo, CSSProperties, useCallback } from 'react';
import { useStoreState } from '../../store/hooks'; import { useStoreState } from '../../store/hooks';
import ConnectionLine from '../../components/ConnectionLine/index'; import ConnectionLine from '../../components/ConnectionLine/index';
import { isEdge, isNode } from '../../utils/graph'; import { isEdge } from '../../utils/graph';
import MarkerDefinitions from './MarkerDefinitions'; import MarkerDefinitions from './MarkerDefinitions';
import { getEdgePositions, getHandle, isEdgeVisible, getSourceTargetNodes } from './utils'; import { getEdgePositions, getHandle, isEdgeVisible, getSourceTargetNodes } from './utils';
import { import {
@@ -169,7 +169,8 @@ const Edge = ({
const EdgeRenderer = (props: EdgeRendererProps) => { const EdgeRenderer = (props: EdgeRendererProps) => {
const transform = useStoreState((state) => state.transform); const transform = useStoreState((state) => state.transform);
const elements = useStoreState((state) => state.elements); const nodes = useStoreState((state) => state.nodes);
const edges = useStoreState((state) => state.edges);
const connectionNodeId = useStoreState((state) => state.connectionNodeId); const connectionNodeId = useStoreState((state) => state.connectionNodeId);
const connectionHandleId = useStoreState((state) => state.connectionHandleId); const connectionHandleId = useStoreState((state) => state.connectionHandleId);
const connectionHandleType = useStoreState((state) => state.connectionHandleType); const connectionHandleType = useStoreState((state) => state.connectionHandleType);
@@ -180,9 +181,6 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
const width = useStoreState((state) => state.width); const width = useStoreState((state) => state.width);
const height = useStoreState((state) => state.height); const height = useStoreState((state) => state.height);
const edges = elements.filter(isEdge);
const nodes = elements.filter(isNode);
if (!width) { if (!width) {
return null; return null;
} }
+3 -4
View File
@@ -1,6 +1,6 @@
import React, { memo, useMemo, ComponentType, MouseEvent } from 'react'; import React, { memo, useMemo, ComponentType, MouseEvent } from 'react';
import { getNodesInside, isNode } from '../../utils/graph'; import { getNodesInside } from '../../utils/graph';
import { useStoreState, useStoreActions } from '../../store/hooks'; import { useStoreState, useStoreActions } from '../../store/hooks';
import { Node, NodeTypesType, WrapNodeProps, Edge } from '../../types'; import { Node, NodeTypesType, WrapNodeProps, Edge } from '../../types';
interface NodeRendererProps { interface NodeRendererProps {
@@ -27,11 +27,10 @@ const NodeRenderer = (props: NodeRendererProps) => {
const elementsSelectable = useStoreState((state) => state.elementsSelectable); const elementsSelectable = useStoreState((state) => state.elementsSelectable);
const width = useStoreState((state) => state.width); const width = useStoreState((state) => state.width);
const height = useStoreState((state) => state.height); const height = useStoreState((state) => state.height);
const elements = useStoreState((state) => state.elements); const nodes = useStoreState((state) => state.nodes);
const batchUpdateNodeDimensions = useStoreActions((actions) => actions.batchUpdateNodeDimensions); const batchUpdateNodeDimensions = useStoreActions((actions) => actions.batchUpdateNodeDimensions);
const viewportBox = { x: 0, y: 0, width, height }; const viewportBox = useMemo(() => ({ x: 0, y: 0, width, height }), [width, height]);
const nodes = elements.filter(isNode);
const visibleNodes = props.onlyRenderVisibleElements ? getNodesInside(nodes, viewportBox, transform, true) : nodes; const visibleNodes = props.onlyRenderVisibleElements ? getNodesInside(nodes, viewportBox, transform, true) : nodes;
const transformStyle = useMemo( const transformStyle = useMemo(
+2 -3
View File
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
import { useStore, useStoreActions } from '../store/hooks'; import { useStore, useStoreActions } from '../store/hooks';
import useKeyPress from './useKeyPress'; import useKeyPress from './useKeyPress';
import { isNode, getConnectedEdges, isEdge } from '../utils/graph'; import { isNode, getConnectedEdges } from '../utils/graph';
import { Elements, KeyCode, ElementId, FlowElement } from '../types'; import { Elements, KeyCode, ElementId, FlowElement } from '../types';
interface HookParams { interface HookParams {
@@ -22,8 +22,7 @@ export default ({ deleteKeyCode, multiSelectionKeyCode, onElementsRemove }: Hook
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode); const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
useEffect(() => { useEffect(() => {
const { elements, selectedElements } = store.getState(); const { edges, selectedElements } = store.getState();
const edges = elements.filter(isEdge);
if (onElementsRemove && deleteKeyPressed && selectedElements) { if (onElementsRemove && deleteKeyPressed && selectedElements) {
const selectedNodes = selectedElements.filter(isNode); const selectedNodes = selectedElements.filter(isNode);
+2 -3
View File
@@ -3,7 +3,7 @@ import { zoomIdentity } from 'd3-zoom';
import { useStoreState, useStore } from '../store/hooks'; import { useStoreState, useStore } from '../store/hooks';
import { clamp } from '../utils'; import { clamp } from '../utils';
import { getRectOfNodes, isNode } from '../utils/graph'; import { getRectOfNodes } from '../utils/graph';
import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, Rect, Transform } from '../types'; import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, Rect, Transform } from '../types';
const DEFAULT_PADDING = 0.1; const DEFAULT_PADDING = 0.1;
@@ -56,8 +56,7 @@ const useZoomPanHelper = (): ZoomPanHelperFunctions => {
d3Zoom.transform(d3Selection, nextTransform); d3Zoom.transform(d3Selection, nextTransform);
}, },
fitView: (options: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => { fitView: (options: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {
const { elements, width, height, minZoom, maxZoom } = store.getState(); const { nodes, width, height, minZoom, maxZoom } = store.getState();
const nodes = elements.filter(isNode);
if (!nodes.length) { if (!nodes.length) {
return; return;
+2 -4
View File
@@ -6,12 +6,10 @@ export const initialState: ReactFlowState = {
width: 0, width: 0,
height: 0, height: 0,
transform: [0, 0, 1], transform: [0, 0, 1],
elements: [], nodes: [],
// nodes: computed((state) => state.elements.filter(isNode)), edges: [],
// edges: computed((state) => state.elements.filter(isEdge)),
selectedElements: null, selectedElements: null,
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 }, selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
// viewportBox: computed((state) => ({ x: 0, y: 0, width: state.width, height: state.height })),
d3Zoom: null, d3Zoom: null,
d3Selection: null, d3Selection: null,
+126 -132
View File
@@ -1,112 +1,109 @@
import isEqual from 'fast-deep-equal'; import isEqual from 'fast-deep-equal';
import { getDimensions } from '../utils'; import { getDimensions } from '../utils';
import { getNodesInside, getConnectedEdges, getRectOfNodes, isNode, isEdge, parseElement } from '../utils/graph'; import {
getNodesInside,
getConnectedEdges,
getRectOfNodes,
isNode,
isEdge,
parseNode,
parseEdge,
} from '../utils/graph';
import { getHandleBounds } from '../components/Nodes/utils'; import { getHandleBounds } from '../components/Nodes/utils';
import { ReactFlowState, FlowElement, Node, XYPosition } from '../types'; import { ReactFlowState, Node, XYPosition, Edge } from '../types';
import { import * as constants from './contants';
ADD_SELECTED_ELEMENTS,
BATCH_UPDATE_NODE_DIMENSIONS,
INIT_D3ZOOM,
RESET_SELECTED_ELEMENTS,
SET_CONNECTION_MODE,
SET_CONNECTION_NODEID,
SET_CONNECTION_POSITION,
SET_ELEMENTS,
SET_ELEMENTS_SELECTABLE,
SET_INTERACTIVE,
SET_MAXZOOM,
SET_MINZOOM,
SET_MULTI_SELECTION_ACTIVE,
SET_NODES_CONNECTABLE,
SET_NODES_DRAGGABLE,
SET_NODE_EXTENT,
SET_ON_CONNECT,
SET_ON_CONNECT_END,
SET_ON_CONNECT_START,
SET_ON_CONNECT_STOP,
SET_SELECTED_ELEMENTS,
SET_SNAPGRID,
SET_SNAPTOGRID,
SET_TRANSLATEEXTENT,
SET_USER_SELECTION,
UNSET_USER_SELECTION,
UPDATE_NODE_DIMENSIONS,
UPDATE_NODE_POS,
UPDATE_NODE_POS_DIFF,
UPDATE_SIZE,
UPDATE_TRANSFORM,
UPDATE_USER_SELECTION,
} from './contants';
import { ReactFlowAction } from './actions'; import { ReactFlowAction } from './actions';
import { initialState } from './index'; import { initialState } from './index';
type ElementsSplitted = {
nodeElements: Node[];
edgeElements: Edge[];
};
export default function reactFlowReducer(state = initialState, action: ReactFlowAction): ReactFlowState { export default function reactFlowReducer(state = initialState, action: ReactFlowAction): ReactFlowState {
switch (action.type) { switch (action.type) {
case SET_ELEMENTS: { case constants.SET_ELEMENTS: {
const propElements = action.payload; const propElements = action.payload;
const elementsSplitted: ElementsSplitted = {
nodeElements: [],
edgeElements: [],
};
const { nodeElements, edgeElements } = propElements.reduce((res, item): ElementsSplitted => {
if (isNode(item)) {
res.nodeElements.push(item);
} else if (isEdge(item)) {
res.edgeElements.push(item);
}
const nextElements = propElements.map((el: FlowElement) => { return res;
let storeElement = state.elements.find((se) => se.id === el.id); }, elementsSplitted);
const nextNodes = nodeElements.map((propNode: Node) => {
let storeNode = state.nodes.find((node) => node.id === propNode.id);
// update existing element // update existing element
if (storeElement) { if (storeNode) {
if (isNode(storeElement)) { const positionChanged =
const propNode = el as Node; storeNode.position.x !== propNode.position.x || storeNode.position.y !== propNode.position.y;
const positionChanged = const typeChanged = typeof propNode.type !== 'undefined' && propNode.type !== storeNode.type;
storeElement.position.x !== propNode.position.x || storeElement.position.y !== propNode.position.y;
const typeChanged = typeof propNode.type !== 'undefined' && propNode.type !== storeElement.type;
storeElement = { storeNode = {
...storeElement, ...storeNode,
...propNode, ...propNode,
}; };
if (positionChanged) { if (positionChanged) {
(storeElement as Node).__rf.position = propNode.position; storeNode.__rf.position = propNode.position;
}
if (typeChanged) {
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
// When the type of a node changes it is possible that the number or positions of handles changes too.
(storeElement as Node).__rf.width = null;
}
} else {
storeElement = {
...storeElement,
...el,
};
} }
return storeElement; if (typeChanged) {
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
// When the type of a node changes it is possible that the number or positions of handles changes too.
storeNode.__rf.width = null;
}
return storeNode;
} else { } else {
// add new element // add new element
return parseElement(el, state.nodeExtent); return parseNode(propNode, state.nodeExtent);
} }
}); });
return { ...state, elements: nextElements }; const nextEdges = edgeElements.map((propEdge: Edge) => {
let storeEdge = state.edges.find((se) => se.id === propEdge.id);
if (storeEdge) {
return {
...storeEdge,
...propEdge,
};
} else {
return parseEdge(propEdge);
}
});
return { ...state, nodes: nextNodes, edges: nextEdges };
} }
case BATCH_UPDATE_NODE_DIMENSIONS: { case constants.BATCH_UPDATE_NODE_DIMENSIONS: {
const updatedElements = state.elements.map((el) => { const updatedNodes = state.nodes.map((node) => {
const update = action.payload.find((u) => u.id === el.id); const update = action.payload.find((u) => u.id === node.id);
if (update) { if (update) {
const dimensions = getDimensions(update.nodeElement); const dimensions = getDimensions(update.nodeElement);
const nodeToUpdate = el as Node;
if ( if (
dimensions.width && dimensions.width &&
dimensions.height && dimensions.height &&
(nodeToUpdate.__rf.width !== dimensions.width || nodeToUpdate.__rf.height !== dimensions.height) (node.__rf.width !== dimensions.width || node.__rf.height !== dimensions.height)
) { ) {
const handleBounds = getHandleBounds(update.nodeElement, state.transform[2]); const handleBounds = getHandleBounds(update.nodeElement, state.transform[2]);
return { return {
...nodeToUpdate, ...node,
__rf: { __rf: {
...nodeToUpdate.__rf, ...node.__rf,
...dimensions, ...dimensions,
handleBounds, handleBounds,
}, },
@@ -114,15 +111,15 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
} }
} }
return el; return node;
}); });
return { return {
...state, ...state,
elements: updatedElements, nodes: updatedNodes,
}; };
} }
case UPDATE_NODE_DIMENSIONS: { case constants.UPDATE_NODE_DIMENSIONS: {
const { nodeElement, id } = action.payload; const { nodeElement, id } = action.payload;
const dimensions = getDimensions(nodeElement); const dimensions = getDimensions(nodeElement);
@@ -130,14 +127,14 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
return state; return state;
} }
const nextElements = state.elements.map((el) => { const nextNodes = state.nodes.map((node) => {
if (el.id === id && isNode(el)) { if (node.id === id) {
const handleBounds = getHandleBounds(nodeElement, state.transform[2]); const handleBounds = getHandleBounds(nodeElement, state.transform[2]);
return { return {
...el, ...node,
__rf: { __rf: {
...el.__rf, ...node.__rf,
width: dimensions.width, width: dimensions.width,
height: dimensions.height, height: dimensions.height,
handleBounds, handleBounds,
@@ -145,12 +142,12 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
}; };
} }
return el; return node;
}); });
return { ...state, elements: nextElements }; return { ...state, nodes: nextNodes };
} }
case UPDATE_NODE_POS: { case constants.UPDATE_NODE_POS: {
const { id, pos } = action.payload; const { id, pos } = action.payload;
let position: XYPosition = pos; let position: XYPosition = pos;
@@ -163,56 +160,56 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
}; };
} }
const nextElements = state.elements.map((el) => { const nextNodes = state.nodes.map((node) => {
if (el.id === id && isNode(el)) { if (node.id === id) {
return { return {
...el, ...node,
__rf: { __rf: {
...el.__rf, ...node.__rf,
position, position,
}, },
}; };
} }
return el; return node;
}); });
return { ...state, elements: nextElements }; return { ...state, nodes: nextNodes };
} }
case UPDATE_NODE_POS_DIFF: { case constants.UPDATE_NODE_POS_DIFF: {
const { id, diff, isDragging } = action.payload; const { id, diff, isDragging } = action.payload;
const nextElements = state.elements.map((el) => { const nextNodes = state.nodes.map((node) => {
if (isNode(el) && (id === el.id || state.selectedElements?.find((sNode) => sNode.id === el.id))) { if (id === node.id || state.selectedElements?.find((sNode) => sNode.id === node.id)) {
if (diff) { if (diff) {
return { return {
...el, ...node,
__rf: { __rf: {
...el.__rf, ...node.__rf,
isDragging, isDragging,
position: { position: {
x: el.__rf.position.x + diff.x, x: node.__rf.position.x + diff.x,
y: el.__rf.position.y + diff.y, y: node.__rf.position.y + diff.y,
}, },
}, },
}; };
} }
return { return {
...el, ...node,
__rf: { __rf: {
...el.__rf, ...node.__rf,
isDragging, isDragging,
}, },
}; };
} }
return el; return node;
}); });
return { ...state, elements: nextElements }; return { ...state, nodes: nextNodes };
} }
case SET_USER_SELECTION: { case constants.SET_USER_SELECTION: {
const mousePos = action.payload; const mousePos = action.payload;
const userSelectionRect = { const userSelectionRect = {
@@ -231,7 +228,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
selectionActive: true, selectionActive: true,
}; };
} }
case UPDATE_USER_SELECTION: { case constants.UPDATE_USER_SELECTION: {
const mousePos = action.payload; const mousePos = action.payload;
const startX = state.userSelectionRect.startX || 0; const startX = state.userSelectionRect.startX || 0;
const startY = state.userSelectionRect.startY || 0; const startY = state.userSelectionRect.startY || 0;
@@ -247,11 +244,8 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
height: Math.abs(mousePos.y - startY), height: Math.abs(mousePos.y - startY),
}; };
const nodes = state.elements.filter(isNode); const selectedNodes = getNodesInside(state.nodes, nextUserSelectRect, state.transform);
const edges = state.elements.filter(isEdge); const selectedEdges = getConnectedEdges(selectedNodes, state.edges);
const selectedNodes = getNodesInside(nodes, nextUserSelectRect, state.transform);
const selectedEdges = getConnectedEdges(selectedNodes, edges);
const nextSelectedElements = [...selectedNodes, ...selectedEdges]; const nextSelectedElements = [...selectedNodes, ...selectedEdges];
const selectedElementsUpdated = !isEqual(nextSelectedElements, state.selectedElements); const selectedElementsUpdated = !isEqual(nextSelectedElements, state.selectedElements);
@@ -269,7 +263,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
userSelectionRect: nextUserSelectRect, userSelectionRect: nextUserSelectRect,
}; };
} }
case UNSET_USER_SELECTION: { case constants.UNSET_USER_SELECTION: {
const selectedNodes = state.selectedElements?.filter((node) => isNode(node) && node.__rf) as Node[]; const selectedNodes = state.selectedElements?.filter((node) => isNode(node) && node.__rf) as Node[];
const selectionActive = false; const selectionActive = false;
@@ -298,7 +292,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
nodesSelectionActive: true, nodesSelectionActive: true,
}; };
} }
case SET_SELECTED_ELEMENTS: { case constants.SET_SELECTED_ELEMENTS: {
const elements = action.payload; const elements = action.payload;
const selectedElementsArr = Array.isArray(elements) ? elements : [elements]; const selectedElementsArr = Array.isArray(elements) ? elements : [elements];
const selectedElementsUpdated = !isEqual(selectedElementsArr, state.selectedElements); const selectedElementsUpdated = !isEqual(selectedElementsArr, state.selectedElements);
@@ -309,7 +303,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
selectedElements, selectedElements,
}; };
} }
case ADD_SELECTED_ELEMENTS: { case constants.ADD_SELECTED_ELEMENTS: {
const { multiSelectionActive, selectedElements } = state; const { multiSelectionActive, selectedElements } = state;
const elements = action.payload; const elements = action.payload;
const selectedElementsArr = Array.isArray(elements) ? elements : [elements]; const selectedElementsArr = Array.isArray(elements) ? elements : [elements];
@@ -325,7 +319,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
return { ...state, selectedElements: nextSelectedElements }; return { ...state, selectedElements: nextSelectedElements };
} }
case INIT_D3ZOOM: { case constants.INIT_D3ZOOM: {
const { d3Zoom, d3Selection, d3ZoomHandler, transform } = action.payload; const { d3Zoom, d3Selection, d3ZoomHandler, transform } = action.payload;
return { return {
@@ -336,7 +330,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
transform, transform,
}; };
} }
case SET_MINZOOM: { case constants.SET_MINZOOM: {
const minZoom = action.payload; const minZoom = action.payload;
if (state.d3Zoom) { if (state.d3Zoom) {
@@ -349,7 +343,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
}; };
} }
case SET_MAXZOOM: { case constants.SET_MAXZOOM: {
const maxZoom = action.payload; const maxZoom = action.payload;
if (state.d3Zoom) { if (state.d3Zoom) {
@@ -361,7 +355,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
maxZoom, maxZoom,
}; };
} }
case SET_TRANSLATEEXTENT: { case constants.SET_TRANSLATEEXTENT: {
const translateExtent = action.payload; const translateExtent = action.payload;
if (state.d3Zoom) { if (state.d3Zoom) {
@@ -373,24 +367,24 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow
translateExtent, translateExtent,
}; };
} }
case SET_ON_CONNECT: case constants.SET_ON_CONNECT:
case SET_ON_CONNECT_START: case constants.SET_ON_CONNECT_START:
case SET_ON_CONNECT_STOP: case constants.SET_ON_CONNECT_STOP:
case SET_ON_CONNECT_END: case constants.SET_ON_CONNECT_END:
case RESET_SELECTED_ELEMENTS: case constants.RESET_SELECTED_ELEMENTS:
case UPDATE_TRANSFORM: case constants.UPDATE_TRANSFORM:
case UPDATE_SIZE: case constants.UPDATE_SIZE:
case SET_CONNECTION_POSITION: case constants.SET_CONNECTION_POSITION:
case SET_CONNECTION_NODEID: case constants.SET_CONNECTION_NODEID:
case SET_SNAPTOGRID: case constants.SET_SNAPTOGRID:
case SET_SNAPGRID: case constants.SET_SNAPGRID:
case SET_INTERACTIVE: case constants.SET_INTERACTIVE:
case SET_NODES_DRAGGABLE: case constants.SET_NODES_DRAGGABLE:
case SET_NODES_CONNECTABLE: case constants.SET_NODES_CONNECTABLE:
case SET_ELEMENTS_SELECTABLE: case constants.SET_ELEMENTS_SELECTABLE:
case SET_MULTI_SELECTION_ACTIVE: case constants.SET_MULTI_SELECTION_ACTIVE:
case SET_CONNECTION_MODE: case constants.SET_CONNECTION_MODE:
case SET_NODE_EXTENT: case constants.SET_NODE_EXTENT:
return { ...state, ...action.payload }; return { ...state, ...action.payload };
default: default:
return state; return state;
+2 -4
View File
@@ -382,12 +382,10 @@ export interface ReactFlowState {
width: number; width: number;
height: number; height: number;
transform: Transform; transform: Transform;
elements: Elements; nodes: Node[];
// nodes: Computed<StoreModel, Node[]>; edges: Edge[];
// edges: Computed<StoreModel, Edge[]>;
selectedElements: Elements | null; selectedElements: Elements | null;
selectedNodesBbox: Rect; selectedNodesBbox: Rect;
// viewportBox: Computed<StoreModel, Rect>;
d3Zoom: ZoomBehavior<Element, unknown> | null; d3Zoom: ZoomBehavior<Element, unknown> | null;
d3Selection: D3Selection<Element, unknown, null, undefined> | null; d3Selection: D3Selection<Element, unknown, null, undefined> | null;
+20 -28
View File
@@ -146,35 +146,31 @@ export const onLoadProject = (currentStore: Store<ReactFlowState>) => {
}; };
}; };
export const parseElement = (element: Node | Edge, nodeExtent: NodeExtent): Node | Edge => { export const parseNode = (node: Node, nodeExtent: NodeExtent): Node => {
if (!element.id) {
throw new Error('All nodes and edges need to have an id.');
}
if (isEdge(element)) {
return {
...element,
source: element.source.toString(),
target: element.target.toString(),
sourceHandle: element.sourceHandle ? element.sourceHandle.toString() : null,
targetHandle: element.targetHandle ? element.targetHandle.toString() : null,
id: element.id.toString(),
type: element.type || 'default',
};
}
return { return {
...element, ...node,
id: element.id.toString(), id: node.id.toString(),
type: element.type || 'default', type: node.type || 'default',
__rf: { __rf: {
position: clampPosition(element.position, nodeExtent), position: clampPosition(node.position, nodeExtent),
width: null, width: null,
height: null, height: null,
handleBounds: {}, handleBounds: {},
isDragging: false, isDragging: false,
}, },
} as Node; };
};
export const parseEdge = (edge: Edge): Edge => {
return {
...edge,
source: edge.source.toString(),
target: edge.target.toString(),
sourceHandle: edge.sourceHandle ? edge.sourceHandle.toString() : null,
targetHandle: edge.targetHandle ? edge.targetHandle.toString() : null,
id: edge.id.toString(),
type: edge.type || 'default',
};
}; };
const getBoundsOfBoxes = (box1: Box, box2: Box): Box => ({ const getBoundsOfBoxes = (box1: Box, box2: Box): Box => ({
@@ -272,9 +268,7 @@ const parseElements = (nodes: Node[], edges: Edge[]): Elements => {
export const onLoadGetElements = (currentStore: Store<ReactFlowState>) => { export const onLoadGetElements = (currentStore: Store<ReactFlowState>) => {
return (): Elements => { return (): Elements => {
const { elements = [] } = currentStore.getState(); const { nodes = [], edges = [] } = currentStore.getState();
const nodes = elements.filter(isNode);
const edges = elements.filter(isEdge);
return parseElements(nodes, edges); return parseElements(nodes, edges);
}; };
@@ -282,9 +276,7 @@ export const onLoadGetElements = (currentStore: Store<ReactFlowState>) => {
export const onLoadToObject = (currentStore: Store<ReactFlowState>) => { export const onLoadToObject = (currentStore: Store<ReactFlowState>) => {
return (): FlowExportObject => { return (): FlowExportObject => {
const { elements = [], transform } = currentStore.getState(); const { nodes = [], edges = [], transform } = currentStore.getState();
const nodes = elements.filter(isNode);
const edges = elements.filter(isEdge);
return { return {
elements: parseElements(nodes, edges), elements: parseElements(nodes, edges),