VTable 是 VisActor 可视化体系中的表格组件库,基于可视化渲染引擎 VRender 进行封装。 VTable 以其优异的性能表现,丰富的可视化能力,迅速得到大量用户的认可。同时也有大批开发者对其实现原理感兴趣,我们将撰写一系列文章来进行详细介绍。
本篇文章介绍一下VTable的架构设计和底层实现。
Options
是用户传入的表格配置,用来描述表格的结构、内容和样式。Options
中主要有以下几类配置:
详细的Options
配置可以参考VTable配置文档 https://www.visactor.io/vtable/option/
用户通过Record
将数据传入传入,除了原始数据外,用户还可以通过配置Filter
自定义数据的过滤规则,以及通过配置Sort
定义数据在表格中的显示顺序;在透视表中,Satistics
模块可以对数据进行数据统计,依据用户的配置计算相应的小计、总计、平均等统计信息。
详细的数据统计相关配置可以参考VTable配置文档 https://www.visactor.io/vtable/option/PivotTable#dataConfig
Theme
模块管理表格的全局样式,通过Theme
模块可以配置表头单元格和内容单元格的样式(背景、边框、文字样式等),也可以配置表格整体的边框、圆角、阴影等,还可以配置菜单、标题、滚动条等表格组件的样式。
详细的主题相关配置可以参考VTable配置文档 https://www.visactor.io/vtable/option/ListTable#theme
Layout
模块负责表格的整体布局,包括通过配置生成行列表头,分配单元格的行列号等任务。
在ListTable中,Layout
分析columns
配置,生成表头单元格信息;在PivotTable中,Layout
分析columnTree
,rowTree
,columns
,rows
配置,生成行列表头单元格信息;表头单元格的合并信息也在此时产生,以下图为例,由于其中Full Name
列配置了多级标题,因此同级的ID
列表头为上下两个单元格合并,Full Name
列的上层表格为左右两个单元格合并:
在表头单元格信息生成后,表格整体的行列信息(表头区域的行列范围、内容区域的行列范围等),以及表格中每条数据对应的单元格行列坐标也由Layout
模块计算得出。
一些布局结构更新操作(树形结构折叠展开,拖拽改变行列位置等),Layout
模块会更新表头,表格整体的行列信息和数据对应的单元格行列坐标,随后通过Scenegraph
模块更新相应的单元格节点。
State
模块管理者表格当前的状态,包括冻结、选中、hover、滚动等等的表格状态。在状态改变时,State
模块会处理相关的变更信息,改变保存的表格状态,并触发Scenegraph
模块的更新,改变相应的单元格节点内容与样式,进而改变画面中表格的展示形态。以列宽改变交互为例:
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
模块负责表格场景节点的创建与更新,表格整体场景节点是基于VRender提供的图元创建的场景树结构,按照表格->表头/内容->列->单元格->单元格内容的组织顺序,一层层构建而成。
Scenegraph
模块将表格分为以下几个区域:
这几个区域所覆盖的单元格行列区域由Layout
模块计算所得,初始化的时候Scenegraph
模块会分别创建这个几个区域的的单元格节点。Scenegraph
模块除了创建单元格节点外,还提供场景节点相关的查询和更新功能,例如通过行列号查找相应的单元格节点,更新单元格节点内的图元树形,添加和删除单元格节点等。
单元格节点会依据当前单元格类型,在单元格中创建相应的图元:
text
/link
类型单元格中为Text
图元,link
类型会有不同的样式及点击跳转交互image
/video
类型单元格中为Image
图元,video
类型有点击播放交互progressbar
类型单元格为进度图,其中为Rect
图元和Text
图元的组合sparkline
类型单元格为迷你图,其中为Line
图元和Symbol
等图元的组合checkbox
类型单元格为选中框,其中为Symbol
图元和Text
等图元的组合chart
类型单元格为图表,其中为VChart图表实例单元格中如果有图标(表头单元格或内容单元格配置icon属性),相应的Image
图元也会创建在相应的单元格节点中。
ProgressProxy
是Scenegraph
模块中的一个子模块,主要负责大数据量下首屏和交互时的性能优化。ProgressProxy
模块会定义场景节点中维护的行列最大数量限制,以避免超大数据量下,场景节点过多导致的超长创建和更新时间。在首屏加载过程中,ProgressProxy
模块会控制节点的创建,首先创建屏幕范围内的单元格,随后异步渐进完成场景节点的创建。在大数据量滚动时,ProgressProxy
模块会动态更新场景节点,滚动期间,按照滚动的方向,一部分单元格会更新其在场景树中的位置,并更新单元格内的图元,完成滚动效果。
VTable的底层渲染由VRender实现,Scenegraph
模块组织好的场景树会加载到VRender的Stage
中,进行渲染;VRender提供的按需重绘及合并异步渲染能能力,支持了VTable的高性能渲染需求。
VRender参考 https://github.com/VisActor/VRender
接下来,我们来简单介绍一下VTable初始化一个表格的完整流程:
第一步,在创建VTable实例后,会初始化各个模块,创建表格渲染的Canvas元素。Scenegraph
模块会创建VRender Stage
,用来管理整个渲染过程,并生成基础的场景节点结构;Event
模块会绑定表格内使用的交互事件,表格事件和自定义事件;State
模块会依据options配置设置表格初始的各项状态。Layout
模块依据options计算行列表头信息,以及表格整体的行列信息,从而得到每条数据对应的行列坐标。
第二步,数据处理,已经用户配置的过滤和排序规则,处理Record数据。如果有树形结构和数据分析的需求,会进一步处理数据,生成相应的结果信息。完成数据处理后,会更新Layout
模块中的表格行列数目信息。
第三步,创建场景节点,依据布局结果和数据,生成相应的单元格场景节点。随后会依据样式配置表格根节点的边框等属性,并生成表格配套组件和其对应的场景节点。最后,依据body部分的单元格尺寸,更新相应容器的尺寸和滚动条节点的状态(尺寸、位置)。
完成所有场景节点的创建更新后,VRender Stage
开始渲染整个场景树,表格就在Canvas元素中被绘制出来了。
我们再以拖拽改变列宽为例,简单介绍一下VTable状态更新的完整流程:
State
模块改变当前状态,并记录初始鼠标位置;Scenegraph
模块显示列宽调整辅助组件,并触发表格重绘。State
模块依据初始鼠标位置和当前鼠标位置,计算新列宽;Scenegraph
模块更新相应节点的宽度属性和布局,以及列宽调整辅助组件的位置;State
模块触发表格事件RESIZE_COLUMN
,Scenegraph
模块触发表格重绘。State
模块结束列宽调整状态,并触发RESIZE_COLUMN_END
;Scenegraph
模块隐藏列宽调整辅助组件,并触发表格重绘。联系方式
项目官网:https://www.visactor.io/vtable
微信公众号(通过公众号菜单可以加入微信群和飞书群):
twiter:https://twitter.com/xuanhun1
今夜无月,期待你点亮星空,感谢Star:
github:https://github.com/VisActor/VTable
更多参考: