2016-05-12
用 Canvas 繪制飛線
背景
上一周完成了地圖與飛線的實現(xiàn),使用的是 d3.js + svg榜晦,后發(fā)現(xiàn)可能存在性能隱患冠蒋。
當飛線數(shù)量多的時候,頁面上則有多個 svg <path>
結點乾胶,并且每條飛線有頭部抖剿、結束圓圈朽寞、蒙板等效果,則頁面上的結點數(shù)是 飛線數(shù)*其他部件數(shù)斩郎。將會是一個較大的值脑融。
Canvas 飛線動畫
畫布罩在整個 HTML 上,共兩層 Canvas 畫布缩宜,底層繪制世界地圖肘迎,表層繪制飛線。
與 SVG 飛線 對比
- SVG 飛線:
- 一條飛線是一個 SVG
<path>
結點锻煌; - 使用 d3.js 中
.transition()
下的子方法.attrTween()
妓布,對于中間幀每一個狀態(tài),改變其<path>
結點里的d
屬性宋梧;
- 一條飛線是一個 SVG
- Canvas 飛線:
- 底下的地圖繪制在一張畫布中匣沼,而飛線繪制在另一張畫布中;
- 每一幀都重新清除掉飛線畫布捂龄,重新繪制每一條飛線肛著;
兩者共同點:
- 通過不斷計算飛線 p 點(起、終點之間的任一點)的位置跺讯,一次次繪制從起點到 p 的二次貝塞爾曲線枢贿;
- 飛線的起點不變,p 點坐標不斷改變
二次貝塞爾曲線公式
(其中 起始點 p0, 控制點 p1, 終點 p2)
t 從 0 變到 1刀脏,每個 t 的變化時局荚,就繪制一幀;
飛線的速度就取決于增量變化的大小愈污,增量越小耀态,動畫就越細致。
如何表現(xiàn) t 暂雹?
給每一個飛線對象單獨一個 t 屬性首装,每繪制完一幀,t = t + 增量(固定值)杭跪;
requestAnimationFrame 動畫
飛線取數(shù)設計
- 總數(shù)據(jù)池: -不斷輪詢服務端仙逻,增加要繪制飛線的數(shù)據(jù);
- 飛線數(shù)據(jù): 存放的是每一幀要繪制在頁面上的飛線涧尿。 只要有值系奉,就用
requestAnimationFrame
不斷調用動畫;
飛線樣式
與 SVG 飛線 相比:
-
SVG 飛線:
- 使用蒙板跟隨飛線尾部的方式
-
Canvas 飛線
- 使用漸變填充色姑廉,對每一條飛線缺亮,都重新生成該飛線起點到 p 點的線性漸變;
漸變消失: ctx.globalAlpha
另一種飛線動畫的實現(xiàn)方式
使用 globalAlpha 和 臨時 Canvas桥言;
但有兩個弊端:
- 無法做停留:飛線飛完之后萌踱,想停留個幾毫秒再消失
- 尾巴長度難控制葵礼,太長的話有明顯的間隔。
飛線性能測試
一并鸵、同等情況下章咧,svg 飛線與 canvas飛線的性能比較。
模擬數(shù)據(jù)來源于B2B 外貿(mào)單日詢盤量能真,總數(shù)共 596 條赁严, 單次同時繪制 50 條 飛線情況下:
動畫幀數(shù) fps | cpu 占用率 | JS Heap 內(nèi)存情況 | 說明 | |
---|---|---|---|---|
svg | 12 fps ~ 43 fps | 高于 100% | 11 mb 左右 | 視覺上仔細看略有卡頓 |
canvas | 42 fps ~ 60 fps | 20% ~ 30% 浮動 | 9.3 mb 左右 | 動畫流暢 |
具體如下:
1. 動畫幀數(shù)
Canvas
動畫幀數(shù)保持在 42-60 左右,動畫流暢粉铐;
SVG
動畫幀數(shù)保持在 12-43 左右疼约,視覺上仔細看略有卡頓;
2. CPU 占用率
Canvas
CPU 占用率在 20%-30% 浮動
SVG
CPU 占用率高于 100%
3. JS Heap 快照
皆無內(nèi)存泄漏問題蝙泼。 SVG 飛線的 JS heap 總大小略高于 Canvas 飛線程剥。
Canvas
SVG
二、Canvas飛線峰值測試
測試了 Canvas 飛線汤踏,在同時繪 50 條织鲸、100 條、200 條溪胶、300 條搂擦、400 條 時的動畫流暢度。
- 在50-100 時候動畫流暢
- 200 時哗脖, fps 低瀑踢,視覺上勉強可接受
- 300 時,有卡頓才避,有明顯漏幀行為橱夭;
- 400 時,卡頓非常嚴重桑逝,幾乎無法完整看到飛線動畫