G2(圖表引擎) 4.0 和 G6(圖分析引擎) 3.4版本已經替換了 G(2D 渲染引擎)4.0,這個版本最大的改進是支持了局部渲染,在一些場景下例如節點的狀態改變、圖形的個體動畫等方面性能提高巨大。G 4.0 從開始重構到如今穩定經歷了半年的不斷完善,遇到了各類各樣的問題,本文將對 Canvas 的局部渲染作一個總結,給後來者一些幫助。 javascript
因爲 Canvas 的繪製方式是畫筆式的,在 Canvas 上繪圖時每調用一次 API 就會在畫布上進行繪製一次,一旦繪製圖形就成爲畫布的一部分。繪製圖形時並無對象保存下來,一旦圖形須要更新,須要清除整個畫布從新繪製。
java
僅僅縮小刷新時的範圍從而提高性能並不夠,以右圖爲例,若是咱們要刷新圖形 2 將圖形變成紅色。這時候若是僅僅清理掉圖形 2 ,從新繪製則:
git
咱們來思考 Canvas 局部渲染方案時,須要看 Canvas 的 API 給咱們提供了什麼樣的接口,這裏主要用到兩個方法:github
經過這兩個 API 咱們能夠獲得 Canvas 局部刷新的方案:canvas
真實的在 G 4.0 中實現局部渲染時遇到的問題比上面的案例複雜的多:瀏覽器
這些問題在 1-2 周內都解決了,可是在接入 G2 和 G6的過程當中遇到了一些徹底沒想過的問題持續了半年的時間,主要體如今兩個方面:安全
首先咱們來看畫布上的兩條線,一樣都是 1 像素顏色 #333 的線,有什麼差異?
markdown
因爲屏幕的分辨率只能在整數的點上繪製顏色,線段 1 一半繪製在 (10, 99)-(200, 99) 一半繪製在 (10, 101 )-(200 101)上,因此瀏覽器會自動的把落到半個像素上的點擴展成一個點,顏色變淡,就變成了下圖的示例(示例中畫布進行放大,每一個單元格表明一像素)。
app
咱們在繪製圖形時不少圖形屬性是自動計算出來的,例如:oop
這時候圖形繪製的區域同數學計算出來的並不一致,這就會致使局部刷新時清空的區域不足,會留下一些殘影。
因爲 Canvas 在實現折線時,在線段的交接處作了處理,會附加額外的像素,使得折線更美觀,咱們來看下單獨繪製兩條線段,和一條折線的差異:
在 Canvas 上繪製圖形時能夠指定陰影,有四個參數關係到陰影的設置:
shadowColor | 設置或返回用於陰影的顏色 |
---|---|
shadowBlur | 設置或返回用於陰影的模糊級別 |
shadowOffsetX | 設置或返回陰影距形狀的水平距離 |
shadowOffsetY | 設置或返回陰影距形狀的垂直距離 |
下面兩個圓,若是不考慮陰影進行局部刷新時會出現下面的狀況:
// 若是存在 shadow 則計算 shadow if (attrs.shadowColor) { const { shadowBlur = 0, shadowOffsetX = 0, shadowOffsetY = 0 } = attrs; const shadowLeft = minX - shadowBlur + shadowOffsetX; const shadowRight = maxX + shadowBlur + shadowOffsetX; const shadowTop = minY - shadowBlur + shadowOffsetY; const shadowBottom = maxY + shadowBlur + shadowOffsetY; minX = Math.min(minX, shadowLeft); maxX = Math.max(maxX, shadowRight); minY = Math.min(minY, shadowTop); maxY = Math.max(maxY, shadowBottom); } 複製代碼
在線上增長箭頭是個常見需求,可是因爲箭頭是附加在線上的,計算包圍盒未計算在其中,這就致使刷新時箭頭未被清除,同時箭頭又有多種狀況,還要考慮箭頭的自定義:
你能看清楚下面的文本發生了什麼嗎?若是仔細觀察會發現文本左側被裁剪掉了一像素,這種狀況在多個場景下都存在
G2 4.0 和 G6 3.4 發佈後,有用戶反饋在頁面上進行操做時,出現一些線的劃痕
// 附加 0.5 像素,會解決1px 變成 2px 的問題,不管 pixelRatio 的值是多少 // 真實測試的環境下,發如今 1-2 之間時會出現 >2 和 <1 的狀況下未出現,可是爲了安全,統一附加 0.5 const appendPixel = 0.5; if (region) { region.minX = Math.floor(region.minX - appendPixel); region.minY = Math.floor(region.minY - appendPixel); region.maxX = Math.ceil(region.maxX + appendPixel); region.maxY = Math.ceil(region.maxY + appendPixel); } 複製代碼
若是同時有多個圖形進行刷新,爲了減小包圍盒的計算,咱們會把全部刷新的圖形的包圍盒進行合併,可是會出現一些特殊狀況,致使局部渲染的性能降低,例如:
經歷了半年的改造,G 4.0 的局部渲染方案已經經歷了 G2 和 G6 的考驗,在局部刷新的場景下在交互和性能等方面提高了 7-10 倍,可是依然存在一些特殊場景上的性能問題,還在持續優化中。渲染的一分提高,上層都會有十分的收穫。
AntV 官網:antv.vision/
2D 繪圖引擎 G:github.com/antvis/g