diff --git a/packages/s2-core/__tests__/spreadsheet/hidden-columns-spec.ts b/packages/s2-core/__tests__/spreadsheet/hidden-columns-spec.ts index 8774ead68e..7dc973370c 100644 --- a/packages/s2-core/__tests__/spreadsheet/hidden-columns-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/hidden-columns-spec.ts @@ -152,6 +152,58 @@ describe('SpreadSheet Hidden Columns Tests', () => { expect(costDetail.hideColumnNodes).toHaveLength(1); expect(costDetail.hideColumnNodes[0].field).toEqual('cost'); }); + + // https://github.com/antvis/S2/issues/2495 + test('should reset latest hidden columns detail when hiddenColumnFields changed', () => { + const hiddenColumns = ['province', 'city']; + const sheet = new TableSheet(getContainer(), mockTableDataConfig, { + ...s2Options, + interaction: { + hiddenColumnFields: hiddenColumns, + }, + }); + sheet.render(); + + sheet.setOptions({ + interaction: { + hiddenColumnFields: ['city'], + }, + }); + + sheet.render(false); + + const hiddenColumnsDetail = sheet.store.get('hiddenColumnsDetail', []); + const [cityDetail] = hiddenColumnsDetail; + + expect(sheet.options.interaction.hiddenColumnFields).toEqual(['city']); + expect(hiddenColumnsDetail).toHaveLength(1); + expect(cityDetail.hideColumnNodes).toHaveLength(1); + expect(cityDetail.hideColumnNodes[0].field).toEqual('city'); + }); + + test('should clear hidden columns detail if hiddenColumnFields is empty', () => { + const hiddenColumns = ['province', 'city']; + const sheet = new TableSheet(getContainer(), mockTableDataConfig, { + ...s2Options, + interaction: { + hiddenColumnFields: hiddenColumns, + }, + }); + sheet.render(); + + sheet.setOptions({ + interaction: { + hiddenColumnFields: [], + }, + }); + + sheet.render(false); + + const hiddenColumnsDetail = sheet.store.get('hiddenColumnsDetail', []); + + expect(sheet.options.interaction.hiddenColumnFields).toBeEmpty(); + expect(hiddenColumnsDetail).toBeEmpty(); + }); }); describe('PivotSheet', () => { diff --git a/packages/s2-core/__tests__/unit/sheet-type/pivot-sheet-spec.ts b/packages/s2-core/__tests__/unit/sheet-type/pivot-sheet-spec.ts index 246d6fbdf6..6ed8370e28 100644 --- a/packages/s2-core/__tests__/unit/sheet-type/pivot-sheet-spec.ts +++ b/packages/s2-core/__tests__/unit/sheet-type/pivot-sheet-spec.ts @@ -657,7 +657,7 @@ describe('PivotSheet Tests', () => { test('should clear init column nodes', () => { s2.store.set('initColumnLeafNodes', [null, null]); - s2.clearColumnLeafNodes(); + s2.clearInitColumnLeafNodes(); expect(s2.store.get('initColumnLeafNodes')).toBeFalsy(); }); diff --git a/packages/s2-core/src/sheet-type/spread-sheet.ts b/packages/s2-core/src/sheet-type/spread-sheet.ts index 6eb4ef9699..c1acbd81dc 100644 --- a/packages/s2-core/src/sheet-type/spread-sheet.ts +++ b/packages/s2-core/src/sheet-type/spread-sheet.ts @@ -394,9 +394,20 @@ export abstract class SpreadSheet extends EE { this.initTooltip(); } + this.resetHiddenColumnsDetailInfoIfNeeded(); this.registerIcons(); } + /** + * 配置都是 merge 操作, 但是隐藏列配置比较特殊, 变更时, 应该是全量覆盖, 而不应该是合并 + * https://github.com/antvis/S2/issues/2495 + */ + private resetHiddenColumnsDetailInfoIfNeeded() { + if (!isEmpty(this.options.interaction?.hiddenColumnFields)) { + this.store.set('hiddenColumnsDetail', []); + } + } + public render(reloadData = true, options: S2RenderOptions = {}) { // 防止表格卸载后, 再次调用 render 函数的报错 if (!this.getCanvasElement()) { @@ -689,7 +700,14 @@ export abstract class SpreadSheet extends EE { return this.store.get('initColumnLeafNodes', []); } + /** + * @deprecated 已废弃, 请使用 clearInitColumnLeafNodes + */ public clearColumnLeafNodes() { + this.clearInitColumnLeafNodes(); + } + + public clearInitColumnLeafNodes() { this.store.set('initColumnLeafNodes', undefined); } diff --git a/packages/s2-react/src/hooks/useSpreadSheet.ts b/packages/s2-react/src/hooks/useSpreadSheet.ts index b56984901b..344b3ec9a2 100644 --- a/packages/s2-react/src/hooks/useSpreadSheet.ts +++ b/packages/s2-react/src/hooks/useSpreadSheet.ts @@ -1,7 +1,7 @@ import { PivotSheet, SpreadSheet, TableSheet } from '@antv/s2'; import type { S2DataConfig, S2Options, ThemeCfg } from '@antv/s2'; import { useUpdate, useUpdateEffect } from 'ahooks'; -import { identity } from 'lodash'; +import { identity, isEmpty } from 'lodash'; import React from 'react'; import type { SheetComponentOptions, @@ -94,7 +94,7 @@ export function useSpreadSheet(props: SheetComponentsProps) { prevDataCfg?.fields?.columns?.length !== dataCfg?.fields?.columns?.length ) { - s2Ref.current?.clearColumnLeafNodes(); + s2Ref.current?.clearInitColumnLeafNodes(); } reloadData = true; diff --git a/packages/s2-vue/src/hooks/useSheetUpdate.ts b/packages/s2-vue/src/hooks/useSheetUpdate.ts index f8ee791f22..94580a1c55 100644 --- a/packages/s2-vue/src/hooks/useSheetUpdate.ts +++ b/packages/s2-vue/src/hooks/useSheetUpdate.ts @@ -39,7 +39,7 @@ export const useSheetUpdate = ( prevDataCfg?.fields?.columns?.length !== dataCfg?.fields?.columns?.length ) { - s2Ref.value?.clearColumnLeafNodes(); + s2Ref.value?.clearInitColumnLeafNodes(); } updateFlag.rerender = true; updateFlag.reloadData = true; diff --git a/s2-site/docs/api/basic-class/spreadsheet.en.md b/s2-site/docs/api/basic-class/spreadsheet.en.md index 063bc7dd2c..64834d623d 100644 --- a/s2-site/docs/api/basic-class/spreadsheet.en.md +++ b/s2-site/docs/api/basic-class/spreadsheet.en.md @@ -68,7 +68,7 @@ s2.xx() | getTotalsConfig | Get Total Subtotal Configuration | (dimension: string) => [Total](/docs/api/general/S2Options#totals) | | | getInitColumnLeafNodes | Get the leaf node of the column header for the first rendering (for example: before hiding the column header) | () => [Node\[\]](/docs/api/basic-class/node/) | | | getCanvasElement | Get the `` HTML element corresponding to the table | () => [HTMLCanvasElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement) | | -| clearColumnLeafNodes | Clear the initial leaf nodes stored in the store | () => void | | +| clearInitColumnLeafNodes | Clear the initial leaf nodes stored in the store | () => void | | | updateSortMethodMap | Update the node sorting method map stored in the store, replace is whether to overwrite the last value | (nodeId: string, sortMethod: string, replace?: boolean) => void | | | getMenuDefaultSelectedKeys | Get the key value of the menu item selected in the tooltip | `(nodeId: string) => string[]` | | | measureText | Get the measurement information of the text in the canvas | (text: `string` , font: [TextTheme](/docs/api/general/S2Theme#texttheme) ) => [TextMetrics](https://developer.mozilla.org/zh-CN/docs/Web/API/TextMetrics) \| `null` | | diff --git a/s2-site/docs/api/basic-class/spreadsheet.zh.md b/s2-site/docs/api/basic-class/spreadsheet.zh.md index 37d949e8c1..187d809a8f 100644 --- a/s2-site/docs/api/basic-class/spreadsheet.zh.md +++ b/s2-site/docs/api/basic-class/spreadsheet.zh.md @@ -49,8 +49,8 @@ s2.isPivotMode() | hideTooltip | 隐藏 tooltip | `() => void` | | | destroyTooltip | 销毁 tooltip | `() => void` | | | registerIcons | 注册 自定义 svg 图标 (根据 `options.customSVGIcons`) | `() => void` | | -| setDataCfg | 更新数据配置 | `(dataCfg: T extends true ?` [`S2DataConfig`](/docs/api/general/S2DataConfig) `: Partial<`[`S2DataConfig`](/docs/api/general/S2DataConfig)`>, reset?: T) => void` | `reset` 参数需在 `@antv/s2-v1.34.0`版本使用 | -| setOptions | 更新表格配置 | (options: [S2Options](/docs/api/general/S2Options), reset?: boolean) => void | `reset` 参数需在 `@antv/s2-v1.34.0`版本使用 | +| setDataCfg | 更新数据配置 | `(dataCfg: T extends true ?` [`S2DataConfig`](/docs/api/general/S2DataConfig) `: Partial<`[`S2DataConfig`](/docs/api/general/S2DataConfig)`>, reset?: T) => void` | `reset` 参数需在 `@antv/s2@^1.34.0`版本使用 | +| setOptions | 更新表格配置 | (options: [S2Options](/docs/api/general/S2Options), reset?: boolean) => void | `reset` 参数需在 `@antv/s2@^1.34.0`版本使用 | | render | 重新渲染表格,如果 `reloadData` = true, 则会重新计算数据,`reBuildDataSet` = true, 重新构建数据集,`reBuildHiddenColumnsDetail` = true 重新构建隐藏列信息 | `(reloadData?: boolean, { reBuildDataSet?: boolean; reBuildHiddenColumnsDetail?: boolean }) => void` | | | destroy | 销毁表格 | `() => void` | | | setThemeCfg | 更新主题配置 (含主题 schema, 色板,主题名) | (themeCfg: [ThemeCfg](/docs/api/general/S2Theme/#themecfg)) => void | | @@ -69,7 +69,8 @@ s2.isPivotMode() | getTotalsConfig | 获取总计小计配置 | (dimension: string) => [Total](/docs/api/general/S2Options#totals) | | | getInitColumnLeafNodes | 获取初次渲染的列头叶子节点 (比如:隐藏列头前) | () => [Node[]](/docs/api/basic-class/node/) | | | getCanvasElement | 获取表格对应的 `` HTML 元素 | () => [HTMLCanvasElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement) | | -| clearColumnLeafNodes | 清空存储在 store 中的初始叶子节点 | () => void | | +| clearColumnLeafNodes | 清空存储在 store 中的初始叶子节点 (已废弃,请使用 `clearInitColumnLeafNodes` ) | () => void | | +| clearInitColumnLeafNodes | 清空存储在 store 中的初始叶子节点 | () => void | `@antv/s2@^1.54.3` | | updateSortMethodMap | 更新存储在 store 中的节点排序方式 map, replace 为是否覆盖上一次的值 | (nodeId: string, sortMethod: string, replace?: boolean) => void | | | getMenuDefaultSelectedKeys | 获取 tooltip 中选中的菜单项 key 值 | `(nodeId: string) => string[]` | | | measureText | 获取文本在画布中的测量信息 | (text: `string`, font: [TextTheme](/docs/api/general/S2Theme#texttheme)) => [TextMetrics](https://developer.mozilla.org/zh-CN/docs/Web/API/TextMetrics) \| `null` | | diff --git a/s2-site/examples/analysis/sort/demo/table-sort.tsx b/s2-site/examples/analysis/sort/demo/table-sort.tsx index 7313e461d7..44404870ca 100644 --- a/s2-site/examples/analysis/sort/demo/table-sort.tsx +++ b/s2-site/examples/analysis/sort/demo/table-sort.tsx @@ -110,7 +110,7 @@ fetch('https://assets.antv.antgroup.com/s2/basic-table-mode.json') sortFieldId: 'price', sortMethod: 'DESC', query: { - city: '浙江', + province: '浙江', }, }, ], 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 82b5baa7e1..3708b6a024 100644 --- a/s2-site/examples/interaction/advanced/demo/pivot-hide-columns.ts +++ b/s2-site/examples/interaction/advanced/demo/pivot-hide-columns.ts @@ -1,5 +1,33 @@ import { PivotSheet, S2Event } from '@antv/s2'; +function hideSelectedColumns(s2) { + // 兼容多选 + const selectedColumnNodes = s2.interaction + .getActiveCells() + .map((cell) => cell.getMeta()); + + const selectedColumnFields = selectedColumnNodes.map((node) => node.id); + s2.interaction.hideColumns(selectedColumnFields, true); +} + +function getTooltipContent(cell, options) { + const { spreadsheet, isLeaf } = cell.getMeta(); + + if (!isLeaf || !spreadsheet.options.tooltip.operation.hiddenColumns) { + return null; + } + + const button = document.createElement('button'); + button.type = 'button'; + button.innerHTML = '隐藏'; + button.className = 'ant-btn'; + button.addEventListener('click', () => { + hideSelectedColumns(spreadsheet); + }); + + return button; +} + fetch( 'https://gw.alipayobjects.com/os/bmw-prod/2a5dbbc8-d0a7-4d02-b7c9-34f6ca63cff6.json', ) @@ -21,6 +49,7 @@ fetch( // 开启手动隐藏, 叶子节点有效 hiddenColumns: true, }, + content: getTooltipContent, }, }; const s2 = new PivotSheet(container, dataCfg, s2Options); 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 08f3ad06c3..8e65be2b8a 100644 --- a/s2-site/examples/interaction/advanced/demo/table-hide-columns.ts +++ b/s2-site/examples/interaction/advanced/demo/table-hide-columns.ts @@ -1,8 +1,34 @@ import { TableSheet, S2Event } from '@antv/s2'; -fetch( - 'https://assets.antv.antgroup.com/s2/basic-table-mode.json', -) +function hideSelectedColumns(s2) { + // 兼容多选 + const selectedColumnNodes = s2.interaction + .getActiveCells() + .map((cell) => cell.getMeta()); + + const selectedColumnFields = selectedColumnNodes.map((node) => node.field); + s2.interaction.hideColumns(selectedColumnFields, true); +} + +function getTooltipContent(cell, options) { + const { spreadsheet, isLeaf } = cell.getMeta(); + + if (!isLeaf || !spreadsheet.options.tooltip.operation.hiddenColumns) { + return null; + } + + const button = document.createElement('button'); + button.type = 'button'; + button.innerHTML = '隐藏'; + button.className = 'ant-btn'; + button.addEventListener('click', () => { + hideSelectedColumns(spreadsheet); + }); + + return button; +} + +fetch('https://assets.antv.antgroup.com/s2/basic-table-mode.json') .then((res) => res.json()) .then((data) => { const container = document.getElementById('container'); @@ -48,13 +74,16 @@ fetch( // 开启手动隐藏 hiddenColumns: true, }, + content: getTooltipContent, }, }; + const s2 = new TableSheet(container, s2DataConfig, s2Options); s2.on(S2Event.LAYOUT_COLS_EXPANDED, (cell) => { console.log('列头展开', cell); }); + s2.on( S2Event.LAYOUT_COLS_HIDDEN, (currentHiddenColumnsInfo, hiddenColumnsDetail) => { diff --git a/s2-site/examples/react-component/switcher/demo/pure-switcher.tsx b/s2-site/examples/react-component/switcher/demo/pure-switcher.tsx index 6811f5283d..5f339685b6 100644 --- a/s2-site/examples/react-component/switcher/demo/pure-switcher.tsx +++ b/s2-site/examples/react-component/switcher/demo/pure-switcher.tsx @@ -8,11 +8,14 @@ const switcherFields = { allowEmpty: false, }, columns: { - items: [{ id: 'type' }], + items: [{ id: 'type', displayName: '类型 (type)' }], }, values: { selectable: true, - items: [{ id: 'price' }, { id: 'cost' }], + items: [ + { id: 'price', checked: true }, + { id: 'cost', checked: false }, + ], }, }; diff --git a/s2-site/examples/react-component/switcher/demo/table.tsx b/s2-site/examples/react-component/switcher/demo/table.tsx index a1e8e1f729..d9c0bc74f0 100644 --- a/s2-site/examples/react-component/switcher/demo/table.tsx +++ b/s2-site/examples/react-component/switcher/demo/table.tsx @@ -23,11 +23,11 @@ fetch( columns: { selectable: true, items: [ - { id: 'province' }, - { id: 'city' }, - { id: 'type' }, - { id: 'sub_type' }, - { id: 'number' }, + { id: 'province', displayName: '省份 (province)' }, + { id: 'city', displayName: '城市 (city)' }, + { id: 'type', displayName: '类别 (type)' }, + { id: 'sub_type', displayName: '子类别 (sub_type)' }, + { id: 'number', displayName: '数量 (number)' }, ], }, };