gojs實(shí)現(xiàn)螞蟻線(xiàn)動(dòng)畫(huà)效果
在繪制 dag 圖時(shí),通過(guò)節(jié)點(diǎn)和來(lái)箭頭的連線(xiàn)來(lái)表示節(jié)點(diǎn)彼此之間的關(guān)系。而節(jié)點(diǎn)常常又帶有狀態(tài),為了更好的表示節(jié)點(diǎn)之間的流程關(guān)系,loading 狀態(tài)的節(jié)點(diǎn),與后續(xù)節(jié)點(diǎn)之間,需要用 動(dòng)畫(huà)著的虛線(xiàn) 表示,表示正在處理中,處理完才會(huì)變成實(shí)線(xiàn)。原理同頁(yè)面沒(méi)加載出來(lái)之間,加個(gè) loading 提示,能提供更好的交互體驗(yàn)。
- 那么如何用 gojs 實(shí)現(xiàn)這個(gè)效果呢?虛線(xiàn),及虛線(xiàn)動(dòng)畫(huà)
- 虛線(xiàn)及虛線(xiàn)動(dòng)畫(huà)的背后原理是什么?
- 虛線(xiàn)為什么又叫螞蟻線(xiàn)?
- 純 css 可以實(shí)現(xiàn)嗎?
一、gojs 實(shí)現(xiàn)
gojs 的基礎(chǔ)使用,可參考之前寫(xiě)的文章數(shù)據(jù)可視化 gojs 簡(jiǎn)單使用介紹。
舉例:國(guó)慶快到了,出游,從上海到北京,假設(shè)當(dāng)前正在途徑安徽到山東的路上。用 gojs 繪制出來(lái)如下:

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');
// 節(jié)點(diǎn)模板,描述了如何構(gòu)造每個(gè)節(jié)點(diǎn)
diagram.nodeTemplate = $(go.Node, "Auto", // 框自動(dòng)適應(yīng)文本
$(go.Shape, "RoundedRectangle", new go.Binding("fill", "color")),
$(go.TextBlock, {margin: 5}, new go.Binding("text", "name"))
);
// 定義model, 描述節(jié)點(diǎn)信息和連線(xiàn)信息
diagram.model = new go.GraphLinksModel(
[ // 節(jié)點(diǎn)
{ key: 'shanghai', name: "出發(fā)地 上海", 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" }
],
[ // 連線(xiàn)
{ from: "shanghai", to: "jiangsu" },
{ from: "jiangsu", to: "anhui" },
{ from: "anhui", to: "shandong" },
{ from: "shandong", to: "hebei" },
{ from: "hebei", to: "tianjin" },
{ from: "tianjin", to: "beijing" }
]
);至此,一個(gè)簡(jiǎn)單的出游途徑地關(guān)系圖就繪制好了,但是沒(méi)有虛線(xiàn)動(dòng)畫(huà)。
2. 虛線(xiàn)實(shí)現(xiàn)
觀察實(shí)現(xiàn)的圖中既有實(shí)線(xiàn),也有虛線(xiàn),所以這兒需要用到 templateMap。
定義實(shí)線(xiàn)及虛線(xiàn)模板
// 定義集合,存儲(chǔ)實(shí)線(xiàn)、虛線(xiàn)模板
const templmap = new go.Map()
const color = '#000'
// 默認(rèn)連線(xiàn)模板
const defaultTemplate = $(
go.Link,
$(go.Shape, { stroke: color, strokeWidth: 1 }),
$(go.Shape, { toArrow: 'Standard', fill: color, stroke: color, strokeWidth: 1 })
)
// 虛線(xiàn)連線(xiàn)模板,關(guān)鍵屬性:strokeDashArray: [6, 3]
const dashedTemplate = $(
go.Link,
// name: 'dashedLink',后面動(dòng)畫(huà)用到
$(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 為名稱(chēng),描述時(shí)用屬性 category: 'dashed' 指定
templmap.add('dashed', dashedTemplate)
diagram.linkTemplateMap = templmapmodel 數(shù)據(jù)找到需要描述為虛線(xiàn)的邊,加如屬性:category: 'dashed',名稱(chēng)需要和定義模板指定的名稱(chēng)一致
{ from: "anhui", to: "shandong", category: 'dashed' },至此,實(shí)線(xiàn)、虛線(xiàn),都繪制好了。接下來(lái)就是最后的動(dòng)畫(huà)了。
3. 讓虛線(xiàn)動(dòng)起來(lái)
找到虛線(xiàn),更改屬性:strokeDashOffset
有兩種方式
- 方式1:go.Animation,會(huì)導(dǎo)致節(jié)點(diǎn)端口交互時(shí)連線(xiàn)操作有粘粘效果
function animation () {
const animation = new go.Animation();
// 虛線(xiàn)動(dòng)畫(huà)
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;
// 虛線(xiàn)動(dòng)畫(huà)
diagram.links.each((link) => {
const dashedLinkShape = link.findObject("dashedLink");
if (dashedLinkShape) {
const off = dashedLinkShape.strokeDashOffset - 3;
// 設(shè)置(移動(dòng))筆劃劃動(dòng)畫(huà)
dashedLinkShape.strokeDashOffset = (off <= 0) ? 60 : off;
}
});
diagram.skipsUndoManager = oldskips;
loop();
}, 180);
}
loop()
}
animation()動(dòng)畫(huà)的兩種方式,如果沒(méi)有節(jié)點(diǎn)端口連線(xiàn)交互,建議用第一種方式實(shí)現(xiàn),庫(kù)的動(dòng)畫(huà)(可能內(nèi)部做了優(yōu)化)。如果想更靈活的控制動(dòng)畫(huà)或者第一種實(shí)現(xiàn)不了時(shí),那么請(qǐng)用第二種方式。
至此,整個(gè)效果就完成了。
二、虛線(xiàn)及虛線(xiàn)動(dòng)畫(huà)背后的原理
上面的代碼,主要用到了 2 個(gè)關(guān)鍵的屬性:strokeDashArray、strokeDashOffset。
文檔上有這么兩行說(shuō)明:
For more information, see Stroke Line Dash Array (w3.org),see Stroke Line Dash Offset (w3.org)
背后就是 canvas,及其兩個(gè)屬性 setLineDash、lineDashOffset
參考:
mdn - setLineDah:一個(gè)Array數(shù)組。一組描述交替繪制線(xiàn)段和間距(坐標(biāo)空間單位)長(zhǎng)度的數(shù)字。 如果數(shù)組元素的數(shù)量是奇數(shù), 數(shù)組的元素會(huì)被復(fù)制并重復(fù)。
代碼示例:
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:設(shè)置虛線(xiàn)偏移量的屬性
代碼示例:
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();三、虛線(xiàn)的一些概念
虛線(xiàn):(數(shù)學(xué)概念)以點(diǎn)或者短線(xiàn)畫(huà)成的斷續(xù)的線(xiàn),多用于幾何圖形或者標(biāo)記。
為什么虛線(xiàn)稱(chēng)為螞蟻線(xiàn)?
在圖像影像軟件中表示選區(qū)的動(dòng)態(tài)虛線(xiàn),因?yàn)樘摼€(xiàn)閃爍的樣子像是一群螞蟻在跑,所以俗稱(chēng)螞蟻線(xiàn)。
在Photoshop,After Effect等軟件中比較常見(jiàn)。
螞蟻線(xiàn):動(dòng)物的一種本能現(xiàn)象,領(lǐng)頭的螞蟻以隨機(jī)的路線(xiàn)走向食物或洞穴,第二只螞蟻緊跟其后以相同的路線(xiàn)行走,每一個(gè)后來(lái)的螞蟻緊跟前面螞蟻行走,排成一條線(xiàn)的現(xiàn)象。
虛線(xiàn)的特征:流動(dòng)性
四、css 繪制邊框虛線(xiàn)
利用 css 的 border-style 繪制,有兩個(gè)屬性值:
- dotted:顯示為一系列圓點(diǎn)。標(biāo)準(zhǔn)中沒(méi)有定義兩點(diǎn)之間的間隔大小,視不同實(shí)現(xiàn)而定。圓點(diǎn)半徑是 border-width 計(jì)算值的一半。
- dashed:顯示為一系列短的方形虛線(xiàn)。標(biāo)準(zhǔn)中沒(méi)有定義線(xiàn)段的長(zhǎng)度和大小,視不同實(shí)現(xiàn)而定。
具體參考 mdn - border-style
css 原生屬性能實(shí)現(xiàn)虛線(xiàn)效果,但是要在此基礎(chǔ)上實(shí)現(xiàn)動(dòng)畫(huà),不容易。但是可以用 css 的其他屬性來(lái)實(shí)現(xiàn)。
示例:
<div class="container">螞蟻線(xiàn)</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%;
}
}
到此這篇關(guān)于gojs實(shí)現(xiàn)螞蟻線(xiàn)動(dòng)畫(huà)效果的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
起點(diǎn)頁(yè)面?zhèn)髦礿s,有空研究學(xué)習(xí)下
起點(diǎn)上的頁(yè)面?zhèn)髦礿s,有空研究下2010-01-01
javascript appendChild,innerHTML,join性能比較代碼
在實(shí)際應(yīng)用中,應(yīng)該避免直接用innerHTML,對(duì)于大量的字符連接運(yùn)算,應(yīng)該考慮先運(yùn)算再輸出。2009-08-08
比較詳細(xì)的關(guān)于javascript中void(0)的具體含義解釋
比較詳細(xì)的關(guān)于javascript中void(0)的具體含義解釋...2007-08-08
如何用JS WebSocket實(shí)現(xiàn)簡(jiǎn)單聊天
這篇文章主要介紹了如何用JS WebSocket實(shí)現(xiàn)簡(jiǎn)單聊天,對(duì)websocket感興趣的同學(xué),可以參考下2021-05-05
極力推薦一款小巧玲瓏的可視化編輯器bootstrap-wysiwyg
這篇文章主要為大家極力推薦一款小巧玲瓏的可視化編輯器bootstrap-wysiwyg,是一款基于jquery和bootstrap的可視化編輯器,感興趣的小伙伴們可以參考一下2016-05-05
詳解如何優(yōu)雅迭代JavaScript字面對(duì)象
迭代是訪問(wèn)集合元素的一種方法,可以被迭代的對(duì)象稱(chēng)為可迭代對(duì)象,下面這篇文章主要給大家介紹了關(guān)于如何優(yōu)雅迭代JavaScript字面對(duì)象的相關(guān)資料,需要的朋友可以參考下2022-05-05

