HTML5 中的 Canvas 對文本的渲染(fillText,strokeText)性能都不太好,好比設置字體(font)、文本旋轉(rotation),若是繪製較多的文本時,一些交互操做會手動很大的影響,操做起來沒那麼順暢,體驗將會極其差,這不是咱們想要的結果,再進一步和圖片的繪製進行比較比較,你會發現,繪製圖片和繪製文本在性能上不是一個等級的,在性能上繪製圖片會好太多。javascript
咱們今天就來談談 HT for Web 性能相關的問題。在 HT 中,有不少地方能夠設置文本,每一個節點上面均可以設置兩個 label 和兩個 note 文本,若是全開啓的話,繪製一個節點就要附帶繪製 4 個文本,假如說繪製 文本的性能消耗是繪製圖片性能消耗的 3 倍的話,附帶繪製 4 個文本,就想當與多出 12 倍的性能消耗,這節點以多的話,可想而知,不論是哪一個引擎都不可能 hold 得住這樣的性能消耗。html
既然繪製文本的性能消耗沒法避免,那麼咱們要如何提升系統的總體性能呢?換個思路,繪製文本會有高性能消耗,致使操做上面的延遲和卡頓,那麼我是否是能夠在操做時不繪製文本呢,將文本繪製所消耗的性能節省下來,用在其餘的性能消耗上,這樣是否是就能夠解決操做延遲和卡頓的問題呢?java
咱們不妨來試試,在 GraphView 中添加若干個 node、edge、group 等節點,而且每一個節點上都顯示文本(包括線條,上圖所示),看看拓撲的縮放效果怎麼樣。沒次縮放都要等上兩三秒,性能實在是差得不行,這樣的應用確定是不合格的。node
咱們來看看具體的 Demo,連接:http://www.hightopo.com/demo/labelVisible/visible.html。接下來解析下具體代碼的實現。瀏覽器
var init = function() { window.matchMedia('screen and (min-resolution: 2dppx)'). addListener(function() { ht.Default.setDevicePixelRatio(); }); var g2d = new ht.graph.GraphView(), dm = g2d.dm(); g2d.addToDOM(); g2d.getLabel = function(data) { if (data.s('label')) return data.s('label'); if (data instanceof ht.Edge) return 'from:' + data.getSourceAgent().toString() + ' to:' + data.getTargetAgent().toString(); return data.toString(); }; createNodes(dm); var autoLayout = new ht.layout.AutoLayout(g2d); autoLayout.setAnimate(true); autoLayout.layout('symmetric', function() { g2d.fitContent(true); }); createFormPane(g2d, autoLayout); };
上面的代碼是頁面初始化代碼,首先先監聽 media 的值變化,防止在不一樣的 devicePixelRatio 屏幕中切換 而致使頁面不清晰,ht.Default.setDevicePixelRatio() 方法會更新 HT 系統中存放 devicePixelRatio 的變量,而後刷新頁面上全部的 HT 組件,這樣就能夠保證頁面必定不會不清晰。網絡
接着是常見網絡拓撲圖 GraphView 組件,並將其添加到 DOM 中,重載 GraphView 的 getLabel 方法設置圖元的文本,讓每一個節點都有文本。佈局
接下來調用 createNodes 方法建立全部的節點,建立完代碼後,建立一個 AutoLayout 來自動佈局全部節點,自動佈局爲開發人員節省手動佈局的時間,在效率上大大提高,在佈局完後,讓 GraphView 中的節點自適應屏幕,讓全部節點都顯示在當前頁面中。性能
最後建立一個 FormPane 放在右上角,用於存放幾個控制按鈕及幾個 ComboBox 選擇項,可讓 GraphView 運行在不一樣的佈局模式下,同時這些功能也能夠用來檢測頁面性能,在佈局的過程當中是否流暢,具體的代碼能夠經過瀏覽器的 Sources 查看。字體
文本始終顯示的話,在性能上仍是不行的,就如上面所說的,是不合格的。那麼我麼該如何優化,讓性能有質的提高呢?優化
在文章的開頭有提到,咱們能夠採用在操做交互的過程當中不繪製文本,來提高性能,讓頁面的呈現更加流暢。那麼該怎麼實現才能讓操做交互過程當中不繪製文本呢?具體 Demo 連接:http://www.hightopo.com/demo/labelVisible/invisible.html。看碼:
var state = {}; g2d.isLabelVisible = function(data) { return !state.zooming && !state.panning && !state.autoLayout; }; g2d.onAutoLayoutEnded = function() { state.autoLayout = false; }; g2d.onZoomEnded = function() { state.zooming = false; }; var timer = null; g2d.mp(function(e) { if (e.property === 'zoom') { state.zooming = true; if (timer) clearTimeout(timer); timer = setTimeout(function() { timer = null; state.zooming = false; g2d.redraw(); }, 100); } }); g2d.mi(function(e) { if (e.kind === 'beginPan') state.panning = true; if (e.kind === 'endPan') { state.panning = false; g2d.redraw(); } });
首先 GraphView 提供了 isLabelVisible 的方法,讓用戶重載自定義文本的顯示與否,state 變量是用來標記當前的操做狀態,zooming 表明當前的 GraphView正在縮放,panning 表明當前的 GraphView 正在移動整個場景,autoLayout 表明正在作自動佈局操做。
GraphView 的 mp(addPropertyChangeListener)方法是監聽 GraphView的屬性變化,當監聽到 zoom 屬性變化的時候,將 zooming 狀態設置爲 true,若是在 zoom 的過程當中沒有啓動動畫的話,就不會觸發 onZoomEnded 回調,因此須要本身添加計時器,過段時間將 zooming 狀態改掉,而且從新繪製下 GraphView。
GraphView 的 mi(addInteractorListener)方法是監聽用戶對 GraphView 的操做動做,在監聽到 beginPan 時將 panning 狀態設置爲 true ,在監聽到 endPan 是將 panning 狀態設置爲 false,並重繪 GraphView。
在 FormPane 中的一些操做會對 GraphView 中的節點進行自動佈局,所以在 FormPane 中會設置 autoLayout 狀態,因爲代碼比較多,我在這邊就貼代碼了。咱們來看看,加上上面的代碼後,對 GraphView 操做後的效果圖:
上圖是在縮放 GraphView 時的效果,能夠發現全部的文本都不見了,用戶操做起來也不會延遲和卡頓了現象,這樣用戶操做交互的性能問題也就解決了。