高性能多维分析表格实现原理剖析

技术

VTable 是 VisActor 可视化体系中的表格组件库,基于可视化渲染引擎 VRender 进行封装。 VTable 以其优异的性能表现,丰富的可视化能力,迅速得到大量用户的认可。同时也有大批开发者对其实现原理感兴趣,我们将撰写一系列文章来进行详细介绍。

本篇文章介绍一下VTable的架构设计和底层实现。

模块简介

picture.image

Options

Options 是用户传入的表格配置,用来描述表格的结构、内容和样式。 Options中主要有以下几类配置:

  • 列表配置:列表的表头配置,转置配置,以及列(行)对应的单元格类型等
  • 透视表配置:透视表行列表头配置,指标所在位置,以及指标对应的单元格类型等
  • 表格宽高相关配置:表格长宽方向的显示模式(依内容自动宽高、适应容器等),表格的默认宽高等
  • 表格状态相关配置:表格的冻结、排序等状态
  • 表格组件相关配置:表格的标题、菜单、滚动条等组件配置

详细的 Options配置可以参考VTable配置文档 https://www.visactor.io/vtable/option/

Dataset

用户通过 Record将数据传入传入,除了原始数据外,用户还可以通过配置 Filter自定义数据的过滤规则,以及通过配置 Sort定义数据在表格中的显示顺序;在透视表中, Satistics模块可以对数据进行数据统计,依据用户的配置计算相应的小计、总计、平均等统计信息。

详细的数据统计相关配置可以参考VTable配置文档 https://www.visactor.io/vtable/option/PivotTable#dataConfig

Theme

Theme模块管理表格的全局样式,通过 Theme模块可以配置表头单元格和内容单元格的样式(背景、边框、文字样式等),也可以配置表格整体的边框、圆角、阴影等,还可以配置菜单、标题、滚动条等表格组件的样式。

详细的主题相关配置可以参考VTable配置文档 https://www.visactor.io/vtable/option/ListTable#theme

Layout

Layout模块负责表格的整体布局,包括通过配置生成行列表头,分配单元格的行列号等任务。

在ListTable中, Layout分析 columns配置,生成表头单元格信息;在PivotTable中, Layout分析 columnTreerowTreecolumnsrows配置,生成行列表头单元格信息;表头单元格的合并信息也在此时产生,以下图为例,由于其中 Full Name列配置了多级标题,因此同级的 ID列表头为上下两个单元格合并, Full Name列的上层表格为左右两个单元格合并:

picture.image

在表头单元格信息生成后,表格整体的行列信息(表头区域的行列范围、内容区域的行列范围等),以及表格中每条数据对应的单元格行列坐标也由 Layout模块计算得出。

一些布局结构更新操作(树形结构折叠展开,拖拽改变行列位置等), Layout模块会更新表头,表格整体的行列信息和数据对应的单元格行列坐标,随后通过 Scenegraph模块更新相应的单元格节点。

State

State模块管理者表格当前的状态,包括冻结、选中、hover、滚动等等的表格状态。在状态改变时, State模块会处理相关的变更信息,改变保存的表格状态,并触发 Scenegraph模块的更新,改变相应的单元格节点内容与样式,进而改变画面中表格的展示形态。以列宽改变交互为例:

picture.image

Event

Event模块负责表格中监听和触发事件,表格内监听的交互事件会触发 State模块相应的状态更新,部分表格的状态的更新也会通过 Event模块触发表格定义的事件类型。其中 Event模块管理事件主要分为三类:

  • 交互事件: Event模块会监听VRender图元的交互事件,并触发相应的表格交互事件( MOUSEMOVE_CELL, CLICK_CELL, MOUSELEAVE_CELL等),供表格内部模块以及用户监听使用。
  • 表格事件:表格事件是指有基础交互触发的表格相应状态改变时,触发的表格定义的事件,例如单元格选择 SELECTED_CELL,列宽调整 RESIZE_COLUMN,表格滚动 SCROLL,拖拽改变表头位置 CHANGE_HEADER_POSITION等。
  • 自定义事件:自定义事件是指表格内组件或用户定义的事件,由定义方按需求触发和监听使用,例如显示菜单 SHOW_MENU,图例点击切换 LEGEND_CHANGE,选择框状态改变 CHECKBOX_STATE_CHANGE等。

Scenegraph

Scenegraph模块负责表格场景节点的创建与更新,表格整体场景节点是基于VRender提供的图元创建的场景树结构,按照表格->表头/内容->列->单元格->单元格内容的组织顺序,一层层构建而成。

picture.image

Scenegraph模块将表格分为以下几个区域:

picture.image

这几个区域所覆盖的单元格行列区域由 Layout模块计算所得,初始化的时候 Scenegraph模块会分别创建这个几个区域的的单元格节点。 Scenegraph模块除了创建单元格节点外,还提供场景节点相关的查询和更新功能,例如通过行列号查找相应的单元格节点,更新单元格节点内的图元树形,添加和删除单元格节点等。

