視覺化引擎antv系列之分面Facet(二)

donglegend發表於2021-09-26

沒想到這麼快就要使用自定義分面Facet功能了,猝不及防。

概述

起因是開發進行到一半的時候,發現 我們實現的效果 和 產品小夥伴的想法很不一致。而引擎現有能力並不支援產品想要的效果。嗯,只能自力更生了。

什麼是分面

分面(Facet)是指利用 G2 提供的 View 遞迴巢狀能力,將一份資料按照某個維度分隔成若干子集,然後建立一個圖表的矩陣,將每一個資料子集繪製到圖表矩陣的窗格中。

上面是官方文件裡的解釋,簡單講就是 根據一定的規則對畫布進行分割,形成多個子 View,然後在子 View 中繪製對應的資料和圖形。

G2本身也內建了幾種分面型別,如常見的list,rect,tree等,使用方式也很簡單:

chart.facet(type: string, cfg: FacetCfg) => View

具體參考官方文件使用

如何自定義分面

自定義分面主要包含三個核心要素:

  1. 分面子 View 的定位邏輯
  2. 自定義分面機制
  3. 實現自定義分面類

子 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分面的實現。
image.png
這就是list分面類全部的程式碼了,很簡潔。
我們核心分析一下 生成分面定位的 generateFacets 方法實現:
image.png
根據維度分割欄位把資料劃分成 幾行幾列的 子view,就是這麼個邏輯。
image.png
畫布區域劃分就是根據行數和列數 評分割槽域,分配給每個子view。
剩餘的繪製邏輯就和 普通圖形沒有區別了

其他幾個分面 和這個都大同小異,本質就是如何 劃分割槽域的問題。

相關文章