zoukankan      html  css  js  c++  java
  • gojs 如何实现虚线(蚂蚁线)动画?

    在绘制 dag 图时,通过节点和来箭头的连线来表示节点彼此之间的关系。而节点常常又带有状态,为了更好的表示节点之间的流程关系,loading 状态的节点,与后续节点之间,需要用 动画着的虚线 表示,表示正在处理中,处理完才会变成实线。原理同页面没加载出来之间,加个 loading 提示,能提供更好的交互体验

    • 那么如何用 gojs 实现这个效果呢?虚线,及虚线动画
    • 虚线及虚线动画的背后原理是什么?
    • 虚线为什么又叫蚂蚁线?
    • 纯 css 可以实现吗?

    一、gojs 实现

    gojs 的基础使用,可参考之前写的文章数据可视化 gojs 简单使用介绍

    举例:国庆快到了,出游,从上海到北京,假设当前正在途径安徽到山东的路上。用 gojs 绘制出来如下:

    demo

    1. 绘图

    <!-- 容器 -->
    <div id="myDiagramDiv" style="height:600px;100%;border:1px solid black"></div>
    
    <!-- 引入gojs -->
    <script src="https://unpkg.com/gojs/release/go.js"></script>
    
    // 生成器
    const $ = go.GraphObject.make;
    
    // 定义容器,myDiagramDiv 为容器 id
    const diagram = $(go.Diagram, 'myDiagramDiv');
    
    // 节点模板,描述了如何构造每个节点
    diagram.nodeTemplate = $(go.Node, "Auto", // 框自动适应文本
      $(go.Shape, "RoundedRectangle", new go.Binding("fill", "color")),
      $(go.TextBlock, {margin: 5}, new go.Binding("text", "name"))
    );
    
    // 定义model, 描述节点信息和连线信息
    diagram.model = new go.GraphLinksModel(
      [ // 节点
        { key: 'shanghai', name: "出发地 上海", color: "lightblue" },
        { key: 'jiangsu', name: "途径地 江苏", color: "pink" },
        { key: 'anhui', name: "途径地 安徽", color: "pink" },
        { key: 'shandong', name: "途径地 山东", color: "orange"},
        { key: 'hebei', name: "途径地 河北", color: "orange" },
        { key: 'tianjin', name: "途径地 天津", color: "orange" },
        { key: 'beijing', name: "目的地 北京", color: "lightgreen" }
      ],
      [ // 连线
        { from: "shanghai", to: "jiangsu" },
        { from: "jiangsu", to: "anhui" },
        { from: "anhui", to: "shandong" },
        { from: "shandong", to: "hebei" },
        { from: "hebei", to: "tianjin" },
        { from: "tianjin", to: "beijing" }
      ]
    );
    

    至此,一个简单的出游途径地关系图就绘制好了,但是没有虚线动画。

    2. 虚线实现

    观察实现的图中既有实线,也有虚线,所以这儿需要用到 templateMap

    定义实线及虚线模板

    // 定义集合,存储实线、虚线模板
    const templmap = new go.Map()
    const color = '#000'
    
    // 默认连线模板
    const defaultTemplate = $(
      go.Link,
      $(go.Shape, { stroke: color, strokeWidth: 1 }),
      $(go.Shape, { toArrow: 'Standard', fill: color, stroke: color, strokeWidth: 1 })
    )
    
    // 虚线连线模板,关键属性:strokeDashArray: [6, 3]
    const dashedTemplate = $(
      go.Link,
      // name: 'dashedLink',后面动画用到
      $(go.Shape, { name: 'dashedLink', stroke: color, strokeWidth: 1, strokeDashArray: [6, 3] }),
      $(go.Shape, { toArrow: 'Standard', fill: color, stroke: color, strokeWidth: 1 })
    )
    
    templmap.add('', defaultTemplate)
    // dashed 为名称,描述时用属性 category: 'dashed' 指定
    templmap.add('dashed', dashedTemplate)
    
    diagram.linkTemplateMap = templmap
    

    model 数据找到需要描述为虚线的边,加如属性:category: 'dashed',名称需要和定义模板指定的名称一致

    { from: "anhui", to: "shandong", category: 'dashed' },
    

    至此,实线、虚线,都绘制好了。接下来就是最后的动画了。

    3. 让虚线动起来

    找到虚线,更改属性:strokeDashOffset

    有两种方式

    方式1:go.Animation,会导致节点端口交互时连线操作有粘粘效果

    function animation () {
      const animation = new go.Animation();
      // 虚线动画
      diagram.links.each((link) => {
        const dashedLink = link.findObject("dashedLink");
        if (dashedLink) {
          animation.add(dashedLink, "strokeDashOffset", 10, 0)
        }
      });
    
      animation.easing = go.Animation.EaseLinear;
      // Run indefinitely
      animation.runCount = Infinity;
      animation.start();
    }
    animation()
    

    方式2:timeout

    function animation () {
      const loop = () => {
        animationTimer = setTimeout(() => {
          const oldskips = diagram.skipsUndoManager;
          diagram.skipsUndoManager = true;
          // 虚线动画
          diagram.links.each((link) => {
            const dashedLinkShape = link.findObject("dashedLink");
            if (dashedLinkShape) {
              const off = dashedLinkShape.strokeDashOffset - 3;
              // 设置(移动)笔划划动画
              dashedLinkShape.strokeDashOffset = (off <= 0) ? 60 : off;
            }
          });
    
          diagram.skipsUndoManager = oldskips;
          loop();
        }, 180);
      }
      loop()
    }
    animation()
    

    动画的两种方式,如果没有节点端口连线交互,建议用第一种方式实现,库的动画(可能内部做了优化)。如果想更灵活的控制动画或者第一种实现不了时,那么请用第二种方式。

    至此,整个效果就完成了。

    二、虚线及虚线动画背后的原理

    上面的代码,主要用到了 2 个关键的属性:strokeDashArraystrokeDashOffset

    文档上有这么两行说明:

    For more information, see Stroke Line Dash Array (w3.org),see Stroke Line Dash Offset (w3.org)

    背后就是 canvas,及其两个属性 setLineDashlineDashOffset

    参考:

    mdn - setLineDah:一个Array数组。一组描述交替绘制线段和间距(坐标空间单位)长度的数字。 如果数组元素的数量是奇数, 数组的元素会被复制并重复。

    代码示例:

    function drawDashedLine(pattern) {
      ctx.beginPath();
      ctx.setLineDash(pattern);
      ctx.moveTo(0, y);
      ctx.lineTo(300, y);
      ctx.stroke();
      y += 20;
    }
    
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    let y = 15;
    
    drawDashedLine([]);
    drawDashedLine([1, 1]);
    drawDashedLine([10, 10]);
    drawDashedLine([20, 5]);
    drawDashedLine([15, 3, 3, 3]);
    drawDashedLine([20, 3, 3, 3, 3, 3, 3, 3]);
    drawDashedLine([12, 3, 3]);  // Equals [12, 3, 3, 12, 3, 3]
    

    mdn - lineDashOffset:设置虚线偏移量的属性

    代码示例:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var offset = 0;
    
    function draw() {
      ctx.clearRect(0,0, canvas.width, canvas.height);
      ctx.setLineDash([4, 2]);
      ctx.lineDashOffset = -offset;
      ctx.strokeRect(10,10, 100, 100);
    }
    
    function march() {
      offset++;
      if (offset > 16) {
        offset = 0;
      }
      draw();
      setTimeout(march, 20);
    }
    
    march();
    

    三、虚线的一些概念

    虚线:(数学概念)以点或者短线画成的断续的线,多用于几何图形或者标记。

    为什么虚线称为蚂蚁线?
    在图像影像软件中表示选区的动态虚线,因为虚线闪烁的样子像是一群蚂蚁在跑,所以俗称蚂蚁线。
    在Photoshop,After Effect等软件中比较常见。

    蚂蚁线:动物的一种本能现象,领头的蚂蚁以随机的路线走向食物或洞穴,第二只蚂蚁紧跟其后以相同的路线行走,每一个后来的蚂蚁紧跟前面蚂蚁行走,排成一条线的现象。

    虚线的特征:流动性

    四、css 绘制边框虚线

    利用 css 的 border-style 绘制,有两个属性值:

    • dotted:显示为一系列圆点。标准中没有定义两点之间的间隔大小,视不同实现而定。圆点半径是 border-width 计算值的一半。
    • dashed:显示为一系列短的方形虚线。标准中没有定义线段的长度和大小,视不同实现而定。

    具体参考 mdn - border-style

    css 原生属性能实现虚线效果,但是要在此基础上实现动画,不容易。但是可以用 css 的其他属性来实现。

    示例:

    <div class="container">蚂蚁线</div>
    
    .container {
       100px;
      height: 100px;
      padding: 5px;
      border: 1px solid transparent;
      background: linear-gradient(white, white) padding-box,
        repeating-linear-gradient(-45deg, black 0, black, 25%, transparent 0, transparent 50%) 0% 0% / 0.6em 0.6em;
      animation: ants 10s linear infinite;
    }
    
    @keyframes ants {
      to {
        background-position: 100% 100%;
      }
    }
    
  • 相关阅读:
    mysql 允许远程登陆
    jade报错:unexpected token
    quartz定时任务
    Java调用脚本
    CentOS安装、卸载jdk
    CentOS系统没有javac命令
    IDEA Error:java: 未结束的字符串文字
    面试连环炮系列(三):synchronized怎么用的
    面试连环炮系列(二):你们的项目Redis做了集群部署吗
    面试连环炮系列(一):如何保证Redis高可用和高并发
  • 原文地址:https://www.cnblogs.com/EnSnail/p/13835122.html
Copyright © 2011-2022 走看看