D3 力導向圖和 WebGL 的整合使用

發表於2017-07-14

D3 是目前最流行的資料視覺化庫,WebGL 是目前 Web 端最快的繪製技術。由於效能問題的侷限,將兩者結合的嘗試越來越多(如),本文將嘗試用 D3 的力導向圖Three.jsPixiJS 結合。全文閱讀完大概 5 分鐘,因為你重點應該看程式碼

做資料視覺化時,必然會考慮效能的問題。早前資料視覺化都是用 Qt 等 GUI,後來逐漸遷移到了迅猛發展的瀏覽器上展示,Web 的效能問題成了大多數視覺化的侷限,尤其是在三維視覺化,或資料量特別大的時候。現在主流的 Web 視覺化技術為三種:SVG、Canvas 和 WebGL,難易程度和效能如下圖:

Web visualization techWeb visualization tech

SVG 的優點很多,編輯簡單,互動便捷,靈活性極高,業內成熟的視覺化工具(如 d3)都是用的 SVG。但是每個 SVG 都是一個 DOM 元素,隨著它的數量上來之後,互動開始慢的難以忍受。這是因為每當修改一個 DOM 物件,只要這個物件在文件裡,接著在瀏覽器裡就會發生兩個動作,一個叫 Reflow(重排,就是重新排版),另一個叫 Repaint(重繪,就是重新渲染頁面)。這兩個動作不一定都會發生,但如果被修改的 DOM 當前可見的話,那麼就會先重排,後重繪。繪製效能上 canvas 和 SVG(DOM 元素)應該差不多,但前者可以省掉重排過程,因此效能更高。然而,WebGL 的效能更勝一籌,因為 WebGL 使用 GPU 加速渲染,GPU 在大規模計算方面有絕對優勢(影像處理、深度學習都在用,顯示卡已經賣瘋了)。例子:用 WebGL 繪製 200000 個點的動畫(http://rickyreusser.com/smoothly-animating-points-with-regl/)

WebGL 雖然威力無窮,但是寫起來比較痛苦,畫個三角形大致要 100 行程式碼。所以很多人對 WebGL 進行了封裝。上面圖中提到的兩個 Three.jsPixiJS 是目前最流行的兩款 WebGL 庫,當然還有新興的 regl 在今年的 OpenVis 上大放異彩。本文嘗試用前兩者和 d3-force 結合(專案程式碼在此),後面如果有時間的話,我會把使用 regl 和原生 WebGL 的例子也補充進去(我知道這是個 flag)。

正文

首先我們要知道什麼是力導向圖和如何使用 d3-force。d3 4.0 之後,作者將其模組化,force 這個模組是基於 velocity Verlet 實現了物理粒子之間的作用力的模擬,常用於網路或關係結構資料。即你把網路中的節點想象成一個個粒子,它們之間互相有作用力,所以不停的拉扯,直到趨於一個穩定狀態,具體可以看我 demo 中視覺化出來的樣子。

Demo 效果圖Demo 效果圖

仔細看 demo 中的原始碼可以發現,用 three.js 和用 pixi.js 實現起來非常類似,其中有關力導向圖的關鍵程式碼是下面幾句:

d3-force 提供了五種作用力,分別是 Centering、Collision、Links、Many-Body、Positioning。此時我們已經建立好帶有各種力的模擬器了,接下來需要啟動它:

至此一個力導向圖的模擬就開始了,那麼怎麼把這些節點和邊顯示出來呢?讓我們繼續看原始碼,以 three.js 為例:

在 Three.js 中展示場景需要具備三要素:場景、照相機、渲染器。照相機就相當於我們的眼睛,它對著渲染好的場景就相當於把場景成像到了相機中,這裡的照相機我們用的是平行投影相機,渲染器我們使用的是 WebGL 渲染器。設定好渲染器的大小,把它新增到頁面的元素上,相當於新增了一個 <canvas> 元素。接下來,我們生成每個節點和邊的樣子:

套路都一樣,都是先建一個幾何體,然後設定材質的樣式,新增到場景中就好了。接下來只要在剛才提到的 ticked 這個回撥函式中把節點和邊的座標更新一下就好了:

是不是比想象的簡單多了?如果以上有什麼地方看不懂,說明你可能對 Three.js 不是很瞭解,不過沒關係,它的文件寫的很好,入門很快。希望這篇文章能給你帶來一些幫助,做了點微小的貢獻,很慚愧 :)

相關文章