Skip to Content
代码示例Whiteboard

橡皮擦工具

此示例展示了如何创建一个橡皮擦工具,允许你通过擦除来删除节点和边。它由两部分组成:

¥This example shows how to create an eraser tool that allows you to delete nodes and edges by wiping them out. It’s made up of two parts:

  1. Eraser 组件负责处理擦除逻辑和橡皮擦轨迹的渲染。

    ¥The Eraser component that handles the erasing logic and rendering of the eraser trail.

  2. 自定义 ErasableNodeErasableEdge 组件响应 toBeDeleted 标志。

    ¥The custom ErasableNode and ErasableEdge that reacts to the toBeDeleted flag.

判断路径是否与节点相交非常简单。 - 但是,检测轨迹与边缘之间的交点稍微复杂一些:我们通过 SVG 路径元素的 getPointAtLength 方法沿边采样点,构建一条折线,然后我们可以使用它来检测与橡皮擦轨迹的交点。这是性能和准确性之间的权衡。 - 你可以尝试使用 sampleDistance 变量来观察它对橡皮擦轨迹的影响。

¥Determining if the trail intersects with a node is fairly straight forward - however detecting intersections between the trail and an edge is a bit more complex: We sample points along the edge through the getPointAtLength method of the SVG path element, construct a polyline that we can then use to detect intersections with the eraser trail. This is a trade-off between performance and accuracy - you can play around with the sampleDistance variable to see the effect it has on the eraser trail.

import { useCallback, useState } from 'react'; import { ReactFlow, useNodesState, useEdgesState, addEdge, Controls, Background, Panel, } from '@xyflow/react'; import { ErasableNode } from './ErasableNode'; import { ErasableEdge } from './ErasableEdge'; import { Eraser } from './Eraser'; import '@xyflow/react/dist/style.css'; const initialNodes = [ { id: '1', type: 'erasable-node', position: { x: 0, y: 0 }, data: { label: 'Hello' }, }, { id: '2', type: 'erasable-node', position: { x: 300, y: 0 }, data: { label: 'World' }, }, ]; const initialEdges = [ { id: '1->2', type: 'erasable-edge', source: '1', target: '2', }, ]; const nodeTypes = { 'erasable-node': ErasableNode, }; const edgeTypes = { 'erasable-edge': ErasableEdge, }; const defaultEdgeOptions = { type: 'erasable-edge', }; export default function EraserFlow() { const [nodes, _, onNodesChange] = useNodesState(initialNodes); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); const onConnect = useCallback((params) => setEdges((els) => addEdge(params, els)), []); const [isEraserActive, setIsEraserActive] = useState(true); return ( <ReactFlow nodes={nodes} nodeTypes={nodeTypes} edges={edges} edgeTypes={edgeTypes} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} fitView defaultEdgeOptions={defaultEdgeOptions} > <Controls /> <Background /> {isEraserActive && <Eraser />} <Panel position="top-left"> <div className="xy-theme__button-group"> <button className={`xy-theme__button ${isEraserActive ? 'active' : ''}`} onClick={() => setIsEraserActive(true)} > Eraser Mode </button> <button className={`xy-theme__button ${!isEraserActive ? 'active' : ''}`} onClick={() => setIsEraserActive(false)} > Selection Mode </button> </div> </Panel> </ReactFlow> ); }
Last updated on