Skip to Content

边标签

¥Edge Labels

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

¥One of the more common uses for custom edges is rendering some controls or info along an edge’s path. In React Flow we call that an edge label and unlike the edge path, edge labels can be any React component!

添加边标签

¥Adding an edge label

要渲染自定义边缘标签,我们必须将其封装在 <EdgeLabelRenderer /> 组件中。这使得我们可以在边所在的 SVG 世界之外渲染标签。边标签渲染器是一个指向单个容器的入口,所有边标签都渲染到该容器中。

¥To render a custom edge label we must wrap it in the <EdgeLabelRenderer /> component. This allows us to render the labels outside of the SVG world where the edges life. The edge label renderer is a portal to a single container that all edge labels are rendered into.

让我们在自定义边上添加一个按钮,该按钮可用于删除它所附加的边:

¥Let’s add a button to our custom edge that can be used to delete the edge it’s attached to:

import { BaseEdge, EdgeLabelRenderer, getStraightPath, useReactFlow, } from '@xyflow/react'; export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY }) { const { deleteElements } = useReactFlow(); const [edgePath] = getStraightPath({ sourceX, sourceY, targetX, targetY, }); return ( <> <BaseEdge id={id} path={edgePath} /> <EdgeLabelRenderer> <button onClick={() => deleteElements({ edges: [{ id }] })}>delete</button> </EdgeLabelRenderer> </> ); }

如果我们现在尝试使用这个边缘,我们会看到按钮被渲染在流的中心(它可能隐藏在 “节点 A” 后面)。由于边缘标签门户,我们需要做一些额外的工作来自己定位按钮。

¥If we try to use this edge now, we’ll see that the button is rendered in the centre of the flow (it might be hidden behind “Node A”). Because of the edge label portal, we’ll need to do some extra work to position the button ourselves.

A screen shot of a simple flow. The edge label renderer is highlighted in the DOM inspector and the button is rendered in the centre of the flow.

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

¥Fortunately, the path utils we’ve already seen can help us with this! Along with the SVG path to render, these functions also return the x and y coordinates of the path’s midpoint. We can then use these coordinates to translate our custom edge label’s into the right position!

export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY }) { const { deleteElements } = 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={() => { onClick={() => deleteElements({ edges: [{ id }] })} }} > ... ); }

要确保我们的边缘标签具有交互性而不仅仅是为了演示,将 pointer-events: all 添加到标签样式中非常重要。这将确保标签可点击。

¥To make sure our edge labels are interactive and not just for presentation, it is important to add pointer-events: all to the label’s style. This will ensure that the label is clickable.

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

¥And just like with interactive controls in custom nodes, we need to remember to add the nodrag and nopan classes to the label to stop mouse events from controlling the canvas.

以下是我们更新的自定义边缘的交互式示例。单击删除按钮将从流程中移除该边缘。创建新边将使用自定义节点。

¥Here’s an interactive example with our updated custom edge. Clicking the delete button will remove that edge from the flow. Creating a new edge will use the custom node.

import { useCallback } from 'react'; import { ReactFlow, addEdge, useNodesState, useEdgesState, } from '@xyflow/react'; import CustomEdge from './CustomEdge'; import '@xyflow/react/dist/style.css'; const initialNodes = [ { id: 'a', position: { x: 0, y: 0 }, data: { label: 'Node A' } }, { id: 'b', position: { x: 0, y: 100 }, data: { label: 'Node B' } }, { id: 'c', position: { x: 0, y: 200 }, data: { label: 'Node C' } }, ]; const initialEdges = [ { id: 'a->b', type: 'custom-edge', source: 'a', target: 'b' }, { id: 'b->c', type: 'custom-edge', source: 'b', target: 'c' }, ]; const edgeTypes = { 'custom-edge': CustomEdge, }; function Flow() { const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); const onConnect = useCallback( (connection) => { const edge = { ...connection, type: 'custom-edge' }; setEdges((eds) => addEdge(edge, eds)); }, [setEdges], ); return ( <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} edgeTypes={edgeTypes} fitView /> ); } export default Flow;
Last updated on