但願讀完系列文章後,可以對 G6 的功能分佈、主要流程有大概的認知。 關注點在 G6 的介紹和主要流程,不涉及到具體 api 的使用。node
下面各個維度解釋下G6git
G6 是一個圖可視化引擎。它提供了圖的繪製、佈局、分析、交互、動畫等圖可視化的基礎能力。旨在讓關係變得透明,簡單。讓用戶得到關係數據的 Insight。github
G6 是 antv 體系的一個圖可視化品牌,主要關注關係圖的繪製,antv 還有其餘應用,好比關注圖表的 G二、F2,關注地理數據渲染的 L7 等算法
G6 是一個開源的 JavaScript 圖形庫,能夠支持 PC、移動端、小程序多個平臺。npm
更多G6使用的示例參見圖可視化引擎 G6json
G6 依賴渲染引擎 G 提供渲染能力,G 是一款Antv體系開源的支持 canvas、svg 渲染,跨 PC、mobile 平臺的強大渲染引擎。 Graphin是基於 G6 的 React 庫,經過接入 React 生態,使用起來更加簡單。bootstrap
上圖是官方 v4 的框架圖,比較能看出 G6 基礎的功能分佈。canvas
G6 是一個多項目共存的庫,使用monorepo的思想來管理項目。monorepo不作過多介紹。思路就是把相關聯的項目都放在一個倉庫裏管理,包括開發、構建、發佈等。我本身經驗來看,這種模式確實在同時多個項目開發時有優點,免去管理、link 多個項目的麻煩。不過上手階段我常常會有疑惑,不能確認問題出在哪一個項目,要總體build,苦笑,應該是我太菜。G6 使用 lerna 來管理全部的子項目,目錄結構和簡介以下:小程序
G6
|-packages
|--core // G6核心庫,實現了大部分功能,主流程、動畫、交互、狀態管理
|--pc // 擴展core,提供更多的交互,pc的事件等
|--mobile // 擴展core,提供mobile、小程序平臺的支持,移動端事件支持等
|--element // 提供預製的自定義圖元素(節點、邊、combo)
|--plugin // 插件,好比[魚眼效果](https://g6.antv.vision/zh/examples/tool/fisheye#fisheye)
|--...
複製代碼
構建項目:npm install
, npm run bootstrap
,更多指令能夠看package.json文件api
提供渲染能力,向上提供
本小節簡單描述了G的流程和輸入的數據結構,用來輔助理解G6。一些更細的點,好比局部渲染、形狀拾取、碰撞檢測、座標系統等,就暫時無論。從流程圖能夠看出,G 跑起來須要 Group 樹結構,因此接下來 G6 須要作的工做就是構建這樣的結構,交給 G 來渲染。
G6的核心概念 在官方文檔有講,此處再也不贅述,能夠先創建下概念和基礎用法。一個簡單的示例以下:
const data = {
nodes: [
{
id: "node1",
label: "Circle1",
x: 150,
y: 150
},
{
id: "node2",
label: "Circle2",
x: 400,
y: 150
}
],
edges: [
{
source: "node1",
target: "node2"
}
]
};
const graph = new G6.Graph({
container: "container",
width: 500,
height: 500,
});
graph.data(data);
graph.render();
複製代碼
例子簡單,但也能基本說明問題。能夠看出:
在此基礎上有交互(behavior)、事件、狀態管理、動畫、佈局幾大功能。下面就按照G6的執行順序,分析下G6的基礎流程和相關設計。
建立graph實例後,同時會初始化如下單例,管理不一樣的功能:
graph.cfg.canvas
G 對應的 Canvas 類實例,調控整個渲染流程,經過該單例與 G 對接起來
graph.cfg.itemController
管理 Item 實例,Item 是 G6 包裝的節點類,輸入的邊和節點數據會組織成 item 實例數組。這個模塊打通從數據到最終渲染的整個流程,下面的章節會着重分析這個模塊相關的部分。
graph.cfg.layoutController
控制佈局相關邏輯,佈局算法比較複雜,G6 拆出了一個 npm 包(@antv/layout)專門放佈局相關算法。
graph.cfg.viewController
控制顯示相關邏輯。核心邏輯是計算視口居中,提供座標轉換等功能。
graph.cfg.eventController
控制事件相關邏輯,核心邏輯是拾取 G 傳來的事件,出發用戶定義事件,最終反饋到 item 上。
graph.cfg.modeController
控制交互,管理 behavior。
ShapeFactory
圖元素的工廠函數,管理(crud、函數調用)定義的節點、邊、combo。
下圖展現了一個節點數據(參照前置文檔示例中節點的數據結構)從輸入,到最終渲染,數據的流動狀態,以及經歷的流程。
data輸入後,須要依靠itemController建立出Item實例來管理。Item做爲G6與渲染層的橋接,能夠仔細分析下。Item類設計以下:
前面裏串通了繪製流程,已經能畫出了圖。除此以外,做爲圖可視化引擎的G6,還支持了哪些功能,又怎麼實現的呢?
本文總體的思路是,分析這些功能互相的關係、內部的一些流程、設計 、實現點,這樣基本能從大到小,解釋清楚整個系統是怎麼運行的。
各個功能的分層關係以下:
整個G6就這些核心功能,從圖中能夠看出各個功能之間的層次關係,能瞭解到功能的所處位置。有了大方向上的認知後,能減小些迷茫。
這些功能除了動畫,均有對應的Controller,由Graph封裝並放在Graph.cfg上,並對外提供入口。G6有個設計的特色,就是全部狀態相關的都會放在cfg裏,表明的應該是這個類型的model。好比Graph類中的cfg,Item類中的Cfg等。不過把Controller這種邏輯密集的也掛在上面總感受有些奇怪。
事件、動畫、Item節點管理會直接依賴G。而交互、狀態管理、佈局則更多基於G6本身的封裝。
官方文檔對事件有清晰的分類。總共分爲三類事件:畫布層次的事件(canvas:mousedown ...),節點層次的事件(node:click ...),按時機的事件(afterlayout ...)。事件包括事件名,以及事件的回調。事件名在不一樣平臺會有差別,好比pc平臺的mouse事件,移動平臺的touch事件。詳細介紹見文檔中核心概念章節的事件小節。
事件咱們都比較熟悉,觀察者、發佈訂閱之類。G6事件也不例外,有個全局的事件中心,graph.cfg.eventController,提供事件的訂閱和發佈。而與咱們認識的Dom的事件不一樣的是,G6面對的可能只有一個Dom元素,Canvas,因此不能依賴平臺自己解析事件觸發的節點、事件對象,須要本身實現及封裝。
經過上篇文章,咱們知道,G將繪圖的節點組織成group樹結構,shape是樹的子節點。要肯定到底點擊到哪一個shape/group,思路其實顯而易見就是遍歷這棵樹,找到節點便可。下面是quickHit模式下的節點拾取流程,源碼參見G項目中g-base包裏event.ts文件。(quickHit模式經看源碼,主要是忽略了group的點擊檢測,只檢測葉子節點,經過這樣處理提高性能。)
其中點擊檢測每一個shape類型有實現本身的檢測方法,好比圓使用點到圓心的距離等。每次觸發事件都要遍歷整顆樹,作點擊檢測,是個性能點,所以G自己也作了一些緩存處理。
事件冒泡是G作的,比較簡單,核心思路是檢測命中shape後,依次向上觸發parent的事件,直到事件對象裏的 propagationStopped
屬性爲true或者到達根元素。
**交互模式解決的問題?**是用來批量操做用戶交互行爲,好比切換編輯和查看模式這種場景。詳細介紹見文檔中核心概念章節的Behavior相關小節。 類設計:
Behavior是個工廠類,使用對像存儲各個Behavior類型。每一種Behavior子類型,定義了所需的事件行爲集合,提供事件的綁定與解綁。 ModeController,根據輸入的mode配置(Behavior類型的索引組成的數組),或動態切換不一樣的Behavior子類實例。
ModeControler綁定Behavior流程:
核心思路就是ModeController調用Behavior工廠建立子類型實例,實例完成綁定過程。觸發時機是初始化Graph或系統運行期間動態調用Graph.setMode。
狀態管理解決的問題? 實現交互時或者業務邏輯中節點狀態變化後,觸發節點樣式的更新或其餘自定義行爲。這裏的狀態能夠是交互中的hover、active,也能夠是自定義的running任何一種狀態。對狀態的響應若是隻是樣式變化,能夠直接在建立Graph實例時輸入的節點配置中設置。若是其餘更加複雜的行爲,好比加個動畫,就須要自定義節點,複寫默認的setState方法。詳細介紹見文檔中核心概念章節的交互mode、狀態state小節。
類設計:
Graph初始化後會實例化StateController和ItemController,能夠在Graph實例的cfg中訪問到。
StateController目前看來只是維護了各類狀態下的Item數組,以及更新狀態後的事件觸發,不影響整個state的流程。
設置狀態流程:
動畫G6沒有作什麼處理,直接使用的G的動畫能力。根據使用場景,分爲全局動畫和自定義節點動畫兩部分。詳細介紹見文檔中核心概念章節的基礎動畫小節。 **全局動畫:**拿到節點樹根部元素,調用animate接口;
自定義節點動畫:在自定義圖元素(能夠看上篇瞭解圖元素,G6用來對接G,封裝了具體的shape)時,拿到shape或group節點,調用animate接口便可。
類設計:
動畫流程:
核心思路就是Element獲取Canvas中的TimeLine實例,傳入動畫數據,交給d3-timer去逐幀執行,經過插值實現連續的動畫效果。
插值計算使用了d3-ease、d3-interpolate輔助計算。
更新到畫布是Element的能力。
觸發流程時機是全局動畫或自定義動畫調用animate時。
佈局是採用算法,使節點和邊可以以某種方式分佈。分爲通常圖佈局和樹圖佈局,目前我只看到了通常圖佈局,就只分析通常圖佈局。詳細介紹見文檔中核心概念章節的圖佈局小節。
相關的類:
佈局使用在初始化Graph時建立的LayoutController控制。具體的佈局算法來自npm包** @antv/layout** 。
通常圖佈局的具體流程
能夠看出,佈局和Graph經過數據解耦。Graph面向數據,數據正確就能正常渲染。佈局算法也只用關注對數據的生產,不用關注Graph或者其餘系統。
佈局算法對節點座標更新以達到佈局的目的,其餘數據項也能夠更新,不過就顯得職責不清晰,因此不建議佈局算法對其餘數據項的更新。
PC和Mobile平臺佈局的流程不一致。PC會額外支持worker佈局,就是圖中第三列的佈局流程,把佈局拆成了三個步驟異步通知進行。
觸發流程的時機是在初始化或者切換數據、佈局的時候,具體是在調用Graph的render/changeData/updateLayout時。
這裏是一個自定義佈局的例子,看完這個例子應該會對佈局算法的職責有更清晰的認知。
經過對各個功能的層次分佈,以及各自實現流程的分析,應該對G6實現思路有了大體的認知。有興趣的話,能夠對着流程看看源碼,看看具體某個步驟的實現邏輯。通過這段時間G6的梳理,對G6也有了更多的瞭解,最後感謝閱讀。
微信搜索公衆號Eval Studio,關注更多動態。