简介

View 是拥有独立数据源,并且能够绘制多个图形的容器。View 加入 G2 是从 G2 2.x 开始的,出发点是为了支持分面、地图等功能,之后 View 的功能一直没有变化。自 3.x 移除了统计函数后,一些之前通过统计函数的图表同未经统计的图表一起显示时也需要 View,G2 对 View 的依赖进一步增强。
G2 4.0 版本开始设计时,考虑到在 BI 场景下的自助分析、多维分析的场景,需要对 View 的功能进一步扩展,希望能够让用户不使用 Chart 而独立使用 View,而这需要对 View 进行一些调整,主要体现在下面几个方面:

  • View 的嵌套
  • 组件和 Controller
  • 分面
  • 多 View 交互

View 的嵌套

首先明确一下为什么要要进行 View 的嵌套,View 的嵌套有什么好处,有什么坏处?

现状

我们首先来看一下目前的情况,再来分析支持View 嵌套的优劣,给出 4.x 的结论:

  • 当前的版本中只有 Chart(本质也是 View) 和 View 两层,View 不能再有子 View。
  • View 可以层叠也可以平铺开:
    • 地图的场景是层叠的典型场景;
    • 显示原始数据和统计数据的场景是层叠;
    • 分面是铺开的一个场景;
    • 而地图的分面场景是既有层叠又有铺开。
  • View 无限嵌套的功能理论上来说,通过一层 view 也能支持,不过在既有层叠又有平铺时存在一些限制。

    支持 View 的好处

  • 语法上是完备的,比较易懂的嵌套递归逻辑

  • 比较好组织既层叠又嵌套的场景

    支持 View 的缺点

  • 增加 G2 的复杂度,配置项要逐层向下传,事件要一级级向上冒泡

  • 组件同 View 的关系更加复杂,是否每一级都允许有 legend、tooltip,不同级上显示的相同组件如何关联
  • 如果支持统计函数(原始数据和统计数据仅需要一个数据源),View 嵌套的场景少之又少,为了这么少的场景是否划算

组件和 Controller

组件和 View 的关系,需要理顺下面的几个问题:

  • 哪些组件仅仅属于 Chart
  • 组件是仅对当前 View 生效还是也要考虑子 View 的影响
  • 组件的布局问题
  • View 的组件的控制权是否开放给用户,一旦开放,如何处理多层嵌套的问题
  • 多 View 的事件机制

    当前组件的所属关系

    当前版本下组件的隶属关系:

  • Legend 和 Tooltip 仅属于 Chart

  • guide(annotation) 和 axis 都属于 View
  • labels 属于 Geometry 这里不做更多讨论 View 的设计 - 图1 目前 G2 的所有组件是自动生成的,其逻辑如下:

  • Legend 是 Geometry 上的视觉通道 color, size, shape 决定;

  • Axis 是由 Geometry 上的视觉通道 position 决定;
  • Tooltip 默认仅仅在 Chart 上生成
  • labels 受 Geometry 上的 label 方法确定

    G2 4.0 的组件所属关系

  • 每个 view 可以有自己的 tooltip,第一次调用时生成,除非设置 tooltip(false),可以既显示自身的信息,也可以显示子 view 的信息,其判定由 interaction 决定。

  • 每个 View 也需要有自己的 Legend 但是Legend 是否能够控制子 view 图形还需要梳理
  • Geometry 上是否也可以开放 guide,这便于实现 max,min 等同数据密切相关的辅助元素

View 的设计 - 图2

组件的布局

各组件的布局位置:

  • Legend 一般显示在图表绘图区域的外边,保证不与图表的图形、文本相遮挡
  • Axis 显示在绘图区域的边缘,栅格线要在图形的下面,文本保持不与 Legend 的遮挡
  • Legend 也不能同 Axis 遮挡
  • Labels 要保证在图表图形的上面,也不能到画布外面显示不完整
  • Guide (annotation) 的布局同图表的绘制区域相关,有些在图形的下面,有些在图形的上面,也得保证不能被画布边缘裁剪。
  • Tooltip 默认不显示,显示时跟随鼠标

