refactor(store): rename nodeLookup to nodeInternals
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useMemo, MouseEvent, useCallback } from 'react';
|
import { useState, MouseEvent, useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
height: s.height,
|
height: s.height,
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
nodeLookup: s.nodeLookup,
|
nodeInternals: s.nodeInternals,
|
||||||
});
|
});
|
||||||
|
|
||||||
const MiniMap = ({
|
const MiniMap = ({
|
||||||
@@ -42,7 +42,13 @@ const MiniMap = ({
|
|||||||
nodeStrokeWidth = 2,
|
nodeStrokeWidth = 2,
|
||||||
maskColor = 'rgb(240, 242, 243, 0.7)',
|
maskColor = 'rgb(240, 242, 243, 0.7)',
|
||||||
}: MiniMapProps) => {
|
}: MiniMapProps) => {
|
||||||
const { width: containerWidth, height: containerHeight, transform, nodes, nodeLookup } = useStore(selector, shallow);
|
const {
|
||||||
|
width: containerWidth,
|
||||||
|
height: containerHeight,
|
||||||
|
transform,
|
||||||
|
nodes,
|
||||||
|
nodeInternals,
|
||||||
|
} = useStore(selector, shallow);
|
||||||
const [tX, tY, tScale] = transform;
|
const [tX, tY, tScale] = transform;
|
||||||
|
|
||||||
const mapClasses = cc(['react-flow__minimap', className]);
|
const mapClasses = cc(['react-flow__minimap', className]);
|
||||||
@@ -85,7 +91,7 @@ const MiniMap = ({
|
|||||||
{nodes
|
{nodes
|
||||||
.filter((node) => !node.isHidden && node.width && node.height)
|
.filter((node) => !node.isHidden && node.width && node.height)
|
||||||
.map((node) => {
|
.map((node) => {
|
||||||
const positionAbsolute = nodeLookup.get(node.id)?.positionAbsolute;
|
const positionAbsolute = nodeInternals.get(node.id)?.positionAbsolute;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MiniMapNode
|
<MiniMapNode
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { getBezierPath } from '../Edges/BezierEdge';
|
|||||||
import { getSmoothStepPath } from '../Edges/SmoothStepEdge';
|
import { getSmoothStepPath } from '../Edges/SmoothStepEdge';
|
||||||
import {
|
import {
|
||||||
ElementId,
|
ElementId,
|
||||||
NodeLookupItem,
|
NodeInternalsItem,
|
||||||
HandleElement,
|
HandleElement,
|
||||||
Position,
|
Position,
|
||||||
ConnectionLineType,
|
ConnectionLineType,
|
||||||
@@ -28,7 +28,7 @@ interface ConnectionLineProps {
|
|||||||
CustomConnectionLineComponent?: ConnectionLineComponent;
|
CustomConnectionLineComponent?: ConnectionLineComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selector = (s: ReactFlowState) => ({ nodeLookup: s.nodeLookup, nodes: s.nodes, transform: s.transform });
|
const selector = (s: ReactFlowState) => ({ nodeInternals: s.nodeInternals, nodes: s.nodes, transform: s.transform });
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
connectionNodeId,
|
connectionNodeId,
|
||||||
@@ -44,8 +44,8 @@ export default ({
|
|||||||
const nodeId = connectionNodeId;
|
const nodeId = connectionNodeId;
|
||||||
const handleId = connectionHandleId;
|
const handleId = connectionHandleId;
|
||||||
|
|
||||||
const { nodeLookup, nodes, transform } = useStore(selector, shallow);
|
const { nodeInternals, nodes, transform } = useStore(selector, shallow);
|
||||||
const sourceNodeInternals = useRef<NodeLookupItem | undefined>(nodeLookup.get(nodeId));
|
const sourceNodeInternals = useRef<NodeInternalsItem | undefined>(nodeInternals.get(nodeId));
|
||||||
const sourceNode = useRef<Node | undefined>(nodes.find((n) => n.id === nodeId));
|
const sourceNode = useRef<Node | undefined>(nodes.find((n) => n.id === nodeId));
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -66,12 +66,11 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
|||||||
const nodeStyle: CSSProperties = useMemo(
|
const nodeStyle: CSSProperties = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
zIndex,
|
zIndex,
|
||||||
// zIndex: isSelected ? zIndex + 1 : zIndex,
|
|
||||||
transform: `translate(${xPos}px,${yPos}px)`,
|
transform: `translate(${xPos}px,${yPos}px)`,
|
||||||
pointerEvents:
|
pointerEvents:
|
||||||
isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave ? 'all' : 'none',
|
isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave ? 'all' : 'none',
|
||||||
// prevents jumping of nodes on start
|
// prevents jumping of nodes on start
|
||||||
// opacity: isInitialized ? 1 : 0,
|
opacity: isInitialized ? 1 : 0,
|
||||||
...style,
|
...style,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
@@ -87,6 +86,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
|||||||
onMouseMove,
|
onMouseMove,
|
||||||
onMouseLeave,
|
onMouseLeave,
|
||||||
isParentNode,
|
isParentNode,
|
||||||
|
zIndex,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
width: s.width,
|
width: s.width,
|
||||||
height: s.height,
|
height: s.height,
|
||||||
connectionMode: s.connectionMode,
|
connectionMode: s.connectionMode,
|
||||||
nodeLookup: s.nodeLookup,
|
nodeInternals: s.nodeInternals,
|
||||||
});
|
});
|
||||||
|
|
||||||
const EdgeRenderer = (props: EdgeRendererProps) => {
|
const EdgeRenderer = (props: EdgeRendererProps) => {
|
||||||
@@ -230,9 +230,9 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
connectionMode,
|
connectionMode,
|
||||||
nodeLookup,
|
nodeInternals,
|
||||||
} = useStore(selector, shallow);
|
} = useStore(selector, shallow);
|
||||||
const edgeTree = useVisibleEdges(props.onlyRenderVisibleElements, nodeLookup);
|
const edgeTree = useVisibleEdges(props.onlyRenderVisibleElements, nodeInternals);
|
||||||
|
|
||||||
if (!width) {
|
if (!width) {
|
||||||
return null;
|
return null;
|
||||||
@@ -254,8 +254,8 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
|
|||||||
{isMaxLevel && <MarkerDefinitions defaultColor={defaultMarkerColor} />}
|
{isMaxLevel && <MarkerDefinitions defaultColor={defaultMarkerColor} />}
|
||||||
<g>
|
<g>
|
||||||
{edges.map((edge: Edge) => {
|
{edges.map((edge: Edge) => {
|
||||||
const sourceNode = nodeLookup.get(edge.source);
|
const sourceNode = nodeInternals.get(edge.source);
|
||||||
const targetNode = nodeLookup.get(edge.target);
|
const targetNode = nodeInternals.get(edge.target);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Edge
|
<Edge
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import shallow from 'zustand/shallow';
|
|||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { Node, NodeTypesType, ReactFlowState, WrapNodeProps } from '../../types';
|
import { Node, NodeTypesType, ReactFlowState, WrapNodeProps } from '../../types';
|
||||||
import useVisibleNodes from '../../hooks/useVisibleNodes';
|
import useVisibleNodes from '../../hooks/useVisibleNodes';
|
||||||
import useNodeLookupRef from '../../hooks/useNodeLookupRef';
|
import useNodeInternalsRef from '../../hooks/useNodeInternalsRef';
|
||||||
|
|
||||||
interface NodeRendererProps {
|
interface NodeRendererProps {
|
||||||
nodeTypes: NodeTypesType;
|
nodeTypes: NodeTypesType;
|
||||||
@@ -34,7 +34,7 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
const NodeRenderer = (props: NodeRendererProps) => {
|
const NodeRenderer = (props: NodeRendererProps) => {
|
||||||
const { scale, nodesDraggable, nodesConnectable, elementsSelectable, updateNodeDimensions, snapGrid, snapToGrid } =
|
const { scale, nodesDraggable, nodesConnectable, elementsSelectable, updateNodeDimensions, snapGrid, snapToGrid } =
|
||||||
useStore(selector, shallow);
|
useStore(selector, shallow);
|
||||||
const nodeLookup = useNodeLookupRef();
|
const nodeInternals = useNodeInternalsRef();
|
||||||
const nodes = useVisibleNodes(props.onlyRenderVisibleElements);
|
const nodes = useVisibleNodes(props.onlyRenderVisibleElements);
|
||||||
|
|
||||||
const resizeObserver = useMemo(() => {
|
const resizeObserver = useMemo(() => {
|
||||||
@@ -56,7 +56,7 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
|||||||
<div className="react-flow__nodes react-flow__container">
|
<div className="react-flow__nodes react-flow__container">
|
||||||
{nodes.map((node) => {
|
{nodes.map((node) => {
|
||||||
const nodeType = node.type || 'default';
|
const nodeType = node.type || 'default';
|
||||||
const lookupNode = nodeLookup.current.get(node.id);
|
const internals = nodeInternals.current.get(node.id);
|
||||||
|
|
||||||
if (!props.nodeTypes[nodeType]) {
|
if (!props.nodeTypes[nodeType]) {
|
||||||
console.warn(`Node type "${nodeType}" not found. Using fallback type "default".`);
|
console.warn(`Node type "${nodeType}" not found. Using fallback type "default".`);
|
||||||
@@ -83,8 +83,8 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
|||||||
sourcePosition={node.sourcePosition}
|
sourcePosition={node.sourcePosition}
|
||||||
targetPosition={node.targetPosition}
|
targetPosition={node.targetPosition}
|
||||||
isHidden={node.isHidden}
|
isHidden={node.isHidden}
|
||||||
xPos={lookupNode?.positionAbsolute?.x || 0}
|
xPos={internals?.positionAbsolute?.x || 0}
|
||||||
yPos={lookupNode?.positionAbsolute?.y || 0}
|
yPos={internals?.positionAbsolute?.y || 0}
|
||||||
isDragging={node.isDragging}
|
isDragging={node.isDragging}
|
||||||
isInitialized={isInitialized}
|
isInitialized={isInitialized}
|
||||||
snapGrid={snapGrid}
|
snapGrid={snapGrid}
|
||||||
@@ -106,8 +106,8 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
|||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
resizeObserver={resizeObserver}
|
resizeObserver={resizeObserver}
|
||||||
dragHandle={node.dragHandle}
|
dragHandle={node.dragHandle}
|
||||||
zIndex={lookupNode?.treeLevel || 0}
|
zIndex={internals?.treeLevel || 0}
|
||||||
isParentNode={!!lookupNode?.isParentNode}
|
isParentNode={!!internals?.isParentNode}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
import { useStoreApi } from '../store';
|
||||||
|
|
||||||
|
function useNodeInternalsRef() {
|
||||||
|
const store = useStoreApi();
|
||||||
|
const nodeInternals = useRef(store.getState().nodeInternals);
|
||||||
|
|
||||||
|
useEffect(() => store.subscribe((state) => (nodeInternals.current = state.nodeInternals)), []);
|
||||||
|
|
||||||
|
return nodeInternals;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useNodeInternalsRef;
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { useRef, useEffect } from 'react';
|
|
||||||
|
|
||||||
import { useStoreApi } from '../store';
|
|
||||||
|
|
||||||
function useNodeLookupRef() {
|
|
||||||
const store = useStoreApi();
|
|
||||||
const nodeLookup = useRef(store.getState().nodeLookup);
|
|
||||||
|
|
||||||
useEffect(() => store.subscribe((state) => (nodeLookup.current = state.nodeLookup)), []);
|
|
||||||
|
|
||||||
return nodeLookup;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useNodeLookupRef;
|
|
||||||
@@ -2,15 +2,15 @@ import { useCallback } from 'react';
|
|||||||
|
|
||||||
import { useStore } from '../store';
|
import { useStore } from '../store';
|
||||||
import { isEdgeVisible } from '../container/EdgeRenderer/utils';
|
import { isEdgeVisible } from '../container/EdgeRenderer/utils';
|
||||||
import { ReactFlowState, NodeLookup, Edge } from '../types';
|
import { ReactFlowState, NodeInternals, Edge } from '../types';
|
||||||
|
|
||||||
function groupEdgesByTreeLevel(edges: Edge[], nodeLookup: NodeLookup) {
|
function groupEdgesByTreeLevel(edges: Edge[], nodeInternals: NodeInternals) {
|
||||||
let maxLevel = -1;
|
let maxLevel = -1;
|
||||||
|
|
||||||
const levelLookup = edges.reduce<Record<string, Edge[]>>((tree, edge) => {
|
const levelLookup = edges.reduce<Record<string, Edge[]>>((tree, edge) => {
|
||||||
const treeLevel = Math.max(
|
const treeLevel = Math.max(
|
||||||
nodeLookup.get(edge.source)?.treeLevel || 0,
|
nodeInternals.get(edge.source)?.treeLevel || 0,
|
||||||
nodeLookup.get(edge.target)?.treeLevel || 0
|
nodeInternals.get(edge.target)?.treeLevel || 0
|
||||||
);
|
);
|
||||||
if (tree[treeLevel]) {
|
if (tree[treeLevel]) {
|
||||||
tree[treeLevel].push(edge);
|
tree[treeLevel].push(edge);
|
||||||
@@ -34,7 +34,7 @@ function groupEdgesByTreeLevel(edges: Edge[], nodeLookup: NodeLookup) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function useVisibleEdges(onlyRenderVisible: boolean, nodeLookup: NodeLookup) {
|
function useVisibleEdges(onlyRenderVisible: boolean, nodeInternals: NodeInternals) {
|
||||||
const edges = useStore(
|
const edges = useStore(
|
||||||
useCallback(
|
useCallback(
|
||||||
(s: ReactFlowState) => {
|
(s: ReactFlowState) => {
|
||||||
@@ -43,8 +43,8 @@ function useVisibleEdges(onlyRenderVisible: boolean, nodeLookup: NodeLookup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return s.edges.filter((e) => {
|
return s.edges.filter((e) => {
|
||||||
const sourceNode = nodeLookup.get(e.source);
|
const sourceNode = nodeInternals.get(e.source);
|
||||||
const targetNode = nodeLookup.get(e.target);
|
const targetNode = nodeInternals.get(e.target);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
sourceNode?.width &&
|
sourceNode?.width &&
|
||||||
@@ -65,11 +65,11 @@ function useVisibleEdges(onlyRenderVisible: boolean, nodeLookup: NodeLookup) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[onlyRenderVisible, nodeLookup]
|
[onlyRenderVisible, nodeInternals]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return groupEdgesByTreeLevel(edges, nodeLookup);
|
return groupEdgesByTreeLevel(edges, nodeInternals);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useVisibleEdges;
|
export default useVisibleEdges;
|
||||||
|
|||||||
+10
-80
@@ -26,12 +26,10 @@ import {
|
|||||||
OnEdgesChange,
|
OnEdgesChange,
|
||||||
EdgeChange,
|
EdgeChange,
|
||||||
NodeDimensionChange,
|
NodeDimensionChange,
|
||||||
NodeLookup,
|
|
||||||
NodeLookupItem,
|
|
||||||
ElementId,
|
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { isNode, isEdge, getRectOfNodes, getNodesInside, getConnectedEdges } from '../utils/graph';
|
import { isNode, isEdge, getRectOfNodes, getNodesInside, getConnectedEdges } from '../utils/graph';
|
||||||
import { getHandleBounds } from '../components/Nodes/utils';
|
import { getHandleBounds } from '../components/Nodes/utils';
|
||||||
|
import { createNodeInternals } from './utils';
|
||||||
|
|
||||||
const { Provider, useStore, useStoreApi } = createContext<ReactFlowState>();
|
const { Provider, useStore, useStoreApi } = createContext<ReactFlowState>();
|
||||||
|
|
||||||
@@ -41,34 +39,6 @@ const createNodeOrEdgeSelectionChange = (isSelected: boolean) => (item: Node | E
|
|||||||
isSelected,
|
isSelected,
|
||||||
});
|
});
|
||||||
|
|
||||||
type XYPosAndTreeLevel = XYPosition & { treeLevel: number };
|
|
||||||
|
|
||||||
function addPositions(a: XYPosAndTreeLevel, b: XYPosition): XYPosAndTreeLevel {
|
|
||||||
return {
|
|
||||||
x: (a.x ?? 0) + (b.x ?? 0),
|
|
||||||
y: (a.y ?? 0) + (b.y ?? 0),
|
|
||||||
treeLevel: a.treeLevel + 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAbsolutePositionAndTreeLevel(
|
|
||||||
node: NodeLookupItem,
|
|
||||||
nodeLookup: NodeLookup,
|
|
||||||
result: XYPosAndTreeLevel
|
|
||||||
): XYPosAndTreeLevel {
|
|
||||||
const parentNode = node.parentNode ? nodeLookup.get(node.parentNode) : false;
|
|
||||||
|
|
||||||
if (!parentNode) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAbsolutePositionAndTreeLevel(
|
|
||||||
parentNode,
|
|
||||||
nodeLookup,
|
|
||||||
addPositions(result, parentNode.position || { x: 0, y: 0 })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const createStore = () =>
|
const createStore = () =>
|
||||||
create<ReactFlowState>((set, get) => ({
|
create<ReactFlowState>((set, get) => ({
|
||||||
width: 0,
|
width: 0,
|
||||||
@@ -125,58 +95,18 @@ const createStore = () =>
|
|||||||
|
|
||||||
reactFlowVersion: typeof __REACT_FLOW_VERSION__ !== 'undefined' ? __REACT_FLOW_VERSION__ : '-',
|
reactFlowVersion: typeof __REACT_FLOW_VERSION__ !== 'undefined' ? __REACT_FLOW_VERSION__ : '-',
|
||||||
|
|
||||||
nodeLookup: new Map(),
|
nodeInternals: new Map(),
|
||||||
|
|
||||||
setNodes: (nodes: Node[]) => {
|
setNodes: (nodes: Node[]) => {
|
||||||
const { nodeLookup } = get();
|
const nodeInternals = createNodeInternals(nodes, get().nodeInternals);
|
||||||
const nextNodeLookup = new Map<ElementId, NodeLookupItem>();
|
|
||||||
|
|
||||||
nodes.forEach((node) => {
|
set({ nodes, nodeInternals });
|
||||||
const lookupNode: NodeLookupItem = {
|
|
||||||
...nodeLookup.get(node.id),
|
|
||||||
width: node.width || null,
|
|
||||||
height: node.height || null,
|
|
||||||
position: node.position,
|
|
||||||
positionAbsolute: node.position,
|
|
||||||
treeLevel: node.zIndex || 0,
|
|
||||||
};
|
|
||||||
if (node.parentNode) {
|
|
||||||
lookupNode.parentNode = node.parentNode;
|
|
||||||
}
|
|
||||||
nextNodeLookup.set(node.id, lookupNode);
|
|
||||||
});
|
|
||||||
|
|
||||||
nodes
|
|
||||||
.filter((node) => node.parentNode)
|
|
||||||
.forEach((node) => {
|
|
||||||
const positionAbsoluteAndTreeLevel = getAbsolutePositionAndTreeLevel(node, nextNodeLookup, {
|
|
||||||
...node.position,
|
|
||||||
treeLevel: node.zIndex || 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
nextNodeLookup.set(node.parentNode!, { ...nextNodeLookup.get(node.parentNode!), isParentNode: true });
|
|
||||||
|
|
||||||
if (positionAbsoluteAndTreeLevel) {
|
|
||||||
const { treeLevel, x, y } = positionAbsoluteAndTreeLevel;
|
|
||||||
|
|
||||||
nextNodeLookup.set(node.id, {
|
|
||||||
...nextNodeLookup.get(node.id),
|
|
||||||
positionAbsolute: {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
},
|
|
||||||
treeLevel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
set({ nodes, nodeLookup: nextNodeLookup });
|
|
||||||
},
|
},
|
||||||
setEdges: (edges: Edge[]) => {
|
setEdges: (edges: Edge[]) => {
|
||||||
set({ edges });
|
set({ edges });
|
||||||
},
|
},
|
||||||
updateNodeDimensions: (updates: NodeDimensionUpdate[]) => {
|
updateNodeDimensions: (updates: NodeDimensionUpdate[]) => {
|
||||||
const { onNodesChange, nodes, transform, nodeLookup } = get();
|
const { onNodesChange, nodes, transform, nodeInternals } = get();
|
||||||
|
|
||||||
const nodesToChange: NodeChange[] = updates.reduce<NodeChange[]>((res, update) => {
|
const nodesToChange: NodeChange[] = updates.reduce<NodeChange[]>((res, update) => {
|
||||||
const node = nodes.find((n) => n.id === update.id);
|
const node = nodes.find((n) => n.id === update.id);
|
||||||
@@ -190,8 +120,8 @@ const createStore = () =>
|
|||||||
|
|
||||||
if (doUpdate) {
|
if (doUpdate) {
|
||||||
const handleBounds = getHandleBounds(update.nodeElement, transform[2]);
|
const handleBounds = getHandleBounds(update.nodeElement, transform[2]);
|
||||||
nodeLookup.set(node.id, {
|
nodeInternals.set(node.id, {
|
||||||
...nodeLookup.get(node.id),
|
...nodeInternals.get(node.id),
|
||||||
handleBounds,
|
handleBounds,
|
||||||
...dimensions,
|
...dimensions,
|
||||||
});
|
});
|
||||||
@@ -208,7 +138,7 @@ const createStore = () =>
|
|||||||
return res;
|
return res;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
set({ nodeLookup: new Map(nodeLookup) });
|
set({ nodeInternals: new Map(nodeInternals) });
|
||||||
|
|
||||||
onNodesChange?.(nodesToChange);
|
onNodesChange?.(nodesToChange);
|
||||||
},
|
},
|
||||||
@@ -216,11 +146,11 @@ const createStore = () =>
|
|||||||
const { onNodesChange, nodes, nodeExtent } = get();
|
const { onNodesChange, nodes, nodeExtent } = get();
|
||||||
|
|
||||||
if (onNodesChange) {
|
if (onNodesChange) {
|
||||||
const matchingNodes = nodes.filter((n) => !!n.isSelected || n.id === id);
|
const matchingNodes = nodes.filter((n) => !!(n.isSelected || n.id === id));
|
||||||
|
|
||||||
if (matchingNodes?.length) {
|
if (matchingNodes?.length) {
|
||||||
onNodesChange(
|
onNodesChange(
|
||||||
matchingNodes.map((node) => {
|
matchingNodes?.map((node) => {
|
||||||
const change: NodeDimensionChange = {
|
const change: NodeDimensionChange = {
|
||||||
id: node.id,
|
id: node.id,
|
||||||
type: 'dimensions',
|
type: 'dimensions',
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { ElementId, Node, NodeInternals, NodeInternalsItem, XYPosition } from '../types';
|
||||||
|
|
||||||
|
type XYPosAndTreeLevel = XYPosition & { treeLevel: number };
|
||||||
|
|
||||||
|
function addPositions(a: XYPosAndTreeLevel, b: XYPosition): XYPosAndTreeLevel {
|
||||||
|
return {
|
||||||
|
x: (a.x ?? 0) + (b.x ?? 0),
|
||||||
|
y: (a.y ?? 0) + (b.y ?? 0),
|
||||||
|
treeLevel: a.treeLevel + 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAbsolutePosAndTreeLevel(
|
||||||
|
node: NodeInternalsItem,
|
||||||
|
nodeInternals: NodeInternals,
|
||||||
|
result: XYPosAndTreeLevel
|
||||||
|
): XYPosAndTreeLevel {
|
||||||
|
const parentNode = node.parentNode ? nodeInternals.get(node.parentNode) : false;
|
||||||
|
|
||||||
|
if (!parentNode) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAbsolutePosAndTreeLevel(
|
||||||
|
parentNode,
|
||||||
|
nodeInternals,
|
||||||
|
addPositions(result, parentNode.position || { x: 0, y: 0 })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function createNodeInternals(nodes: Node[], nodeInternals: NodeInternals): NodeInternals {
|
||||||
|
const nextNodeInternals = new Map<ElementId, NodeInternalsItem>();
|
||||||
|
const parentNodes: Record<ElementId, boolean> = {};
|
||||||
|
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
const internals: NodeInternalsItem = {
|
||||||
|
...nodeInternals.get(node.id),
|
||||||
|
width: node.width || null,
|
||||||
|
height: node.height || null,
|
||||||
|
position: node.position,
|
||||||
|
positionAbsolute: node.position,
|
||||||
|
treeLevel: node.zIndex || 0,
|
||||||
|
};
|
||||||
|
if (node.parentNode) {
|
||||||
|
internals.parentNode = node.parentNode;
|
||||||
|
parentNodes[node.parentNode] = true;
|
||||||
|
}
|
||||||
|
nextNodeInternals.set(node.id, internals);
|
||||||
|
});
|
||||||
|
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
const updatedInternals: NodeInternalsItem = nextNodeInternals.get(node.id)!;
|
||||||
|
|
||||||
|
if (node.parentNode) {
|
||||||
|
const positionAbsoluteAndTreeLevel = getAbsolutePosAndTreeLevel(node, nextNodeInternals, {
|
||||||
|
...node.position,
|
||||||
|
treeLevel: node.zIndex || 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { treeLevel, x, y } = positionAbsoluteAndTreeLevel;
|
||||||
|
|
||||||
|
nextNodeInternals.set(node.parentNode!, { ...nextNodeInternals.get(node.parentNode!), isParentNode: true });
|
||||||
|
updatedInternals.positionAbsolute = {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
};
|
||||||
|
updatedInternals.treeLevel = treeLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((node.isDragging || node.isSelected) && !parentNodes[node.id]) {
|
||||||
|
nextNodeInternals.set(node.id, { ...updatedInternals, treeLevel: 1000 });
|
||||||
|
} else {
|
||||||
|
nextNodeInternals.set(node.id, { ...updatedInternals, treeLevel: updatedInternals?.treeLevel || 0 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return nextNodeInternals;
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
.react-flow__viewport {
|
.react-flow__viewport {
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__renderer {
|
.react-flow__renderer {
|
||||||
|
|||||||
+3
-3
@@ -457,7 +457,7 @@ export type InitD3ZoomPayload = {
|
|||||||
export type OnNodesChange = (nodes: NodeChange[]) => void;
|
export type OnNodesChange = (nodes: NodeChange[]) => void;
|
||||||
export type OnEdgesChange = (nodes: EdgeChange[]) => void;
|
export type OnEdgesChange = (nodes: EdgeChange[]) => void;
|
||||||
|
|
||||||
export type NodeLookupItem = {
|
export type NodeInternalsItem = {
|
||||||
width?: number | null;
|
width?: number | null;
|
||||||
height?: number | null;
|
height?: number | null;
|
||||||
parentNode?: ElementId;
|
parentNode?: ElementId;
|
||||||
@@ -468,14 +468,14 @@ export type NodeLookupItem = {
|
|||||||
isParentNode?: boolean;
|
isParentNode?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NodeLookup = Map<ElementId, NodeLookupItem>;
|
export type NodeInternals = Map<ElementId, NodeInternalsItem>;
|
||||||
|
|
||||||
export interface ReactFlowState {
|
export interface ReactFlowState {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
transform: Transform;
|
transform: Transform;
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
nodeLookup: NodeLookup;
|
nodeInternals: NodeInternals;
|
||||||
edges: Edge[];
|
edges: Edge[];
|
||||||
selectedNodesBbox: Rect;
|
selectedNodesBbox: Rect;
|
||||||
onNodesChange: OnNodesChange | null;
|
onNodesChange: OnNodesChange | null;
|
||||||
|
|||||||
Reference in New Issue
Block a user