如何让AntV X6 的连线“动”起来:实现流动效果?

AntV X6 是一款功能强大的图编辑引擎,它提供了丰富的节点和边的定制能力。在许多业务场景中,例如流程图、数据血缘分析、网络拓扑图等,我们不仅需要静态地展示节点和它们之间的关系,还希望能够动态地表示方向和流动。让连线拥有流动的动画效果,就是一个非常直观且常见的需求。

那么如何实现?

一、实现原理

AntV X6 的画布是基于 SVG 渲染的,而连线的流动效果,其背后是利用了 SVG path 元素的两个关键属性:stroke-dasharraystroke-dashoffset

  1. stroke-dasharray:定义虚线样式

    这个属性可以把一条实线变成虚线。它接受一组数字,用于定义"实线"和"空白"的长度。

    • stroke-dasharray: "5 5" 会创建一段 5px 的实线,然后是一段 5px 的空白,如此循环。
    • stroke-dasharray: "10 5" 会创建一段 10px 的实线,然后是一段 5px 的空白。
  2. stroke-dashoffset:定义虚线的起始偏移

    这个属性定义了虚线图案开始绘制的位置距离路径起点的偏移量。默认值为 0。如果我们动态地改变这个值,虚线图案就会沿着路径移动起来。

我们先用 stroke-dasharray 将一条普通的实线变成我们想要的虚线样式(比如一小段线段加一大段空白)。然后,通过 CSS 动画或 JavaScript,不断地、周期性地改变 stroke-dashoffset 的值,让虚线图案看起来就像在路径上平移,从而产生了"流动"的视觉效果。

二、实现思路

整个实现过程非常清晰,可以分为以下三步:

  1. 获取边的 SVG 路径 :在 X6 中,每一条边都对应一个 SVG 的 path 元素。我们可以通过边的 attrs 属性来操作它。

  2. 设置虚线样式 :为这条 path 设置 stroke-dasharray 属性,定义流动线段的长度和间隔。

  3. 创建并应用动画

    • CSS 方案 (推荐) :定义一个 CSS @keyframes 动画规则,该规则持续改变 stroke-dashoffset 的值。然后,将这个动画应用到指定的 path 元素上。这是最简单且性能较好的方法。
    • JavaScript 方案 :通过 requestAnimationFrame 创建一个动画循环,在每一帧中手动更新 path 元素的 stroke-dashoffset 样式。这种方案控制更灵活,可以动态地开始、暂停或改变速度。

接下来,我们将展示如何使用 CSS 方案来实现

三、实战代码

我们将创建一个包含两个节点和一条流动连线的简单示例

在下面的代码中:

  • 我们通过 attrs 属性为边的 line (即 path 元素) 添加了一个 CSS 类名 running-line
  • 在 CSS 中,我们为 .running-line 类定义了 stroke-dasharrayanimation 属性。
  • @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>
相关推荐
袁煦丞2 小时前
WebSocket实时通信不卡顿:cpolar内网穿透实验室第503个成功挑战
前端·程序员·远程工作
YuspTLstar2 小时前
Redux从入门到进阶
前端·react.js
云枫晖3 小时前
JS核心知识-闭包
前端·javascript
前端老鹰3 小时前
HTML `<meter>` 标签:原生度量衡指示器,直观展示百分比、评分等量化数据
前端·html
赵明飞3 小时前
如何配置GDO51和GDI51网关通过Basic Station连接到ChirpStack平台
前端
前端康师傅3 小时前
Javascript 数组基础用法
前端·javascript
胖鱼罐头3 小时前
Android-尺寸单位换算全解析
前端
召摇3 小时前
命令-查询分离原则(Command-Query Separation)
前端·javascript·面试
不一样的少年_3 小时前
别再无脑装插件了!你的浏览器扩展可能正在“偷家”
前端·安全·浏览器