而用户还有更进一步的需求:

  • 要求图表绘图区域和画布的边框自动计算出 padding ,这就需要考虑
    • Axis 和 Legend 在边框上的排布
    • Labels 和 guide 和边框的重合
  • 要求图表绘图区域的文本不能相互遮挡
    • Guide 上的文本遮挡问题
    • Labels 上的遮挡问题
  • Tooltip 不能被边框裁剪,不能跑到窗口外面

    View 的组件的控制权

    前面已经讲了组件大多数会自动生成,其生成逻辑同视觉映射相关,非自动组件有:

  • guide (annotation) 用户整个 view 时,需要指定具体的位置

  • 滑动条,用来对数据进行过滤,一般需要用户单独指定
  • 其他组件,用户只能控制是否显示(生效)

但是在 G2 4.0 中需要考虑组件的扩展,需要增加更多种的组件类型

View 的事件机制

当事件在 View 上触发时需要解决下面的这些问题:

  • 事件是否属于 View,是否需要冒泡抛出
  • View 的组件触发事件,是否也要在 View 上抛出
  • 当一个事件同时发生在多个 View 中时,如何处理
  • 统一的事件机制,来自图形元素的事件、空白画布处的事件、Element 的事件、View 上的事件、组件上的事件

    Controller

    看到上面的内容后,你就理解 Controller 是来干什么了,Controller 的功能是:

  • 根据 Geometry 上的映射规则自动生成组件

  • 完成组件的布局,防止同画布绘制区域重合
  • Chart、View、Geometry 更新时同步更新
  • 处理好 Chart、View、Geometry 等层级的事件

    G2 4.0 中的设计

    首先确定无论是否支持 View 嵌套都要支持的功能:

  • 组件的自动生成需要在 View/Chart 的 Controller 中实现

  • 自适应边框 padding ,仅在 Chart 层考虑,通用的 view 层不支持
  • 支持组件指定类型,用户可以通过继承来扩展对应的组件
  • Chart 和 View 上没有同数据互动的交互,所有交互由外部的 interaction 实现
  • 统一的事件处理机制

    分面

    G2 中默认支持了几种常见的分面:rect, list, tree, mirror, matrix
    当前分面的问题:

  • 不可用问题:而当前的分面一个分面仅能使用一个 View ,那么多层的地图、点图和回归线、个别双轴图(数据源不一样时)。

  • 不好用问题:多个分面使用共同的 Geometry (包括映射语法),依然需要循环多次
  • 交互联动问题:显示 tooltip,筛选等操作都受限
  • 分面的间距、坐标轴文本的是否显示等等跟布局、遮挡相关的问题

在 G2 4.0 设计时,需要考虑一个问题:分面是否不应该是 G2 默认的功能,而是上层的一个产品?
要解开上面的问题,需要进行下面的一些改造:

  • 重新引入统计函数,认为原始数据和统计值是同一份数据源,就不需要拆分多个 View
  • 支持无限级 View 的嵌套,度量的统一可以在 View 层确定
  • 不好用的问题,可能需要在上层的产品来解决。在 G2 层仅能提供机制,很难做的精细
  • 交互联动问题,下面章节讨论
  • 分面的间距,同 View 上的组件布局是同一个问题,需要一起解决

多View 交互

多 View 的交互需要以 View 的事件机制来保证,View 之间进行联动主要有下面几个场景:

  • 一起进行数据过滤,图例筛选、框选等
  • 同时显示 View 上的数据细节,tooltip 联动
  • 一个 View 上交互的图形,其他 View 上的图形同等反馈

由于 G2 不在内部添加任何交互的逻辑,所以需要在 interaction 中实现上面的功能,可以默认实现一些交互,其他的让用户自己进行扩展。

数据过滤

可以定义一个状态量,将筛选的范围放到状态量中,interaction 监听状态量的变化,然后更新相关的 view。

tooltip 联动

定义一个 interaction ,监听鼠标移动事件,直接调用各个 view 上显示 tooltip 的接口

最终的类图

View 的设计 - 图3需要实现以下功能:

  • chart 上对组件的配置能够影响所有 view, view 上的配置项能够影响所有子 View
  • 如果度量需要同步 sync ,那么度量在设置 sync 的那一层创建,所有子 view 共享
  • View 可以组件(axis, legend),并可以动态的修改一些配置项

总结

本章讨论了 View 的设计,原先对 View 使用不多的用户不会受到很大影响。如果你是一个图表的开发者,你会发现View 的变化使得你对图表的控制更加精细,如果你是一位多维分析工具的开发者,这将是你梦寐以求的工具。