@逍为(hustcc)

背景

分面(Facet)的核心逻辑是按照数据字段,和分片逻辑将当前 view 切分成几个部分,每个部分会生成一个子 view,配合 view 递归嵌套的能力,可以画布区域进行灵活的分片和布局。

G2 将内置以下分面形式:

  • circle
  • list
  • matrix
  • mirror
  • rect
  • tree

API

API 是很简单的,在 view 上新增 facet API,可以指定使用某一个分面方式去做分面,并传入分面的配置。

  1. view.facet(type: string, cfg: FacetCfg) {};

实现

view

  • 增加 facet API
  • view 生命周期执行分面逻辑
  • render
  • changeData

facet 基类

facet 基类确定了 facet 的生命周期,以及后续分面的扩展。

生命周期

  • initial

  • [x] 初始化过程,初始化 G 容器

  • [x] 按照分面字段,将数据分片,形成分面数据 FacetData,这个数据最终用来生成分面子 View

  • render

  • [x] 将 FacetData 渲染成子 View,执行 eachView 的逻辑

  • 然后根据数据生成 title、axis、legend 等一些辅助 UI
  • title
  • axis
  • [ ] legend

  • destroy

  • [x] 移除 G 容器

  • 关闭事件
  • 清空数据,view 等

facet 构造参数

  1. class Facet {
  2. // 构造函数
  3. constructor(view: View, cfg: FacetCfg) {
  4. // ...
  5. }
  6. }
  7. /**
  8. * 默认的基础配置
  9. */
  10. export interface FacetCfg {
  11. // 布局类型
  12. readonly type?: string;
  13. // view 创建回调
  14. readonly eachView: (innerView: View, facet?: FacetData) => any;
  15. // facet 间距
  16. readonly padding?: number;
  17. // 子 view 的 padding
  18. readonly viewPadding?: number;
  19. }
  1. 构造函数由两个参数,第一个为父级 view,第二个为 facet 实例的配置
  2. 基类 facet 配置定义结构为 FacetCfg,子类的配置结构继承于它

布局

分面布局分成为几部分:

  • facet 区域布局
    • facet 区域其实就是 view 的绘图区大小
  • 子 view 的布局
    • 按照分面字段,均分区域 region
    • padding 字段来决定 view 之间的 padding
    • margin 字段决定 view 的 margin
  • title axis 等组件布局
    • 将 title axis 放置到 margin 区域中

rect

内置的矩形分面。

构造参数

  1. /**
  2. * rect 分面的配置
  3. */
  4. export interface RectCfg extends FacetCfg {
  5. // column, row
  6. readonly fields: [string, string];
  7. }

在基类配置的基础上,增加 fields 分面字段信息。

  • 继承 Facet 基类,实现数据分面
  • 实现 title
  • 实现 axis
  • 实现 legend

渲染和布局过程

在 render 过程中的执行逻辑。分面的 render 是 view 嵌套逻辑中的一个子环节,可以到 布局逻辑 文档查看整体的流程。

image.png

在 initial 阶段,已经通过分面字段,计算除了分面数据,分面数据包含:

  1. 分面 region
  2. 分面数据
  3. 分面索引

在 render 阶段做的事情包括:

  • 渲染分面组件
    • 根据分面索引,获取上右下左四个方向贴边的分面数据
    • 根据贴边分面数据,生成组件
      • 左、下方生成 axis 组件
      • 上、右方生成 title 组件
    • 非贴边的分面,生成 x axis 组件
    • 所有组件都放置到 FORE layer(view 三层中的顶层)
  • 布局分面组件
    • 根据四个方向的组件,计算上右下左四个方向 gap
    • 更新 view 的 coordinateBBox,去除 gap
    • 遍历组件,将组件 move 到 coordinateBBox 的四个方向上
  • 渲染分面 views
    • 根据分面数据,view.createView 生成子 view
    • 设置子 view 数据
    • 执行 eachView 逻辑,设置子 view 中的 Geometry

然后在 view 的 render 流程中会递归渲染子 view(也就是分面生成的 view)。