相关源码位置
- package/vtable/src/scenegraph/group-creater/cell-helper.ts:VTable 渲染引擎中单元格处理的核心文件,提供了 用于根据不同列类型创建单元格(
createCell)、负责单元格的动态更新(updateCell和updateCellContent)等功能;- package/vtable/src/scenegraph/group-creater/column-helper.ts:基于createCell单元格创建实现了复合列表ComplexColumn的合并、渲染处理;
- package/vtable/src/scenegraph/group-creater/column.ts:基于CreateComplexColumn从起始列到结束列,遍历创建列组,从而构建整个表格的列结构;
表格的创建流程
表格的场景图的构建过程是层层递进的,整体流程大致是先通过createCell函数创建单个单元格,然后利用createComplexColumn函数创建复合列(同一列中不同类型的单元格),最后通过createColGroup函数遍历生成表格的列组,进而形成整个表格的结构。
下面逐层分析创建的流程:
单元格的创建(
功能:根据传入的单元格类型
type,创建相应类型的单元格。支持的类型包括text、image、video、chart、progressbar、sparkline、checkbox、radio等。
function createCell( type: ColumnTypeOption, // 单元格类型(text/link/image/chart等) value: string, // 单元格显示值 define: ColumnDefine, // 列定义配置 table: BaseTableAPI, // 表格实例 col: number, // 列索引 row: number, // 行索引 colWidth: number, // 列宽 cellWidth: number, // 单元格实际宽度(可能合并) cellHeight: number, // 单元格高度 columnGroup: Group, // 父容器(列组) y: number, // Y轴位置 padding: [number, number, number, number], // 内边距 textAlign: CanvasTextAlign, // 文本对齐 textBaseline: CanvasTextBaseline, // 文本基线 mayHaveIcon: boolean, // 是否可能包含图标 cellTheme: IThemeSpec, // 主题样式 range: CellRange | undefined, // 合并单元格范围 customResult?: { elementsGroup?: VGroup; renderDefault: boolean; } ): Group
这个函数源码的大部分结构是根据不同的CellType进入不同的创建流程,对创建的Group对象通过Factory.getFunction动态获取各类型创建函数,然后配置不同单元格特有的参数或逻辑处理,

列的创建(createComplexColumn)
功能:在指定的列范围内,根据单元格的合并情况、数据类型等,创建复合列,计算或获取合并单元格的总宽度和高度,并通过Map缓存优化性能。
确认插入坐标坐标
复杂列的创建 一开始先确认插入的坐标,根据 columnGroup 的最后一个子元素和高度,确定单元格插入的起始Y坐标;如果连续插入单元格的话,就跟在现有的高度上累加上单元格的高度,从而形成列的结构。这里处理了连续添加单元格时的垂直定位问题。
let y = 0; if (columnGroup.lastChild && (columnGroup.lastChild as Group).row === rowStart - 1) { y = (columnGroup.lastChild as Group).attribute.y + (columnGroup.lastChild as Group).attribute.height; } else if (columnGroup.colHeight) { y = columnGroup.colHeight; }
合并单元格dealMerge
接着从起始行至终止行开始执行遍历循环,处理单元格的合并算法;处理单元格的合并,即通过计算更新单元格的宽度和高度(计算mergeSize)实现合并的效果。此处的缓存指的是以起始行列的拼接值做键,通过Map缓存mergeResult ,存储计算的CellWitdh和CellHeight值,避免重复计算
function dealMerge(range: CellRange, mergeMap: MergeMap, table: BaseTableAPI, forceUpdate: boolean) {
let cellWidth = 0;
let cellHeight = 0;
const mergeResult = mergeMap.get(`${range.start.col},${range.start.row};${range.end.col},${range.end.row}`);
if (!mergeResult || forceUpdate) {
for (let col = range.start.col; col <= range.end.col; col++) {
cellWidth += table.getColWidth(col);
}
// let cellHeight = 0;
for (let i = range.start.row; i <= range.end.row; i++) {
cellHeight += table.getRowHeight(i);
}
mergeMap.set(`${range.start.col},${range.start.row};${range.end.col},${range.end.row}`, {
cellWidth,
cellHeight
});
} else {
cellWidth = mergeResult.cellWidth;
cellHeight = mergeResult.cellHeight;
}
return {
cellWidth,
cellHeight
};
}
表格的创建(createColGroup)
功能:在指定的列和行范围内,创建列组,从而构建整个表格的列结构。
for (let i = colStart; i <= colEnd; i++) { const col = i; const colWidth = table.getColWidth(col); const columnGroup = new Group({ x: xOrigin + x, y: yOrigin, width: colWidth, height: 0, clip: false, pickable: false }); columnGroup.role = 'column'; columnGroup.col = i; containerGroup.addChild(columnGroup); const { width: default2Width, height: default2Height } = createComplexColumn( columnGroup, col, colWidth, rowStart, rowEnd, table.scenegraph.mergeMap, cellLocation === 'columnHeader' && isNumber(defaultHeaderRowHeight) ? (defaultHeaderRowHeight as number) : defaultRowHeight, table, // cellLocation, rowLimit ); x += default2Width; heightMax = Math.max(heightMax, default2Height); }
这段代码首先从起始列到末尾列依次遍历,依次执行:
-
创建列组对象
columnGroup,x: xOrigin + x理解起来比较形象,x (偏移量)随着循环创建列组而不断累加,不难想象由此每一列组都能依次排列在水平方向上;width: colWidth设置列组的宽度为当前列的宽度colWidth,该宽度通过table.getColWidth(col)获取;height: 0初始时将列组的高度设置为 0,后续会根据该列中实际创建的元素(如单元格)的高度进行更新。 -
设置列组属性和索 引,设置
role属性为'column',列组设置col属性为当前列的索引i,这样可以明确该列组对应的是表格中的哪一列。 -
通过调用
createComplexColumn函数,在指定的列组中创建ComplexColumn复合列,并动态更新布局参数。createComplexColumn函数接收多个参数,包括列组、列索引、列宽、行范围等,同时会考虑单元格的位置、合并情况以及默认行高,最终生成相应的列结构。