单元格类型

单元格节点会依据当前单元格类型,在单元格中创建相应的图元:

  • text/link: text/ link类型单元格中为 Text图元, link类型会有不同的样式及点击跳转交互
  • image/video: image/ video类型单元格中为 Image图元, video类型有点击播放交互
  • progressbar: progressbar类型单元格为进度图,其中为 Rect图元和 Text图元的组合

picture.image

  • sparkline: sparkline类型单元格为迷你图,其中为 Line图元和 Symbol等图元的组合

picture.image

  • checkbox: checkbox类型单元格为选中框,其中为 Symbol图元和 Text等图元的组合

picture.image

  • chart: chart类型单元格为图表,其中为VChart图表实例

单元格中如果有图标(表头单元格或内容单元格配置icon属性),相应的 Image图元也会创建在相应的单元格节点中。

ProgressProxy

ProgressProxyScenegraph模块中的一个子模块,主要负责大数据量下首屏和交互时的性能优化。 ProgressProxy模块会定义场景节点中维护的行列最大数量限制,以避免超大数据量下,场景节点过多导致的超长创建和更新时间。在首屏加载过程中, ProgressProxy模块会控制节点的创建,首先创建屏幕范围内的单元格,随后异步渐进完成场景节点的创建。在大数据量滚动时, ProgressProxy模块会动态更新场景节点,滚动期间,按照滚动的方向,一部分单元格会更新其在场景树中的位置,并更新单元格内的图元,完成滚动效果。

picture.image

Render

VTable的底层渲染由VRender实现, Scenegraph模块组织好的场景树会加载到VRender的 Stage中,进行渲染;VRender提供的按需重绘及合并异步渲染能能力,支持了VTable的高性能渲染需求。

VRender参考 https://github.com/VisActor/VRender

从数据到画面

初始化

接下来,我们来简单介绍一下VTable初始化一个表格的完整流程:

  1. 基础模块初始化

picture.image

第一步,在创建VTable实例后,会初始化各个模块,创建表格渲染的Canvas元素。 Scenegraph模块会创建VRender Stage,用来管理整个渲染过程,并生成基础的场景节点结构; Event模块会绑定表格内使用的交互事件,表格事件和自定义事件; State模块会依据options配置设置表格初始的各项状态。 Layout模块依据options计算行列表头信息,以及表格整体的行列信息,从而得到每条数据对应的行列坐标。

  1. 接收处理数据

picture.image

第二步,数据处理,已经用户配置的过滤和排序规则,处理Record数据。如果有树形结构和数据分析的需求,会进一步处理数据,生成相应的结果信息。完成数据处理后,会更新 Layout模块中的表格行列数目信息。

  1. 场景节点生成与渲染

picture.image

第三步,创建场景节点,依据布局结果和数据,生成相应的单元格场景节点。随后会依据样式配置表格根节点的边框等属性,并生成表格配套组件和其对应的场景节点。最后,依据body部分的单元格尺寸,更新相应容器的尺寸和滚动条节点的状态(尺寸、位置)。

完成所有场景节点的创建更新后,VRender Stage开始渲染整个场景树,表格就在Canvas元素中被绘制出来了。

状态更新

我们再以拖拽改变列宽为例,简单介绍一下VTable状态更新的完整流程:

  1. 接收mousedown事件,如果鼠标位置在列边缘,则开始拖拽改变列宽。 State模块改变当前状态,并记录初始鼠标位置; Scenegraph模块显示列宽调整辅助组件,并触发表格重绘。

picture.image

  1. 接收mousemove事件,如果在拖拽改变列宽过程中, State模块依据初始鼠标位置和当前鼠标位置,计算新列宽; Scenegraph模块更新相应节点的宽度属性和布局,以及列宽调整辅助组件的位置; State模块触发表格事件 RESIZE_COLUMNScenegraph模块触发表格重绘。

picture.image

  1. 接收mouseup事件,如果在拖拽改变列宽过程中, State模块结束列宽调整状态,并触发 RESIZE_COLUMN_ENDScenegraph模块隐藏列宽调整辅助组件,并触发表格重绘。

picture.image

欢迎交流

联系方式

项目官网:https://www.visactor.io/vtable

微信公众号(通过公众号菜单可以加入微信群和飞书群):

twiter:https://twitter.com/xuanhun1

今夜无月,期待你点亮星空,感谢Star:

githubhttps://github.com/VisActor/VTable

picture.image

更多参考:

  1. 基于 VTable 的多维数据展示的原理与实践

  2. VTable——不只是高性能的多维数据分析表格

  3. VisActor——面向叙事的智能可视化解决方案

  4. 火山引擎DataWind产品可视化能力揭秘

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论