gojs实现蚂蚁线动画效果


Posted in Javascript onFebruary 18, 2022

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

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

一、gojs 实现

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

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

gojs实现蚂蚁线动画效果

1. 绘图

<!-- 容器 -->
<div id="myDiagramDiv" style="height:600px;width: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]

gojs实现蚂蚁线动画效果

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 {
  width: 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%;
  }
}

gojs实现蚂蚁线动画效果

到此这篇关于gojs实现蚂蚁线动画效果的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
浏览器窗口加载和大小改变事件示例
Feb 27 Javascript
JavaScript组合拼接字符串的效率对比测试
Nov 06 Javascript
JS基于面向对象实现的放烟花效果
May 07 Javascript
jQuery+canvas实现的球体平抛及颜色动态变换效果
Jan 28 Javascript
jQuery+ajax实现实用的点赞插件代码
Jul 06 Javascript
bootstrap手风琴制作方法详解
Jan 11 Javascript
浅谈js中同名函数和同名变量的执行问题
Feb 12 Javascript
javascript设计模式之单体模式学习笔记
Feb 15 Javascript
jquery请求servlet实现ajax异步请求的示例
Jun 03 jQuery
Vue学习笔记进阶篇之过渡状态详解
Jul 14 Javascript
JS实现水平遍历和嵌套递归操作示例
Aug 15 Javascript
Antd的table组件表格的序号自增操作
Oct 27 Javascript
uni-app 微信小程序授权登录的实现步骤
Feb 18 #Javascript
详解TypeScript的基础类型
Feb 18 #Javascript
详解jQuery的核心函数和事件处理
Feb 18 #jQuery
JavaScript事件的委托(代理)的用法示例详解
Feb 18 #Javascript
vue项目中的支付功能实现(微信支付和支付宝支付)
Feb 18 #Vue.js
vue3获取当前路由地址
Feb 18 #Vue.js
如何利用React实现图片识别App
You might like
实用函数8
2007/11/08 PHP
基于php使用memcache存储session的详解
2013/06/25 PHP
PHP会话控制:Session与Cookie详解
2014/09/27 PHP
使用WAMP搭建PHP本地开发环境
2017/05/10 PHP
thinkphp分页集成实例
2017/07/24 PHP
PHP安装BCMath扩展的方法
2019/02/13 PHP
PHP 7.4中使用预加载的方法详解
2019/07/08 PHP
JavaScript实现16进制颜色值转RGB的方法
2015/02/09 Javascript
nodejs简单实现中英文翻译
2015/05/04 NodeJs
jQuery简单操作cookie的插件实例
2016/01/13 Javascript
BootStrap点击下拉菜单项后显示一个新的输入框实现代码
2016/05/16 Javascript
JS实现获取剪贴板内容的方法
2016/06/21 Javascript
npm配置国内镜像资源+淘宝镜像的方法
2018/09/07 Javascript
[01:00:59]VP VS VG Supermajor小组赛胜者组第二轮 BO3第二场 6.2
2018/06/03 DOTA
python从sqlite读取并显示数据的方法
2015/05/08 Python
用python实现的线程池实例代码
2018/01/06 Python
Python判断一个三位数是否为水仙花数的示例
2018/11/13 Python
python爬取cnvd漏洞库信息的实例
2019/02/14 Python
python TK库简单应用(实时显示子进程输出)
2019/10/29 Python
tensorflow 模型权重导出实例
2020/01/24 Python
Python如何把Spark数据写入ElasticSearch
2020/04/18 Python
DHC美国官网:日本通信销售第一的化妆品品牌
2017/11/12 全球购物
职专应届生求职信
2013/11/16 职场文书
优秀管理者获奖感言
2014/02/17 职场文书
机关道德讲堂实施方案
2014/03/15 职场文书
春节联欢晚会主持词
2014/03/24 职场文书
市场营销毕业生自荐信范文
2014/04/01 职场文书
护士上岗前培训自我鉴定
2014/04/20 职场文书
英语课前三分钟演讲稿(6篇)
2014/09/13 职场文书
委托书的写法
2014/09/16 职场文书
担保书范本
2015/01/20 职场文书
工程项目合作意向书
2015/05/08 职场文书
小学毕业教师寄语
2019/06/21 职场文书
Apache压力测试工具的安装使用
2021/03/31 Servers
vue实现可以快进后退的跑马灯组件
2022/04/08 Vue.js
python实现学生信息管理系统(面向对象)
2022/06/05 Python