AntV X6 是一款功能强大的图编辑引擎,它提供了丰富的节点和边的定制能力。在许多业务场景中,例如流程图、数据血缘分析、网络拓扑图等,我们不仅需要静态地展示节点和它们之间的关系,还希望能够动态地表示方向和流动。让连线拥有流动的动画效果,就是一个非常直观且常见的需求。
那么如何实现?
一、实现原理
AntV X6 的画布是基于 SVG 渲染的,而连线的流动效果,其背后是利用了 SVG path
元素的两个关键属性:stroke-dasharray
和 stroke-dashoffset
-
stroke-dasharray:定义虚线样式
这个属性可以把一条实线变成虚线。它接受一组数字,用于定义"实线"和"空白"的长度。
stroke-dasharray: "5 5"
会创建一段 5px 的实线,然后是一段 5px 的空白,如此循环。stroke-dasharray: "10 5"
会创建一段 10px 的实线,然后是一段 5px 的空白。
-
stroke-dashoffset:定义虚线的起始偏移
这个属性定义了虚线图案开始绘制的位置距离路径起点的偏移量。默认值为 0。如果我们动态地改变这个值,虚线图案就会沿着路径移动起来。
我们先用 stroke-dasharray 将一条普通的实线变成我们想要的虚线样式(比如一小段线段加一大段空白)。然后,通过 CSS 动画或 JavaScript,不断地、周期性地改变 stroke-dashoffset 的值,让虚线图案看起来就像在路径上平移,从而产生了"流动"的视觉效果。
二、实现思路
整个实现过程非常清晰,可以分为以下三步:
-
获取边的 SVG 路径 :在 X6 中,每一条边都对应一个 SVG 的
path
元素。我们可以通过边的attrs
属性来操作它。 -
设置虚线样式 :为这条
path
设置stroke-dasharray
属性,定义流动线段的长度和间隔。 -
创建并应用动画:
- CSS 方案 (推荐) :定义一个 CSS
@keyframes
动画规则,该规则持续改变stroke-dashoffset
的值。然后,将这个动画应用到指定的path
元素上。这是最简单且性能较好的方法。 - JavaScript 方案 :通过
requestAnimationFrame
创建一个动画循环,在每一帧中手动更新path
元素的stroke-dashoffset
样式。这种方案控制更灵活,可以动态地开始、暂停或改变速度。
- CSS 方案 (推荐) :定义一个 CSS
接下来,我们将展示如何使用 CSS 方案来实现
三、实战代码
我们将创建一个包含两个节点和一条流动连线的简单示例
在下面的代码中:
- 我们通过
attrs
属性为边的line
(即path
元素) 添加了一个 CSS 类名running-line
。 - 在 CSS 中,我们为
.running-line
类定义了stroke-dasharray
和animation
属性。 @keyframes running-line
动画规则负责将stroke-dashoffset
从 0 变化到 -20,然后循环这个过程,实现了不间断的流动效果。
效果:

完整代码:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AntV X6 流动线表示例</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@antv/x6/dist/x6.css">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
margin: 0;
padding: 20px;
background-color: #f0f2f5;
}
h1 {
text-align: center;
color: #333;
}
#container {
width: 100%;
height: 400px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* --- 核心动画样式 --- */
/* 定义动画 */
@keyframes running-line {
to {
/*
* stroke-dashoffset 会从 0 减到 -20。
* 负值会让虚线图案向前(或路径方向)移动。
* -20 是 stroke-dasharray (10 + 10) 的总长度,
* 这样可以实现无缝循环动画。
*/
stroke-dashoffset: -20;
}
}
/* 将动画应用到带有 .running-line 类的 path 元素上 */
.running-line {
/* * 定义虚线样式: 10px 的实线,后面跟着 10px 的空白。
* 你可以调整这些值来改变流动点的外观。
* 例如 '2 10' 会变成点状流动的效果。
*/
stroke-dasharray: 10 10;
/* * 应用动画:
* running-line: 动画名称
* 1s: 动画周期,即流动一个循环需要1秒
* linear: 动画速度曲线,保持匀速
* infinite: 无限循环
*/
animation: running-line 1s linear infinite;
}
</style>
</head>
<body>
<h1>AntV X6 流动线表示例</h1>
<div id="container"></div>
<!-- 引入 AntV X6 -->
<script src="https://cdn.jsdelivr.net/npm/@antv/x6/dist/x6.js"></script>
<script>
// 1. 创建画布
const graph = new X6.Graph({
container: document.getElementById('container'),
// 开启网格背景
grid: true,
// 节点和边在连接时可以吸附到网格
snapline: true,
// 允许平移和缩放
panning: true,
mousewheel: true,
});
// 2. 创建节点
const sourceNode = graph.addNode({
x: 100,
y: 100,
width: 120,
height: 60,
label: '数据源',
attrs: {
body: {
fill: '#eff4ff',
stroke: '#5f95ff',
rx: 4, // 圆角
ry: 4,
},
label: {
fill: '#333',
fontSize: 14,
}
},
});
const targetNode = graph.addNode({
x: 400,
y: 250,
width: 120,
height: 60,
label: '目的地',
attrs: {
body: {
fill: '#eff4ff',
stroke: '#5f95ff',
rx: 4,
ry: 4,
},
label: {
fill: '#333',
fontSize: 14,
}
},
});
// 3. 创建带流动效果的边
graph.addEdge({
source: sourceNode,
target: targetNode,
// 设置边的样式
attrs: {
line: {
// 将 .running-line class 添加到边的 <path> 元素上
class: 'running-line',
stroke: '#5f95ff', // 边的颜色
strokeWidth: 2,
// 设置目标箭头
targetMarker: 'classic',
},
},
// 使用正交路由,使路径更规整
router: {
name: 'manhattan',
},
});
// 自适应画布尺寸
graph.centerContent();
</script>
</body>
</html>