Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 明细表-列分组增加 rowSpan 配置项, 用来支持自定义合并单元格 close #2150 #2159

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
50 changes: 50 additions & 0 deletions packages/s2-core/__tests__/data/simple-table-data-rowspan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"fields": {
"columns": [
{
"key": "price",
"rowSpan": 2,
"children": [
{
"key": "cost",
"rowSpan": 1
}
]
},
"province",
{
"key": "city",
"rowSpan": 1,
"children": [
{
"key": "type",
"rowSpan": 2
}
]
}
]
},
"data": [
{
"province": "浙江",
"city": "义乌",
"type": "笔",
"price": 1,
"cost": 2
},
{
"province": "浙江",
"city": "义乌",
"type": "笔",
"price": 1,
"cost": 2
},
{
"province": "浙江",
"city": "杭州",
"type": "笔",
"price": 1,
"cost": 2
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* @description spec for issue #2150
* https://github.com/antvis/S2/issues/2150
* 明细表-列分组增加 rowSpan 配置项, 用来支持自定义合并单元格
*/
import { getContainer } from 'tests/util/helpers';
import dataCfg from 'tests/data/simple-table-data-rowspan.json';
import { TableSheet } from '@/sheet-type';
import type { S2Options } from '@/common';

const s2Options: S2Options = {
width: 600,
height: 480,
};

describe('TableSheet Sort Tests', () => {
test('should be rendered based on the rowSpan', () => {
const s2 = new TableSheet(getContainer(), dataCfg, s2Options);
s2.render();
const { height: cellHeightOfLevel0 } = s2.getColumnNodes(0).slice(-1)[0];
const { height: cellHeightOfLevel1 } = s2.getColumnNodes(1).slice(-1)[0];
expect(cellHeightOfLevel0 * 2).toBe(cellHeightOfLevel1);
});
});
1 change: 1 addition & 0 deletions packages/s2-core/src/common/interface/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export interface Fields {
export interface ColumnNode {
key: string;
children?: Columns;
rowSpan?: number;
}

export interface TotalsStatus {
Expand Down
89 changes: 85 additions & 4 deletions packages/s2-core/src/facet/table-facet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
isBoolean,
isNil,
isNumber,
isString,
last,
maxBy,
omit,
set,
values,
} from 'lodash';
Expand All @@ -23,6 +25,8 @@ import {
import { FrozenCellGroupMap } from '../common/constant/frozen';
import { DebuggerUtil } from '../common/debug';
import type {
ColumnNode,
Columns,
FilterParam,
LayoutResult,
ResizeInteractionOptions,
Expand Down Expand Up @@ -289,11 +293,68 @@ export class TableFacet extends BaseFacet {
return cellCfg?.width;
}

/** 扁平化树形 columns */
private flattenTree(tree: Columns): Columns {
return tree.reduce((prev, curr) => {
if (isString(curr)) {
prev = prev.concat(curr);
} else {
prev = prev.concat(omit(curr, 'children'));
if (curr.children?.length) {
prev = prev.concat(this.flattenTree(curr.children));
}
}
return prev;
}, []);
}

/** 当前节点所在列是否配置了 rowSpan */
private hasRowSpanInBranch(tree: Columns, field: string): boolean {
const columns = tree.map((item) => this.flattenTree([item]));
const branch = columns.find((items) => {
return items.some((item) => {
if (isString(item)) {
return item === field;
}
if (item.key === field) {
return true;
}
return false;
});
});
return branch?.some((item) => !isString(item) && Boolean(item?.rowSpan));
}

/** 当前节点的 rowSpan */
private findRowSpanInCurrentNode(
columns: Columns,
field: string,
): number | void {
const flattedColumns = this.flattenTree(columns);
const column = flattedColumns.find((item) => {
return !isString(item) && item.key === field;
});
return !isString(column) && column?.rowSpan;
}

/** TIP: 获取列头 Node 高度 */
private getColNodeHeight(col: Node, totalHeight?: number) {
const { colCfg } = this.cfg;
const { colCfg, columns } = this.cfg;

// 明细表所有列节点高度保持一致
const userDragHeight = values(colCfg?.heightByField)[0];

const hasRowSpanInBranch = this.hasRowSpanInBranch(columns, col.field);
const currentRowSpan = this.findRowSpanInCurrentNode(columns, col.field);

/** 用户拖拽高度 > 配置高度 */
const height = userDragHeight || colCfg?.height;

// 如果当前列任意 leaf 设置了 rowSpan, 按照 rowSpan 划分列头单元格高度
if (hasRowSpanInBranch) {
wywppkd marked this conversation as resolved.
Show resolved Hide resolved
return height * (currentRowSpan || 1);
}

if (!totalHeight) {
return height;
}
Expand All @@ -308,15 +369,35 @@ export class TableFacet extends BaseFacet {
return totalHeight;
}

private getKeysOfFirstColumn(columns: Columns) {
let res = [];
const key = isString(columns?.[0]) ? columns?.[0] : columns?.[0]?.key;
if (key) {
res = res.concat(key);
}
if (!isString(columns?.[0]) && columns?.[0]?.children?.length) {
res = res.concat(this.getKeysOfFirstColumn(columns?.[0]?.children));
}
return res;
}

private calculateColNodesCoordinate(
colLeafNodes: Node[],
colsHierarchy: Hierarchy,
) {
const { columns } = this.cfg;
let preLeafNode = Node.blankNode();
const allNodes = colsHierarchy.getNodes();
for (const levelSample of colsHierarchy.sampleNodesForAllLevels) {
levelSample.height = this.getColNodeHeight(levelSample);
colsHierarchy.height += levelSample.height;

const keys = this.getKeysOfFirstColumn(columns);

const nodesOfFirstColumn = allNodes.filter((node) => {
return keys.includes(node.field);
});

for (const nodeSample of nodesOfFirstColumn) {
nodeSample.height = this.getColNodeHeight(nodeSample);
colsHierarchy.height += nodeSample.height;
}
const adaptiveColWidth = this.getAdaptiveColWidth(colLeafNodes);
let currentCollIndex = 0;
Expand Down
3 changes: 2 additions & 1 deletion s2-site/docs/api/general/S2DataConfig.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,6 @@ Function description: used to support custom data cell rendering of multiple ind

| 属性名称 | 说明 | 类型 | 默认值 | 必选 |
| ------- | ---------| -------| ------|------|
| name | 列字段 id 或分组 id | string | | ✓ |
| key | 列字段 id 或分组 id | string | | ✓ |
| rowSpan | 合并单元格行数,配置后则优先按照 rowSpan 规划列头单元格高度 | number | | |
| children | 分组下面的子级 | Array\<ColumnNode \| string\> | | |
1 change: 1 addition & 0 deletions s2-site/docs/api/general/S2DataConfig.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,5 @@ object **必选**,_default:null_
| 属性名称 | 说明 | 类型 | 默认值 | 必选 |
| ------- | ---------| -------| ------|------|
| key | 列字段 id 或分组 id | string | | ✓ |
| rowSpan | 合并单元格行数,配置后则优先按照 rowSpan 规划列头单元格高度 | number | | |
| children | 分组下面的子级 | `Array<ColumnNode \| string>` | | |
8 changes: 8 additions & 0 deletions s2-site/examples/basic/table/demo/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@
"en": "Column Group"
},
"screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*DgnhTYveL1AAAAAAAAAAAAAADmJ7AQ/original"
},
{
"filename": "table-column-group-customize-cell.ts",
"title": {
"zh": "列分组自定义合并单元格",
"en": "Column Group Customize The Cell"
},
"screenshot": "/rowspan.png"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { TableSheet } from '@antv/s2';

fetch('https://assets.antv.antgroup.com/s2/basic-table-mode.json')
.then((res) => res.json())
.then((data) => {
const container = document.getElementById('container');
const s2DataConfig = {
fields: {
columns: [
{
key: 'area',
rowSpan: 1,
children: [
{
key: 'province',
rowSpan: 2,
},
{
key: 'city',
rowSpan: 2,
},
],
},
'type',
{
key: 'money',
rowSpan: 2,
children: [
{
key: 'price',
rowSpan: 1,
},
],
},
],
},
meta: [
{
field: 'province',
name: '省份',
},
{
field: 'city',
name: '城市',
},
{
field: 'type',
name: '商品类别',
},
{
field: 'price',
name: '价格',
},
{
field: 'cost',
name: '成本',
},
{
field: 'area',
name: '位置',
},
{
field: 'money',
name: '金额',
},
],
data,
};

const s2Options = {
width: 600,
height: 480,
showSeriesNumber: true,
};
const s2 = new TableSheet(container, s2DataConfig, s2Options);

s2.render();
});
Binary file added s2-site/public/rowspan.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading