没想到这么快就要使用自定义分面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。
剩余的绘制逻辑就和 普通图形没有区别了

其他几个分面 和这个都大同小异,本质就是如何 划分区域的问题。


donglegend
910 声望82 粉丝

长安的风何时才能吹到边梁?


引用和评论

0 条评论