沒想到這麼快就要使用自定義分面Facet功能了,猝不及防。
概述
起因是開發進行到一半的時候,發現 我們實現的效果 和 產品小夥伴的想法很不一致。而引擎現有能力並不支援產品想要的效果。嗯,只能自力更生了。
什麼是分面
分面(Facet)是指利用 G2 提供的 View 遞迴巢狀能力,將一份資料按照某個維度分隔成若干子集,然後建立一個圖表的矩陣,將每一個資料子集繪製到圖表矩陣的窗格中。
上面是官方文件裡的解釋,簡單講就是 根據一定的規則對畫布進行分割,形成多個子 View,然後在子 View 中繪製對應的資料和圖形。
G2本身也內建了幾種分面型別,如常見的list,rect,tree等,使用方式也很簡單:
chart.facet(type: string, cfg: FacetCfg) => View
具體參考官方文件使用
如何自定義分面
自定義分面主要包含三個核心要素:
- 分面子 View 的定位邏輯
- 自定義分面機制
- 實現自定義分面類
子 View 定位
定位實質就是 分割出畫布上的一部分給子view容器。
分面的核心邏輯是將當前 View 大小,根據資料拆分成多個子 view。
G2 中 View 可以擁有多個子 view,形成無限的巢狀邏輯。
自定義分面機制
G2 提供自定義分面能力,實現並註冊一個自定義分面的機制,大概如下程式碼:
import { registerFacet, Facet } from '@antv/g2';
// 實現一個自定義分面,繼承 G2 分面基類
class MyFacet extends Facet {
// TODO 實現自己的分面邏輯
}
// 註冊自定義分面到 G2 中
registerFacet('my-facet', Facet);
// 消費自己的自定義分面
const chart = new Chart({
/*...*/
});
chart.facet('my-facet', {
/* facetConfig */
});
實現自定義分面
核心就是開發自定義分面類 MyFacet,有5 個抽象方法必須實現。
import { Datum, Facet, FacetCfg, FacetData, View } from '@antv/g2';
interface MyFacetCfg extends FacetCfg {
// TODO
}
interface MyFacetData extends FacetData {
// TODO
}
class MyFacet extends Facet<MyFacetCfg, MyFacetData> {
protected afterEachView(view: View, facet: MyFacetCfg) {}
protected beforeEachView(view: View, facet: MyFacetCfg) {}
protected generateFacets(data: Datum[]): MyFacetCfg[] {
return [];
}
protected getXAxisOption(x: string, axes: any, option: object, facet: MyFacetCfg): object {
return undefined;
}
protected getYAxisOption(y: string, axes: any, option: object, facet: MyFacetCfg): object {
return undefined;
}
}
內建分面原始碼分析
ok,瞭解了分面相關的基本概念,我們來分析一下內建分面的邏輯。
內建分面實現和自定義分面實現邏輯並無不同,也是必須實現5個抽象方法,我們先看一下 list分面的實現。
這就是list分面類全部的程式碼了,很簡潔。
我們核心分析一下 生成分面定位的 generateFacets 方法實現:
根據維度分割欄位把資料劃分成 幾行幾列的 子view,就是這麼個邏輯。
畫布區域劃分就是根據行數和列數 評分割槽域,分配給每個子view。
剩餘的繪製邏輯就和 普通圖形沒有區別了
其他幾個分面 和這個都大同小異,本質就是如何 劃分割槽域的問題。