在繪制 dag 圖時,通過節點和來箭頭的連線來表示節點彼此之間的關系。而節點常常又帶有狀态,為了更好的表示節點之間的流程關系,loading 狀态的節點,與後續節點之間,需要用 動畫着的虛線 表示,表示正在進行中,處理完才會變成實線。原理同頁面沒加載出來之間,加個 loading 提示,能提供更好的互動體驗。
- 那麼如何用 gojs 實作這個效果呢?虛線,及虛線動畫
- 虛線及虛線動畫的背後原理是什麼?
- 虛線為什麼又叫螞蟻線?
- 純 css 可以實作嗎?
一、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 個關鍵的屬性:strokeDashArray、strokeDashOffset。
文檔上有這麼兩行說明:
For more information, see Stroke Line Dash Array (w3.org),see Stroke Line Dash Offset (w3.org)
背後就是 canvas,及其兩個屬性
setLineDash
、
lineDashOffset
參考:
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 {
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%;
}
}
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiYWan5SO4IDN2AzMyMTMtEzNxQzMyQDNxgTMwEDMyAjMtQjM1YDM48CXwEDMyAjMvwFNyUjNwgzLcd2bsJ2Lc12bj5ycn9Gbi52YuAjMwIzZtl2Lc9CX6MHc0RHaiojIsJye.gif)