跳到主要内容

自定义边

与自定义节点一样,React Flow 中的自定义边缘的一部分只是 React 组件:这意味着您可以沿着边缘渲染任何您想要的东西!本指南向您展示如何使用一些附加控件来实现自定义边缘。

基本的自定义边缘

如果边不能渲染两个连接节点之间的路径,那么它对我们来说就没多大用处。这些路径始终基于 SVG,并且通常使用 <BaseEdge /> 组件进行渲染。为了计算要渲染的实际 SVG 路径,React Flow 附带了一些方便的实用函数:

  • getBezierPath
  • getSimpleBezierPath
  • getSmoothStepPath
  • getStraightPath

为了启动我们的自定义边缘,我们只需在源和目标之间渲染一条直线路径。

import { BaseEdge, getStraightPath } from 'reactflow';

export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY }) {
const [edgePath] = getStraightPath({
sourceX,
sourceY,
targetX,
targetY,
});

return (
<>
<BaseEdge id={id} path={edgePath} />
</>
);
}
备注

传递给自定义边缘组件的所有 props 都可以在 EdgeProps 类型下的 API 参考中找到。

这为我们提供了一条直边,其行为与默认的“直”边类型相同。要使用它,我们还需要更新 <ReactFlow /> 组件上的 edgeTypes 属性。

在组件外部定义 EdgeTypes 对象或使用 React 的 useMemo 钩子来防止不必要的重新渲染非常重要。如果您忘记执行此操作,React Flow 将在控制台中显示警告。

import ReactFlow from 'reactflow'
import CustomEdge from './CustomEdge'


const edgeTypes = {
'custom-edge': CustomEdge
}

export function Flow() {
return <ReactFlow edgeTypes={edgeTypes} ... />
}

定义edgeTypes对象后,我们可以通过将边的类型字段设置为“custom-edge”来使用新的自定义边。

参考预览:https://codesandbox.io/p/sandbox/compassionate-babbage-2qmg2h?file=%2FApp.js&utm_medium=sandpack

添加边缘标签

自定义边缘最常见的用途之一是沿着边缘的路径呈现一些控件或信息。在 React Flow 中,我们称之为边缘标签,与边缘路径不同,边缘标签可以是任何 React 组件!

要渲染自定义边缘标签,我们必须将其包装在 <EdgeLabelRenderer /> 组件中。出于性能原因,这是必要的:边缘标签渲染器是所有边缘标签都渲染到其中的单个容器的门户。

让我们向自定义边缘添加一个按钮,可用于删除其附加的边缘:

import {
BaseEdge,
EdgeLabelRenderer,
getStraightPath,
useReactFlow,
} from 'reactflow';

export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY }) {
const { setEdges } = useReactFlow();
const [edgePath] = getStraightPath({
sourceX,
sourceY,
targetX,
targetY,
});

return (
<>
<BaseEdge id={id} path={edgePath} />
<EdgeLabelRenderer>
<button
onClick={() => setEdges((edges) => edges.filter((e) => e.id !== id))}
>
delete
</button>
</EdgeLabelRenderer>
</>
);
}

如果我们现在尝试使用此边缘,我们将看到该按钮呈现在流程的中心(它可能隐藏在“节点 A”后面)。由于边缘标签入口,我们需要做一些额外的工作来自己定位按钮。

幸运的是,我们已经见过的路径实用程序可以帮助我们做到这一点!除了要渲染的 SVG 路径之外,这些函数还返回路径中点的 x 和 y 坐标。然后,我们可以使用这些坐标将自定义边缘标签翻译到正确的位置!

export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY }) {
const { setEdges } = useReactFlow();
const [edgePath, labelX, labelY] = getStraightPath({ ... });

return (
...
<button
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
pointerEvents: 'all',
}}
className="nodrag nopan"
onClick={() => {
setEdges((es) => es.filter((e) => e.id !== id));
}}
>
...
);
}
备注

为了确保我们的边缘标签是交互式的,而不仅仅是用于演示,添加指针事件非常重要:all 到标签的样式。这将确保标签是可点击的。

就像自定义节点中的交互式控件一样,我们需要记住将 nodrag 和 nopan 类添加到标签中,以阻止鼠标事件控制画布。

这是一个带有我们更新的自定义边缘的交互式示例。单击删除按钮将从流中删除该边。创建新边将使用自定义节点。

参考预览:https://codesandbox.io/p/sandbox/happy-meadow-nmp7zs?file=%2FApp.js&utm_medium=sandpack