From 7e30008ca4d784c740dccd26a6fa891579d1cb99 Mon Sep 17 00:00:00 2001 From: Jinke Li Date: Fri, 20 Dec 2024 11:54:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E8=A1=A8=E8=87=AA=E5=AE=9A=E4=B9=89=E5=88=97=E5=A4=B4=E6=97=B6?= =?UTF-8?q?,=20=E9=9A=90=E8=97=8F=E5=88=97=E5=A4=B4=E5=90=8E=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=E7=A9=BA=E7=99=BD=E5=8C=BA=E5=9F=9F=20close=20#3044?= =?UTF-8?q?=20(#3046)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复明细表自定义列头时, 隐藏列头后出现空白区域 close #3044 * test: 更新快照 --- jest.config.base.js | 1 - .../__tests__/data/custom-table-col-fields.ts | 27 ++++++++++++ .../custom-table-col-spec.ts.snap | 41 +++++++++++++++++++ .../spreadsheet/custom-table-col-spec.ts | 31 ++++++++++++++ packages/s2-core/scripts/test-live.mjs | 2 +- packages/s2-core/src/facet/base-facet.ts | 32 +++++++++++++++ packages/s2-core/src/facet/pivot-facet.ts | 35 +--------------- packages/s2-core/src/facet/table-facet.ts | 27 +----------- packages/s2-react/scripts/test-live.mjs | 2 +- s2-site/docs/common/interaction.zh.md | 2 +- .../advanced/interaction/hide-columns.zh.md | 23 ++++++++--- .../advanced/demo/pivot-hide-columns.ts | 2 +- .../advanced/demo/table-hide-columns.ts | 1 + 13 files changed, 156 insertions(+), 70 deletions(-) diff --git a/jest.config.base.js b/jest.config.base.js index af2e973948..6d436dcbee 100644 --- a/jest.config.base.js +++ b/jest.config.base.js @@ -7,7 +7,6 @@ module.exports = { clearMocks: true, collectCoverage: false, verbose: true, - forceExit: true, collectCoverageFrom: [ 'src/**/*.{ts,tsx,js,vue}', '!**/node_modules/**', diff --git a/packages/s2-core/__tests__/data/custom-table-col-fields.ts b/packages/s2-core/__tests__/data/custom-table-col-fields.ts index a7cadc1437..5e9fbbc95d 100644 --- a/packages/s2-core/__tests__/data/custom-table-col-fields.ts +++ b/packages/s2-core/__tests__/data/custom-table-col-fields.ts @@ -86,3 +86,30 @@ export const customColMultipleColumns: CustomTreeNode[] = [ children: [], }, ]; + +export const customColMultipleColumns2: CustomTreeNode[] = [ + { + field: 'area', + title: '地区', + children: [ + { + field: 'province', + title: '省份', + children: [ + { + field: 'type', + title: '类型', + }, + ], + }, + { + field: 'city', + title: '城市', + children: [ + { field: 'price', title: '价格', description: '价格描述' }, + { field: 'number', title: '数量' }, + ], + }, + ], + }, +]; diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/custom-table-col-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/custom-table-col-spec.ts.snap index e7310e8255..aa55c6bcec 100644 --- a/packages/s2-core/__tests__/spreadsheet/__snapshots__/custom-table-col-spec.ts.snap +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/custom-table-col-spec.ts.snap @@ -1,5 +1,46 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`TableSheet Custom Tests should calc correctly cell conditions after hide first level node 1`] = ` +Array [ + Object { + "height": 90, + "width": 80, + "x": 0, + "y": 0, + }, + Object { + "height": 30, + "width": 519, + "x": 80, + "y": 0, + }, + Object { + "height": 30, + "width": 0, + "x": 0, + "y": 30, + }, + Object { + "height": 30, + "width": 519, + "x": 80, + "y": 30, + }, + Object { + "height": 30, + "width": 259.5, + "x": 80, + "y": 60, + }, + Object { + "height": 30, + "width": 259.5, + "x": 339.5, + "y": 60, + }, +] +`; + exports[`TableSheet Custom Tests should calc correctly col index of leaf nodes 1`] = ` Array [ Object { diff --git a/packages/s2-core/__tests__/spreadsheet/custom-table-col-spec.ts b/packages/s2-core/__tests__/spreadsheet/custom-table-col-spec.ts index 9c84fffe1b..0ec0afe282 100644 --- a/packages/s2-core/__tests__/spreadsheet/custom-table-col-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/custom-table-col-spec.ts @@ -2,11 +2,13 @@ import type { S2DataConfig, S2Options } from '@/common/interface'; import type { CustomRect } from '@/engine'; import { SpreadSheet, TableSheet } from '@/sheet-type'; import type { Group } from '@antv/g'; +import { pick } from 'lodash'; import { waitForRender } from 'tests/util'; import { getContainer } from 'tests/util/helpers'; import { KEY_GROUP_COL_RESIZE_AREA } from '../../src/common/constant'; import { customColMultipleColumns, + customColMultipleColumns2, customColSimpleColumns, } from '../data/custom-table-col-fields'; import { data } from '../data/mock-dataset.json'; @@ -333,4 +335,33 @@ describe('TableSheet Custom Tests', () => { ); }, ); + + // https://github.com/antvis/S2/issues/3044 + test('should calc correctly cell conditions after hide first level node', async () => { + // 类型 + const hiddenColumns = ['root[&]area[&]province[&]type']; + + s2.setDataCfg({ + ...baseDataConfig, + fields: { + columns: customColMultipleColumns2, + }, + }); + s2.setOptions({ + seriesNumber: { + enable: true, + }, + }); + await s2.render(); + + await waitForRender(s2, () => { + s2.interaction.hideColumns(hiddenColumns); + }); + + const colNodes = s2.facet + .getColNodes() + .map((node) => pick(node, ['x', 'y', 'width', 'height'])); + + expect(colNodes).toMatchSnapshot(); + }); }); diff --git a/packages/s2-core/scripts/test-live.mjs b/packages/s2-core/scripts/test-live.mjs index ac491d2ea5..5acde67f40 100644 --- a/packages/s2-core/scripts/test-live.mjs +++ b/packages/s2-core/scripts/test-live.mjs @@ -8,7 +8,7 @@ import ora from 'ora'; inquirer.registerPrompt('autocomplete', autoCompletePrompt); function run(path) { - const command = `cross-env DEBUG_MODE=1 npx jest ${path} --passWithNoTests`; + const command = `cross-env DEBUG_MODE=1 npx jest ${path} --passWithNoTests --detectOpenHandles`; const jestSpinner = ora(`[测试运行中]: ${command}`).start(); try { diff --git a/packages/s2-core/src/facet/base-facet.ts b/packages/s2-core/src/facet/base-facet.ts index 440fffcd59..0ea141855f 100644 --- a/packages/s2-core/src/facet/base-facet.ts +++ b/packages/s2-core/src/facet/base-facet.ts @@ -537,6 +537,38 @@ export abstract class BaseFacet { return height; } + /** + * 根据叶子节点宽度计算所有父级节点宽度和 x 坐标 + */ + protected calculateColParentNodeWidthAndX(colLeafNodes: Node[]) { + let prevColParent: Node | null = null; + let i = 0; + + const leafNodes = colLeafNodes.slice(0); + + while (i < leafNodes.length) { + const node = leafNodes[i++]; + const parentNode = node?.parent; + + if (prevColParent !== parentNode && parentNode) { + leafNodes.push(parentNode); + + const firstVisibleChildNode = parentNode.children?.find( + (childNode) => childNode.width, + ); + // 父节点 x 坐标 = 第一个未隐藏的子节点的 x 坐标 + const parentNodeX = firstVisibleChildNode?.x || 0; + // 父节点宽度 = 所有子节点宽度之和 + const parentNodeWidth = sumBy(parentNode.children, 'width'); + + parentNode.x = parentNodeX; + parentNode.width = parentNodeWidth; + + prevColParent = parentNode; + } + } + } + /** * 将每一层级的采样节点更新为高度最大的节点 (未隐藏, 非汇总节点) */ diff --git a/packages/s2-core/src/facet/pivot-facet.ts b/packages/s2-core/src/facet/pivot-facet.ts index cad5b22972..dc423659eb 100644 --- a/packages/s2-core/src/facet/pivot-facet.ts +++ b/packages/s2-core/src/facet/pivot-facet.ts @@ -213,7 +213,7 @@ export class PivotFacet extends FrozenFacet { // 1. 计算叶子节点宽度 this.calculateColLeafNodesWidth(layoutResult); // 2. 根据叶子节点宽度计算所有父级节点宽度和 x 坐标, 便于计算自动换行后节点的真实高度 - this.calculateColNodeWidthAndX(colLeafNodes); + this.calculateColParentNodeWidthAndX(colLeafNodes); // 3. 计算每一层级的采样节点 this.updateColsHierarchySampleMaxHeightNodes(colsHierarchy, rowsHierarchy); // 4. 计算所有节点的高度 @@ -376,39 +376,6 @@ export class PivotFacet extends FrozenFacet { }); } - /** - * Auto column no-leaf node's width and x coordinate - * @param colLeafNodes - */ - protected calculateColNodeWidthAndX(colLeafNodes: Node[]) { - let prevColParent: Node | null = null; - let i = 0; - - const leafNodes = colLeafNodes.slice(0); - - while (i < leafNodes.length) { - const node = leafNodes[i++]; - const parentNode = node?.parent; - - if (prevColParent !== parentNode && parentNode) { - leafNodes.push(parentNode); - - const firstVisibleChildNode = parentNode.children?.find( - (childNode) => childNode.width, - ); - // 父节点 x 坐标 = 第一个未隐藏的子节点的 x 坐标 - const parentNodeX = firstVisibleChildNode?.x || 0; - // 父节点宽度 = 所有子节点宽度之和 - const parentNodeWidth = sumBy(parentNode.children, 'width'); - - parentNode.x = parentNodeX; - parentNode.width = parentNodeWidth; - - prevColParent = parentNode; - } - } - } - protected getColLeafNodesWidth( colNode: Node, colLeafNodes: Node[], diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index aae599341b..5e26b85d9f 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -510,7 +510,7 @@ export class TableFacet extends FrozenFacet { ) { // 先计算宽度, 再计算高度, 确保计算多行文本时能获取到正确的最大文本宽度 this.calculateColLeafNodesWidth(colLeafNodes, colsHierarchy); - this.calculateColNodeWidthAndX(colLeafNodes); + this.calculateColParentNodeWidthAndX(colLeafNodes); this.updateColsHierarchySampleMaxHeightNodes(colsHierarchy); this.calculateColNodesHeight(colsHierarchy); this.updateCustomFieldsSampleNodes(colsHierarchy); @@ -520,31 +520,6 @@ export class TableFacet extends FrozenFacet { }); } - /** - * Auto column no-leaf node's width and x coordinate - * @param colLeafNodes - */ - private calculateColNodeWidthAndX(colLeafNodes: Node[]) { - let prevColParent: Node | null = null; - const leafNodes = colLeafNodes.slice(0); - - while (leafNodes.length) { - const node = leafNodes.shift(); - const parent = node?.parent; - - if (prevColParent !== parent && parent) { - leafNodes.push(parent); - // parent's x = first child's x - parent.x = parent.children[0].x; - // parent's width = all children's width - parent.width = parent.children - .map((childNode) => childNode.width) - .reduce((sum, current) => sum + current, 0); - prevColParent = parent; - } - } - } - private getCompactColNodeWidth(colNode: Node) { const { theme, dataSet } = this.spreadsheet; const { bolderText: colCellTextStyle } = theme.colCell!; diff --git a/packages/s2-react/scripts/test-live.mjs b/packages/s2-react/scripts/test-live.mjs index 72d2d0a299..5ce0d08372 100644 --- a/packages/s2-react/scripts/test-live.mjs +++ b/packages/s2-react/scripts/test-live.mjs @@ -8,7 +8,7 @@ import ora from 'ora'; inquirer.registerPrompt('autocomplete', autoCompletePrompt); function run(path) { - const command = `cross-env DEBUG_MODE=1 npx jest ${path} --passWithNoTests`; + const command = `cross-env DEBUG_MODE=1 npx jest ${path} --passWithNoTests --detectOpenHandles`; const jestSpinner = ora(`[测试运行中]: ${command}`).start(); try { diff --git a/s2-site/docs/common/interaction.zh.md b/s2-site/docs/common/interaction.zh.md index bfba535e98..b07d72a0ec 100644 --- a/s2-site/docs/common/interaction.zh.md +++ b/s2-site/docs/common/interaction.zh.md @@ -13,7 +13,7 @@ order: 5 | selectedCellsSpotlight | 是否开启选中高亮聚光灯效果 | `boolean` | `false` | | | hoverHighlight | 鼠标悬停时高亮当前单元格,以及所对应的行头,列头 | `boolean` | `true` | | | hoverFocus | 鼠标悬停在当前单元格超过默认 800ms 后,保持当前高亮,显示 tooltip,悬停时间通过设置 `duration` 来控制 | `boolean \| {duration: number}` | `true` | | -| hiddenColumnFields | 用于配置默认隐藏的列,透视表需要配置列头唯一 id, 明细表配置列头 field 字段即可 | `string[]` | | | +| hiddenColumnFields | 用于配置默认隐藏的列,`透视表` 和`多列头明细表` 需要配置列头唯一 id, `单列头明细表` 配置列头 field 字段即可 (即:`s2DataConfig.fields.columns`). [了解更多](/manual/advanced/interaction/hide-columns) | `string[]` | | | | copy | 单元格复制配置 | [Copy](#copy) | | | | customInteractions | 自定义交互 [详情](/manual/advanced/interaction/custom) | [CustomInteraction[]](#custominteraction) | | | | scrollSpeedRatio | 用于控制滚动速率,分水平和垂直两个方向,默认为 1 | [ScrollSpeedRatio](#scrollspeedratio) | | | diff --git a/s2-site/docs/manual/advanced/interaction/hide-columns.zh.md b/s2-site/docs/manual/advanced/interaction/hide-columns.zh.md index bb41106c36..e7e7a06f09 100644 --- a/s2-site/docs/manual/advanced/interaction/hide-columns.zh.md +++ b/s2-site/docs/manual/advanced/interaction/hide-columns.zh.md @@ -54,7 +54,20 @@ const s2Options = { ![preview](https://gw.alipayobjects.com/zos/antfincdn/GHizMg2ok/f8d667c9-910a-40da-a6e3-74c238e7afa8.png) -对于 [自定义列头](/manual/advanced/custom/custom-header#21-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%88%97%E5%A4%B4) 的明细表,指定 `field` 字段。 +对于 [自定义列头](/manual/advanced/custom/custom-header#21-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%88%97%E5%A4%B4) 的明细表,需要指定单元格的对应 [节点 id](/api/basic-class/node)。 + +
+ 如何获取列头 ID? + +```ts | pure +const s2 = new TableSheet() + +await s2.render() + +console.log(s2.facet.getColNodes()) +``` + +
```ts const s2DataConfig = { @@ -81,14 +94,14 @@ const s2DataConfig = { const s2Options = { interaction: { - hiddenColumnFields: ['a-1-1'] + hiddenColumnFields: ['root[&]a-1[&]a-1-1'] } } ``` ### 2. 透视表 -透视表存在多列头,需要指定列头对应的 [节点 id](/api/basic-class/node), 如果是 [自定义列头](/manual/advanced/custom/custom-header#12-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%88%97%E5%A4%B4) , 那么和明细表相同,指定 `field` 字段即可,这里不再赘述。 +透视表存在多列头,需要指定列头对应的 [节点 id](/api/basic-class/node), [自定义列头](/manual/advanced/custom/custom-header#12-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%88%97%E5%A4%B4) 同理,这里不再赘述。
如何获取列头 ID? @@ -158,7 +171,7 @@ const s2Options = { [查看所有 API](/api/basic-class/interaction) ```ts -const s2 = new PivotSheet(...) +const s2 = new TableSheet(...) const hiddenColumnFields = ['province', 'type', 'price'] s2.interaction.hideColumns(hiddenColumnFields) @@ -171,7 +184,7 @@ s2.interaction.hideColumns(hiddenColumnFields) ```ts import { S2Event } from '@antv/s2' -const s2 = new PivotSheet(...); +const s2 = new TableSheet(...); s2.on(S2Event.COL_CELL_EXPANDED, (cell) => { console.log('列头展开', cell); diff --git a/s2-site/examples/interaction/advanced/demo/pivot-hide-columns.ts b/s2-site/examples/interaction/advanced/demo/pivot-hide-columns.ts index 502f131e14..3a925318e3 100644 --- a/s2-site/examples/interaction/advanced/demo/pivot-hide-columns.ts +++ b/s2-site/examples/interaction/advanced/demo/pivot-hide-columns.ts @@ -44,7 +44,7 @@ fetch( height: 480, interaction: { // 透视表默认隐藏需要指定唯一列头 id - // 可通过 `s2.facet.getColNodes()` 获取列头节点查看i d + // 可通过 `s2.facet.getColNodes()` 获取列头节点查看 id hiddenColumnFields: ['root[&]家具[&]沙发[&]number'], }, tooltip: { diff --git a/s2-site/examples/interaction/advanced/demo/table-hide-columns.ts b/s2-site/examples/interaction/advanced/demo/table-hide-columns.ts index 7a7333357a..636ab26332 100644 --- a/s2-site/examples/interaction/advanced/demo/table-hide-columns.ts +++ b/s2-site/examples/interaction/advanced/demo/table-hide-columns.ts @@ -79,6 +79,7 @@ fetch('https://assets.antv.antgroup.com/s2/basic-table-mode.json') height: 480, interaction: { // 默认隐藏 [省份] 和 [价格] + // 如果是自定义列头, 需要指定 `id`, 可通过 `s2.facet.getColNodes()` 获取列头节点查看 id hiddenColumnFields: ['province', 'price'], }, tooltip: {