Merge pull request #4105 from xyflow/refactor/internal-nodes

React Flow 12: separate user nodes and internal nodes
This commit is contained in:
Moritz Klack
2024-04-09 13:33:25 +02:00
committed by GitHub
57 changed files with 722 additions and 582 deletions
+20 -9
View File
@@ -56,18 +56,19 @@ const initialEdges: Edge[] = [
const defaultEdgeOptions = {};
const BasicFlow = () => {
const { setNodes, getNodes, setEdges, getEdges, deleteElements, updateNodeData, toObject, setViewport } =
const { addNodes, setNodes, getNodes, setEdges, getEdges, deleteElements, updateNodeData, toObject, setViewport } =
useReactFlow();
const updatePos = () => {
setNodes((nodes) =>
nodes.map((node) => {
node.position = {
x: Math.random() * 400,
y: Math.random() * 400,
return {
...node,
position: {
x: Math.random() * 400,
y: Math.random() * 400,
},
};
return node;
})
);
};
@@ -78,9 +79,10 @@ const BasicFlow = () => {
const toggleClassnames = () => {
setNodes((nodes) =>
nodes.map((node) => {
node.className = node.className === 'light' ? 'dark' : 'light';
return node;
return {
...node,
className: node.className === 'light' ? 'dark' : 'light',
};
})
);
};
@@ -108,6 +110,14 @@ const BasicFlow = () => {
updateNodeData('1', { label: 'update' });
updateNodeData('2', { label: 'update' });
};
const addNode = () => {
addNodes({
id: `${Math.random()}`,
data: { label: 'Node' },
position: { x: Math.random() * 300, y: Math.random() * 300 },
className: 'light',
});
};
return (
<ReactFlow
@@ -144,6 +154,7 @@ const BasicFlow = () => {
<button onClick={deleteSomeElements}>deleteSomeElements</button>
<button onClick={onSetNodes}>setNodes</button>
<button onClick={onUpdateNode}>updateNode</button>
<button onClick={addNode}>addNode</button>
</Panel>
</ReactFlow>
);
@@ -9,8 +9,8 @@ function getNodeIntersection(intersectionNode: Node, targetNode: Node) {
width: intersectionNodeWidth,
height: intersectionNodeHeight,
positionAbsolute: intersectionNodePosition,
} = intersectionNode.computed || {};
const targetPosition = targetNode.computed?.positionAbsolute!;
} = intersectionNode.measured || {};
const targetPosition = targetNode.measured?.positionAbsolute!;
const w = intersectionNodeWidth! / 2;
const h = intersectionNodeHeight! / 2;
@@ -33,7 +33,7 @@ function getNodeIntersection(intersectionNode: Node, targetNode: Node) {
// returns the position (top,right,bottom or right) passed node compared to the intersection point
function getEdgePosition(node: Node, intersectionPoint: XYPosition) {
const n = { ...node.computed?.positionAbsolute, ...node };
const n = { ...node.measured?.positionAbsolute, ...node };
const nx = Math.round(n.x!);
const ny = Math.round(n.y!);
const px = Math.round(intersectionPoint.x);
@@ -42,13 +42,13 @@ function getEdgePosition(node: Node, intersectionPoint: XYPosition) {
if (px <= nx + 1) {
return Position.Left;
}
if (px >= nx + n.computed?.width! - 1) {
if (px >= nx + n.measured?.width! - 1) {
return Position.Right;
}
if (py <= ny + 1) {
return Position.Top;
}
if (py >= n.y! + n.computed?.height! - 1) {
if (py >= n.y! + n.measured?.height! - 1) {
return Position.Bottom;
}
@@ -5,8 +5,8 @@ import { getEdgeParams } from './utils';
const FloatingEdge: FC<EdgeProps> = ({ id, source, target, style }) => {
const { sourceNode, targetNode } = useStore((s) => {
const sourceNode = s.nodes.find((n) => n.id === source);
const targetNode = s.nodes.find((n) => n.id === target);
const sourceNode = s.nodeLookup.get(source);
const targetNode = s.nodeLookup.get(target);
return { sourceNode, targetNode };
});
@@ -1,4 +1,4 @@
import { Position, XYPosition, Node, Edge } from '@xyflow/react';
import { Position, XYPosition, Node, Edge, InternalNode } from '@xyflow/react';
// this helper function returns the intersection point
// of the line between the center of the intersectionNode and the target node
@@ -6,7 +6,7 @@ function getNodeIntersection(intersectionNode: Node, targetNode: Node): XYPositi
// https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a
const { position: intersectionNodePosition } = intersectionNode;
const { width: intersectionNodeWidth, height: intersectionNodeHeight } = intersectionNode.computed ?? {
const { width: intersectionNodeWidth, height: intersectionNodeHeight } = intersectionNode.measured ?? {
width: 0,
height: 0,
};
@@ -42,13 +42,13 @@ function getEdgePosition(node: Node, intersectionPoint: XYPosition) {
if (px <= nx + 1) {
return Position.Left;
}
if (px >= nx + (n.computed?.width ?? 0) - 1) {
if (px >= nx + (n.measured?.width ?? 0) - 1) {
return Position.Right;
}
if (py <= ny + 1) {
return Position.Top;
}
if (py >= n.y + (n.computed?.height ?? 0) - 1) {
if (py >= n.y + (n.measured?.height ?? 0) - 1) {
return Position.Bottom;
}
@@ -56,7 +56,7 @@ function getEdgePosition(node: Node, intersectionPoint: XYPosition) {
}
// returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge
export function getEdgeParams(source: Node, target: Node) {
export function getEdgeParams(source: InternalNode, target: InternalNode) {
const sourceIntersectionPoint = getNodeIntersection(source, target);
const targetIntersectionPoint = getNodeIntersection(target, source);
@@ -137,7 +137,7 @@ const initialNodes: Node[] = [
label: 'Child with extent: parent',
},
position: { x: 50, y: 50 },
parentNode: '5',
parentId: '5',
extent: 'parent',
width: 50,
height: 100,
@@ -148,7 +148,7 @@ const initialNodes: Node[] = [
type: 'defaultResizer',
data: { label: 'Child with expandParent' },
position: { x: 150, y: 100 },
parentNode: '5',
parentId: '5',
expandParent: true,
style: { ...nodeStyle },
},
@@ -157,7 +157,7 @@ const initialNodes: Node[] = [
type: 'defaultResizer',
data: { label: 'Child with expandParent & keepAspectRatio', keepAspectRatio: true },
position: { x: 25, y: 200 },
parentNode: '5',
parentId: '5',
expandParent: true,
style: { ...nodeStyle },
},
@@ -50,7 +50,7 @@ const initialNodes: Node[] = [
data: { label: 'Node 4a' },
position: { x: 15, y: 15 },
className: 'light',
parentNode: '4',
parentId: '4',
origin: [0.5, 0.5],
extent: [
@@ -68,21 +68,21 @@ const initialNodes: Node[] = [
height: 200,
width: 300,
},
parentNode: '4',
parentId: '4',
},
{
id: '4b1',
data: { label: 'Node 4b1' },
position: { x: 40, y: 20 },
className: 'light',
parentNode: '4b',
parentId: '4b',
},
{
id: '4b2',
data: { label: 'Node 4b2' },
position: { x: 20, y: 100 },
className: 'light',
parentNode: '4b',
parentId: '4b',
},
{
id: '5',
@@ -98,7 +98,7 @@ const initialNodes: Node[] = [
data: { label: 'Node 5a' },
position: { x: 0, y: 0 },
className: 'light',
parentNode: '5',
parentId: '5',
extent: 'parent',
},
{
@@ -106,7 +106,7 @@ const initialNodes: Node[] = [
data: { label: 'Node 5b' },
position: { x: 225, y: 50 },
className: 'light',
parentNode: '5',
parentId: '5',
expandParent: true,
},
{
@@ -160,7 +160,7 @@ const Subflow = () => {
const updatePos = () => {
setNodes((nds) => {
return nds.map((n) => {
if (!n.parentNode) {
if (!n.parentId) {
return {
...n,
position: {
@@ -194,7 +194,7 @@ const Subflow = () => {
return nds.map((n) => {
return {
...n,
hidden: !!n.parentNode && !n.hidden,
hidden: !!n.parentId && !n.hidden,
};
});
});