Skip to Content
示例Edges

动画边缘

React Flow 为默认边类型提供了一个简单的内置动画,但也可以通过使用自定义边创建更高级的动画。以下是一些示例,展示边路径可能的不同使用方式

🌐 React Flow provides a simple built-in animation for the default edge type, but it is possible to create more advanced animations by using custom edges. Below are a collection of examples showing different ways an edge path might be used in

动画 SVG 元素

🌐 Animating SVG elements

可以使用 <animateMotion /> 元素沿路径动画化 SVG 元素。这个示例创建了一个自定义边缘,使圆沿边缘路径动画移动。

🌐 It is possible to animate an SVG element along a path using the <animateMotion /> element. This example creates a custom edge that animates a circle along the edge path.

import React from 'react'; import { BaseEdge, getSmoothStepPath, type EdgeProps } from '@xyflow/react'; export function AnimatedSVGEdge({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, }: EdgeProps) { const [edgePath] = getSmoothStepPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition, }); return ( <> <BaseEdge id={id} path={edgePath} /> <circle r="10" fill="#ff0073"> <animateMotion dur="2s" repeatCount="indefinite" path={edgePath} /> </circle> </> ); }

动画其他节点

🌐 Animating other nodes

如果你想沿着一条边动画化超过 SVG 的内容,你可以使用 Web Animations API 来实现。这个示例演示了如何通过使用 offsetPath 属性并动画化 offsetDistance 属性来沿着边路径动画化流中的另一个节点。

🌐 If you want to animate more than SVG along an edge, you can do that with the Web Animations API. This example demonstrates how to animate another node in the flow along an edge path by using the offsetPath property and animating the offsetDistance property.

import { useEffect, useMemo } from 'react'; import { BaseEdge, getBezierPath, useReactFlow, type Edge, type EdgeProps, } from '@xyflow/react'; export type AnimatedNodeEdge = Edge<{ node: string }, 'animatedNode'>; export function AnimatedNodeEdge({ id, data = { node: '' }, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, }: EdgeProps<AnimatedNodeEdge>) { const { getNode, updateNode } = useReactFlow(); const [edgePath] = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition, }); const selector = useMemo( () => `.react-flow__node[data-id="${data.node}"]`, [data.node], ); useEffect(() => { const node = document.querySelector(selector) as HTMLElement; if (!node) return; node.style.offsetPath = `path('${edgePath}')`; node.style.offsetRotate = '0deg'; // This property is fairly new and not all versions of TypeScript have it // in the lib.dom.d.ts file. If you get an error here, you can either // ignore it or add the property to the CSSStyleDeclaration interface // yourself. // // @ts-expect-error node.style.offsetAnchor = 'center'; let wasDraggable = getNode(data.node).draggable; updateNode(data.node, { draggable: false }); return () => { node.style.offsetPath = 'none'; updateNode(data.node, { draggable: wasDraggable }); }; }, [selector, edgePath]); useEffect(() => { const node = document.querySelector(selector) as HTMLElement; if (!node) return; const keyframes = [{ offsetDistance: '0%' }, { offsetDistance: '100%' }]; const animation = node.animate(keyframes, { duration: 2000, direction: 'alternate', iterations: Infinity, }); return () => { animation.cancel(); }; }, [selector]); return <BaseEdge id={id} path={edgePath} />; }

此示例中有一些重要的细节需要注意:

🌐 There are some important details in this example to take note of:

  • 当动画运行时,动画节点的 draggable 属性被设置为 false。这可以防止用户移动节点并破坏动画路径。
  • 动画路径和动画本身是在不同的 useEffect 钩子中设置的。这让动画即使在边路径被重新计算时(例如,当源节点或目标节点被拖动时)也能继续平滑播放。
Last updated on