diff --git a/packages/s2-core/__tests__/spreadsheet/scroll-spec.ts b/packages/s2-core/__tests__/spreadsheet/scroll-spec.ts index a40ece9723..ac0fc899b6 100644 --- a/packages/s2-core/__tests__/spreadsheet/scroll-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/scroll-spec.ts @@ -1,6 +1,7 @@ /* eslint-disable jest/no-conditional-expect */ import * as mockDataConfig from 'tests/data/simple-data.json'; import { createMockCellInfo, getContainer, sleep } from 'tests/util/helpers'; +import { ScrollType } from '../../src/ui/scrollbar'; import type { CellScrollPosition } from './../../src/common/interface/scroll'; import { PivotSheet, SpreadSheet } from '@/sheet-type'; import type { @@ -72,7 +73,7 @@ describe('Scroll Tests', () => { test('should hide tooltip when start scroll', () => { const hideTooltipSpy = jest .spyOn(s2, 'hideTooltip') - .mockImplementation(() => {}); + .mockImplementationOnce(() => {}); canvas.dispatchEvent(new WheelEvent('wheel', { deltaX: 20, deltaY: 0 })); expect(hideTooltipSpy).toHaveBeenCalledTimes(1); @@ -81,12 +82,35 @@ describe('Scroll Tests', () => { test('should clear hover timer when start scroll', () => { const clearHoverTimerSpy = jest .spyOn(s2.interaction, 'clearHoverTimer') - .mockImplementation(() => {}); + .mockImplementationOnce(() => {}); canvas.dispatchEvent(new WheelEvent('wheel', { deltaX: 20, deltaY: 0 })); expect(clearHoverTimerSpy).toHaveBeenCalledTimes(1); }); + test('should clear hover timer and hide tooltip when drag scroll bar', () => { + const hideTooltipSpy = jest + .spyOn(s2, 'hideTooltip') + .mockImplementationOnce(() => {}); + + const clearHoverTimerSpy = jest + .spyOn(s2.interaction, 'clearHoverTimer') + .mockImplementationOnce(() => {}); + + s2.facet.hScrollBar.emit(ScrollType.ScrollChange, { + offset: 10, + updateThumbOffset: 10, + }); + + s2.facet.vScrollBar.emit(ScrollType.ScrollChange, { + offset: 10, + updateThumbOffset: 10, + }); + + expect(clearHoverTimerSpy).toHaveBeenCalledTimes(2); + expect(hideTooltipSpy).toHaveBeenCalledTimes(2); + }); + test('should not trigger scroll if not scroll over the viewport', () => { const expectScroll = getScrollExpect(); diff --git a/packages/s2-core/__tests__/unit/facet/pivot-facet-spec.ts b/packages/s2-core/__tests__/unit/facet/pivot-facet-spec.ts index deed6997f7..d55757e813 100644 --- a/packages/s2-core/__tests__/unit/facet/pivot-facet-spec.ts +++ b/packages/s2-core/__tests__/unit/facet/pivot-facet-spec.ts @@ -63,6 +63,10 @@ jest.mock('@/sheet-type', () => { getFreezeCornerDiffWidth: jest.fn(), }, getCanvasElement: () => container.get('el'), + hideTooltip: jest.fn(), + interaction: { + clearHoverTimer: jest.fn(), + }, }; }), }; @@ -184,10 +188,10 @@ describe('Pivot Mode Facet Test', () => { describe('should get correct result when tree mode', () => { s2.isHierarchyTreeType = jest.fn().mockReturnValue(true); - const ds = new MockPivotDataSet(s2); + const mockDataSet = new MockPivotDataSet(s2); const treeFacet = new PivotFacet({ spreadsheet: s2, - dataSet: ds, + dataSet: mockDataSet, ...assembleDataCfg().fields, ...assembleOptions(), ...DEFAULT_STYLE, @@ -280,4 +284,34 @@ describe('Pivot Mode Facet Test', () => { }); }, ); + + // https://github.com/antvis/S2/pull/1591 + test.each([ + { width: 200, useFunc: false }, + { width: 300, useFunc: true }, + ])( + 'should render custom column leaf node width by %o', + ({ width, useFunc }) => { + const mockDataSet = new MockPivotDataSet(s2); + const widthFn = jest.fn(() => width); + const customWidthFacet = new PivotFacet({ + spreadsheet: s2, + dataSet: mockDataSet, + ...assembleDataCfg().fields, + ...assembleOptions(), + colCfg: { + width: useFunc ? widthFn : width, + }, + }); + + customWidthFacet.layoutResult.colLeafNodes.forEach((node) => { + expect(node.width).toStrictEqual(width); + }); + + if (useFunc) { + // eslint-disable-next-line jest/no-conditional-expect + expect(widthFn).toHaveReturnedTimes(4); + } + }, + ); }); diff --git a/packages/s2-core/__tests__/unit/facet/table-facet-spec.ts b/packages/s2-core/__tests__/unit/facet/table-facet-spec.ts index 727746c16a..cd1c73a68e 100644 --- a/packages/s2-core/__tests__/unit/facet/table-facet-spec.ts +++ b/packages/s2-core/__tests__/unit/facet/table-facet-spec.ts @@ -45,6 +45,10 @@ jest.mock('@/sheet-type', () => { getColumnLeafNodes: jest.fn().mockReturnValue([]), isHierarchyTreeType: jest.fn(), getCanvasElement: () => container.get('el'), + hideTooltip: jest.fn(), + interaction: { + clearHoverTimer: jest.fn(), + }, }; }), }; @@ -457,10 +461,10 @@ describe('Table Mode Facet Test With Zero Height', () => { }); describe('Table Mode Facet With Frozen layoutCoordinate Test', () => { - const ss: SpreadSheet = new MockSpreadSheet(); - const dataSet: TableDataSet = new MockTableDataSet(ss); + const s2: SpreadSheet = new MockSpreadSheet(); + const dataSet: TableDataSet = new MockTableDataSet(s2); const facet: TableFacet = new TableFacet({ - spreadsheet: ss, + spreadsheet: s2, dataSet, ...assembleDataCfg().fields, ...assembleOptions({ @@ -482,3 +486,41 @@ describe('Table Mode Facet With Frozen layoutCoordinate Test', () => { }); }); }); + +describe('Custom Column Width Tests', () => { + // https://github.com/antvis/S2/pull/1591 + test.each([ + { width: 200, useFunc: false }, + { width: 300, useFunc: true }, + ])( + 'should render custom column leaf node width by %o', + ({ width, useFunc }) => { + const s2: SpreadSheet = new MockSpreadSheet(); + const dataSet: TableDataSet = new MockTableDataSet(s2); + const widthFn = jest.fn(() => width); + const customWidthFacet = new TableFacet({ + spreadsheet: s2, + dataSet, + ...assembleDataCfg().fields, + ...assembleOptions(), + ...DEFAULT_STYLE, + colCfg: { + width: useFunc ? widthFn : width, + }, + }); + + customWidthFacet.layoutResult.colNodes.forEach((node) => { + expect(node.width).toStrictEqual(width); + }); + + customWidthFacet.layoutResult.colLeafNodes.forEach((node) => { + expect(node.width).toStrictEqual(width); + }); + + if (useFunc) { + // eslint-disable-next-line jest/no-conditional-expect + expect(widthFn).toHaveReturnedTimes(2); + } + }, + ); +}); diff --git a/packages/s2-core/src/common/interface/basic.ts b/packages/s2-core/src/common/interface/basic.ts index eb79e6350e..ce08fdbdcb 100644 --- a/packages/s2-core/src/common/interface/basic.ts +++ b/packages/s2-core/src/common/interface/basic.ts @@ -283,6 +283,8 @@ export type HierarchyCallback = ( node: Node, ) => HierarchyResult; +export type CellCustomWidth = number | ((node: Node) => number); + export interface CellCfg { width?: number; height?: number; @@ -297,7 +299,7 @@ export interface CellCfg { export interface RowCfg { // row's cell width - width?: number; + width?: CellCustomWidth; // specific some row field's width widthByField?: Record; heightByField?: Record; @@ -306,6 +308,8 @@ export interface RowCfg { } export interface ColCfg { + // custom column width + width?: CellCustomWidth; // columns height(for normal state) height?: number; // specific some col field's width diff --git a/packages/s2-core/src/facet/base-facet.ts b/packages/s2-core/src/facet/base-facet.ts index 1a058bb97b..c43faf2124 100644 --- a/packages/s2-core/src/facet/base-facet.ts +++ b/packages/s2-core/src/facet/base-facet.ts @@ -4,7 +4,17 @@ import { Group } from '@antv/g-canvas'; import { type GestureEvent, Wheel } from '@antv/g-gesture'; import { interpolateArray } from 'd3-interpolate'; import { timer, type Timer } from 'd3-timer'; -import { clamp, debounce, each, find, isUndefined, last, reduce } from 'lodash'; +import { + clamp, + debounce, + each, + find, + get, + isFunction, + isUndefined, + last, + reduce, +} from 'lodash'; import { DataCell } from '../cell'; import { InterceptType, @@ -22,6 +32,7 @@ import { DEBUG_VIEW_RENDER, } from '../common/debug'; import type { + CellCustomWidth, FrameConfig, GridInfo, LayoutResult, @@ -134,6 +145,15 @@ export abstract class BaseFacet { this.init(); } + protected getCellCustomWidth(node: Node, width: CellCustomWidth) { + return isFunction(width) ? width?.(node) : width; + } + + protected getCellDraggedWidth(node: Node): number { + const { colCfg } = this.cfg; + return get(colCfg?.widthByFieldValue, `${node.value}`, node.width); + } + hideScrollBar = () => { this.hRowScrollBar?.hide(); this.hScrollBar?.hide(); @@ -1218,6 +1238,9 @@ export abstract class BaseFacet { this.panelBBox.viewportHeight, ); + this.spreadsheet.hideTooltip(); + this.spreadsheet.interaction.clearHoverTimer(); + this.realCellRender(scrollX, scrollY); this.updatePanelScrollGroup(); this.translateRelatedGroups(scrollX, scrollY, hRowScrollX); diff --git a/packages/s2-core/src/facet/pivot-facet.ts b/packages/s2-core/src/facet/pivot-facet.ts index 480a193747..bd934c55a3 100644 --- a/packages/s2-core/src/facet/pivot-facet.ts +++ b/packages/s2-core/src/facet/pivot-facet.ts @@ -4,6 +4,8 @@ import { get, isArray, isEmpty, + isFunction, + isNil, keys, last, maxBy, @@ -11,7 +13,14 @@ import { reduce, size, } from 'lodash'; -import { LAYOUT_SAMPLE_COUNT, type IconTheme, type MultiData } from '../common'; +import { + LAYOUT_SAMPLE_COUNT, + type CellCustomWidth, + type ColCfg, + type IconTheme, + type MultiData, + type RowCfg, +} from '../common'; import { EXTRA_FIELD, LayoutWidthTypes, VALUE_FIELD } from '../common/constant'; import { CellTypes } from '../common/constant/interaction'; import { DebuggerUtil } from '../common/debug'; @@ -245,16 +254,21 @@ export class PivotFacet extends BaseFacet { rowHeaderWidth: number, ): number { const { colCfg, dataSet, filterDisplayDataItem } = this.cfg; - // current.width = get(colCfg, `widthByFieldValue.${current.value}`, current.width); - const userDragWidth = get( - get(colCfg, 'widthByFieldValue'), - `${col.value}`, - col.width, - ); - if (userDragWidth) { - return userDragWidth; + + const cellDraggedWidth = this.getCellDraggedWidth(col); + + // 1. 拖拽后的宽度优先级最高 + if (cellDraggedWidth) { + return cellDraggedWidth; + } + + // 2. 其次是自定义, 返回 null 则使用默认宽度 + const cellCustomWidth = this.getCellCustomWidth(col, colCfg?.width); + if (!isNil(cellCustomWidth)) { + return cellCustomWidth; } + // 3. 紧凑布局 if (this.spreadsheet.getLayoutWidthType() === LayoutWidthTypes.Compact) { const { bolderText: colCellTextStyle, @@ -326,10 +340,13 @@ export class PivotFacet extends BaseFacet { appendedWidth ); } - // adaptive + + // 4. 自适应 adaptive + // 4.1 树状自定义 if (this.spreadsheet.isHierarchyTreeType()) { return this.getAdaptTreeColWidth(col, colLeafNodes, rowLeafNodes); } + // 4.2 网格自定义 return this.getAdaptGridColWidth(colLeafNodes, rowHeaderWidth); } @@ -598,14 +615,15 @@ export class PivotFacet extends BaseFacet { private calculateGridRowNodesWidth(node: Node, colLeafNodes: Node[]): number { const { rowCfg, spreadsheet } = this.cfg; - const userDragWidth = get(rowCfg, `widthByField.${node.key}`); - const userCustomWidth = get(rowCfg, 'width'); - if (userDragWidth) { - return userDragWidth; + const cellDraggedWidth = get(rowCfg, `widthByField.${node.key}`); + + if (cellDraggedWidth) { + return cellDraggedWidth; } - if (userCustomWidth) { - return userCustomWidth; + const cellCustomWidth = this.getCellCustomWidth(node, rowCfg?.width); + if (!isNil(cellCustomWidth)) { + return cellCustomWidth; } if (spreadsheet.getLayoutWidthType() !== LayoutWidthTypes.Adaptive) { @@ -709,12 +727,19 @@ export class PivotFacet extends BaseFacet { */ private getTreeRowHeaderWidth(): number { const { rows, dataSet, rowCfg, treeRowsWidth } = this.cfg; - // user drag happened + + // 1. 用户拖拽或手动指定的行头宽度优先级最高 if (rowCfg?.treeRowsWidth) { return rowCfg?.treeRowsWidth; } - // + province/city/level + // 2. 其次是自定义 + const customRowWidth = this.getCellCustomWidth(null, rowCfg?.width); + if (customRowWidth) { + return customRowWidth; + } + + // 3. 然后是计算 (+ icon province/city/level) const treeHeaderLabel = rows .map((key: string): string => dataSet.getFieldName(key)) .join('/'); @@ -758,7 +783,7 @@ export class PivotFacet extends BaseFacet { } = spreadsheet.theme.cornerCell; const { field, isLeaf } = node; - // calc rowNodeWitdh + // calc rowNode width const rowIconWidth = this.getExpectedCellIconWidth( CellTypes.ROW_CELL, !spreadsheet.isValueInCols() && diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index 31ba3486cf..d1b2f9bec6 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -1,5 +1,5 @@ import type { Group, IElement, IGroup } from '@antv/g-canvas'; -import { get, isBoolean, last, maxBy, set } from 'lodash'; +import { get, isBoolean, isNil, last, maxBy, set, values } from 'lodash'; import { TableSeriesCell } from '../cell'; import { FRONT_GROUND_GROUP_COL_FROZEN_Z_INDEX, @@ -271,16 +271,16 @@ export class TableFacet extends BaseFacet { const seriesNumberWidth = this.getSeriesNumberWidth(); const colHeaderColSize = colLeafNodes.length - (showSeriesNumber ? 1 : 0); const canvasW = this.getCanvasHW().width - seriesNumberWidth; - return Math.max(cellCfg.width, canvasW / Math.max(1, colHeaderColSize)); + return Math.max(cellCfg?.width, canvasW / Math.max(1, colHeaderColSize)); } - return cellCfg.width; + return cellCfg?.width; } - private getColNodeHeight(col: Node) { + private getColNodeHeight() { const { colCfg } = this.cfg; // 明细表所有列节点高度保持一致 - const userDragHeight = Object.values(get(colCfg, `heightByField`))[0]; - return userDragHeight || colCfg.height; + const userDragHeight = values(colCfg?.heightByField)[0]; + return userDragHeight || colCfg?.height; } private calculateColNodesCoordinate( @@ -290,7 +290,7 @@ export class TableFacet extends BaseFacet { let preLeafNode = Node.blankNode(); const allNodes = colsHierarchy.getNodes(); for (const levelSample of colsHierarchy.sampleNodesForAllLevels) { - levelSample.height = this.getColNodeHeight(levelSample); + levelSample.height = this.getColNodeHeight(); colsHierarchy.height += levelSample.height; } const { frozenTrailingColCount } = getValidFrozenOptions( @@ -314,7 +314,7 @@ export class TableFacet extends BaseFacet { preLeafNode = currentNode; currentNode.y = 0; - currentNode.height = this.getColNodeHeight(currentNode); + currentNode.height = this.getColNodeHeight(); nodes.push(currentNode); @@ -353,61 +353,65 @@ export class TableFacet extends BaseFacet { const { colCfg, dataSet, spreadsheet } = this.cfg; const layoutWidthType = this.spreadsheet.getLayoutWidthType(); - const userDragWidth = get( - get(colCfg, 'widthByFieldValue'), - `${col.value}`, - col.width, - ); + const cellDraggedWidth = this.getCellDraggedWidth(col); + + // 1. 拖拽后的宽度优先级最高 + if (cellDraggedWidth) { + return cellDraggedWidth; + } + + // 2. 其次是自定义, 返回 null 则使用默认宽度 + const cellCustomWidth = this.getCellCustomWidth(col, colCfg?.width); + if (!isNil(cellCustomWidth)) { + return cellCustomWidth; + } + let colWidth: number; - if (userDragWidth) { - colWidth = userDragWidth; - } else { - if (layoutWidthType === LayoutWidthTypes.Compact) { - const datas = dataSet.getDisplayDataSet(); - const colLabel = col.label; - - const allLabels = - datas?.map((data) => `${data[col.key]}`)?.slice(0, 50) || []; // 采样取了前50 - allLabels.push(colLabel); - const maxLabel = maxBy(allLabels, (label) => - measureTextWidthRoughly(label), - ); + if (layoutWidthType === LayoutWidthTypes.Compact) { + const datas = dataSet.getDisplayDataSet(); + const colLabel = col.label; + + const allLabels = + datas?.map((data) => `${data[col.key]}`)?.slice(0, 50) || []; // 采样取了前50 + allLabels.push(colLabel); + const maxLabel = maxBy(allLabels, (label) => + measureTextWidthRoughly(label), + ); - const { bolderText: colCellTextStyle } = spreadsheet.theme.colCell; - const { text: dataCellTextStyle, cell: cellStyle } = - spreadsheet.theme.dataCell; + const { bolderText: colCellTextStyle } = spreadsheet.theme.colCell; + const { text: dataCellTextStyle, cell: cellStyle } = + spreadsheet.theme.dataCell; - DebuggerUtil.getInstance().logger( - 'Max Label In Col:', - col.field, - maxLabel, - ); + DebuggerUtil.getInstance().logger( + 'Max Label In Col:', + col.field, + maxLabel, + ); - // 最长的 Label 如果是列名,按列名的标准计算宽度 - if (colLabel === maxLabel) { - colWidth = - measureTextWidth(maxLabel, colCellTextStyle) + - getOccupiedWidthForTableCol( - this.spreadsheet, - col, - spreadsheet.theme.colCell, - ); - } else { - // 额外添加一像素余量,防止 maxLabel 有多个同样长度情况下,一些 label 不能展示完全 - const EXTRA_PIXEL = 1; - colWidth = - measureTextWidth(maxLabel, dataCellTextStyle) + - cellStyle.padding.left + - cellStyle.padding.right + - EXTRA_PIXEL; - } + // 最长的 Label 如果是列名,按列名的标准计算宽度 + if (colLabel === maxLabel) { + colWidth = + measureTextWidth(maxLabel, colCellTextStyle) + + getOccupiedWidthForTableCol( + this.spreadsheet, + col, + spreadsheet.theme.colCell, + ); } else { - colWidth = adaptiveColWidth; + // 额外添加一像素余量,防止 maxLabel 有多个同样长度情况下,一些 label 不能展示完全 + const EXTRA_PIXEL = 1; + colWidth = + measureTextWidth(maxLabel, dataCellTextStyle) + + cellStyle.padding.left + + cellStyle.padding.right + + EXTRA_PIXEL; } + } else { + colWidth = adaptiveColWidth; + } - if (col.field === SERIES_NUMBER_FIELD) { - colWidth = this.getSeriesNumberWidth(); - } + if (col.field === SERIES_NUMBER_FIELD) { + colWidth = this.getSeriesNumberWidth(); } return colWidth; @@ -416,7 +420,7 @@ export class TableFacet extends BaseFacet { protected getDefaultCellHeight() { const { cellCfg } = this.cfg; - return cellCfg.height; + return cellCfg?.height; } public getCellHeight(index: number) { diff --git a/s2-site/docs/common/style.zh.md b/s2-site/docs/common/style.zh.md index 8d222a6c84..61b01abe17 100644 --- a/s2-site/docs/common/style.zh.md +++ b/s2-site/docs/common/style.zh.md @@ -9,11 +9,11 @@ object **必选**,_default:null_ 功能描述:样式设置 | 参数 | 类型 | 必选 | 默认值 | 功能描述 | | --- | --- | :-: | --- | --- | --- | -|layoutWidthType | `adaptive` \| `colAdaptive` \| `compact` | | | 单元格宽度布局类型
`adaptive` : 行列等宽,均分整个 `Canvas` 画布宽度
`colAdaptive`:列等宽,行头紧凑布局,列等分画布宽度减去行头宽度的剩余宽度
`compact`:行列紧凑布局,指标维度少的时候无法布满整个画布 | +| layoutWidthType | `adaptive` \| `colAdaptive` \| `compact` | | | 单元格宽度布局类型
`adaptive` : 行列等宽,均分整个 `Canvas` 画布宽度
`colAdaptive`:列等宽,行头紧凑布局,列等分画布宽度减去行头宽度的剩余宽度
`compact`:行列紧凑布局,指标维度少的时候无法布满整个画布 | | showTreeLeafNodeAlignDot | `boolean` | | false | 树状模式下叶子节点是否显示层级占位点 | -| treeRowsWidth | `number` | | 120 | 树状模式行单元格宽度 | +| treeRowsWidth | `number` | | 120 | 树状模式行单元格宽度 (优先级大于 `rowCfg.width`) | | hierarchyCollapse | `boolean` | | `false` | 在树状结构模式下行头是否默认展开。 | -| collapsedRows | `Record` | | | 树状模式下行头自定义折叠、收起状态(透视表使用)。
key 值的生成需遵守指定的规则:'root[&]行头维度值'。 [查看 demo](/zh/examples/basic/pivot#tree) | +| collapsedRows | `Record` | | | 树状模式下行头自定义折叠、收起状态(透视表使用)。
key 值的生成需遵守指定的规则:'root[&] 行头维度值'。 [查看 demo](/zh/examples/basic/pivot#tree) | | cellCfg | [CellCfg](#cellcfg) | | | 单元格配置 | | colCfg | [ColCfg](#colcfg) | | | 列样式配置 | | rowCfg | [RowCfg](#rowcfg) | | | 行样式配置 | @@ -21,12 +21,13 @@ object **必选**,_default:null_ 功能描述:样式设置 ## CellCfg -object **必选**,_default:null_ 功能描述:单元格配置 +object **必选**,_default:null_ 功能描述:数值单元格配置 | 参数 | 说明 | 类型 | 默认值 | 必选 | | ------- | ------------ | ------ | ------ | ---- | | width | 单元格宽度 | `number` | 96 | - | | height | 单元格高度 | `number` | 30 | - | +| valuesCfg | 单元格配置 | `{ originalValueField?: string, widthPercent?: number[] }` | | - | ## ColCfg @@ -34,8 +35,10 @@ object **必选**,_default:null_ 功能描述: 列样式配置 | 参数 | 说明 | 类型 | 默认值 | 必选 | | --- | --- | --- | --- | :-: | -| height | 单元格高度(普通状态) | `number` | 30 | | -| widthByFieldValue | 根据度量值设置宽度(拖拽或者预设宽度场景), `fieldValue` 对应 `s2DataConfig.fields.columns` 中的列头 | `Record` | - | | +| width | 单元格宽度,可根据当前列头节点动态设置宽度 (叶子节点有效) | `number | (colNode: Node) => number` | | | +| height | 单元格高度 | `number` | 30 | | +| widthByFieldValue | 根据度量值设置宽度(拖拽或者预设宽度场景), `fieldValue` 对应 `s2DataConfig.fields.columns` 中的列头数值 | `Record` | - | | +| heightByField | 根据度量值设置高度(拖拽或者预设高度场景), `field` 对应 列头 id, [查看详情](/zh/docs/manual/advanced/custom/cell-size#%E8%B0%83%E6%95%B4%E8%A1%8C%E5%A4%B4%E5%8D%95%E5%85%83%E6%A0%BC%E5%AE%BD%E9%AB%98) | `Record` | - | | | hideMeasureColumn | 默认数值挂列头,会同时显示列头和数值,隐藏数值列,使其更美观。 | `boolean` | false | | ## RowCfg @@ -44,5 +47,7 @@ object **必选**,_default:null_ 功能描述: 行样式配置 | 参数 | 说明 | 类型 | 默认值 | 必选 | | --- | --- | --- | --- | :-: | -| width | 行单元格宽度 | `number` | 96 | | -| heightByField | 可以单独设置每行的高度。`field` 是行的 id, [查看详情](/zh/docs/manual/advanced/custom/cell-size#%E8%B0%83%E6%95%B4%E8%A1%8C%E5%A4%B4%E5%8D%95%E5%85%83%E6%A0%BC%E5%AE%BD%E9%AB%98) | `Record` | - | | +| width | 行单元格宽度,可根据当前行头节点动态设置宽度,如果是树状结构,请使用 `styles.treeRowsWidth` | `number | (rowNode: Node) => number` | 96 | | +| treeRowsWidth | 树状结构下,行单元格宽度 | `number` | 120 | | +| withByField | 根据 `field` 设置每行的宽度。`field` 是行的 id, [查看详情](/zh/docs/manual/advanced/custom/cell-size#%E8%B0%83%E6%95%B4%E8%A1%8C%E5%A4%B4%E5%8D%95%E5%85%83%E6%A0%BC%E5%AE%BD%E9%AB%98) | `Record` | - | | +| heightByField | 根据 `field` 设置每行的高度。`field` 是行的 id, [查看详情](/zh/docs/manual/advanced/custom/cell-size#%E8%B0%83%E6%95%B4%E8%A1%8C%E5%A4%B4%E5%8D%95%E5%85%83%E6%A0%BC%E5%AE%BD%E9%AB%98) | `Record` | - | | diff --git a/s2-site/docs/manual/advanced/custom/cell-size.zh.md b/s2-site/docs/manual/advanced/custom/cell-size.zh.md index f418db6fc0..4a181a0f87 100644 --- a/s2-site/docs/manual/advanced/custom/cell-size.zh.md +++ b/s2-site/docs/manual/advanced/custom/cell-size.zh.md @@ -26,6 +26,8 @@ const s2Options = { ## 调整树状模式下行头宽度 +> 优先级大于 `style.rowCfg.width` + ```ts const s2Options = { hierarchyType: 'tree', @@ -56,6 +58,8 @@ const s2Options = { ## 调整行头单元格宽高 +> 优先级小于 `style.treeRowsWidth` + ```ts const s2Options = { style: { @@ -66,9 +70,25 @@ const s2Options = { } ``` +还可以根据当前行头节点信息动态调整,返回 `null` 代表使用默认宽度 + +```ts +const s2Options = { + style: { + rowCfg: { + width: (row) => { + console.log('row: ', row); + // 动态配置:叶子节点 300px, 非叶子节点 200px + return row.isLeaf ? 300 : 200; + }, + }, + }, +} +``` + preview -如果想给每一行设置不同的高度,可以通过 `rowCfg` 的 `heightByField` 来实现,这里的 `field` 对应行列交叉后每一个行头节点对应的唯一 ID [(如何获取)](/zh/docs/manual/advanced/get-cell-data#%E8%8E%B7%E5%8F%96%E6%8C%87%E5%AE%9A%E5%8C%BA%E5%9F%9F%E5%8D%95%E5%85%83%E6%A0%BC) +如果想给每一行设置不同的高度,可以通过 `rowCfg` 的 `heightByField` 预设高度来实现,这里的 `field` 对应行列交叉后每一个行头节点对应的唯一 ID [(如何获取)](/zh/docs/manual/advanced/get-cell-data#%E8%8E%B7%E5%8F%96%E6%8C%87%E5%AE%9A%E5%8C%BA%E5%9F%9F%E5%8D%95%E5%85%83%E6%A0%BC) ```ts const s2Options = { @@ -91,17 +111,35 @@ const s2Options = { const s2Options = { style: { colCfg: { + width: 200, height: 60, }, }, } ``` +列头单元格宽度调整**作用于叶子节点** (非叶子节点的宽度是所有子节点宽度总和) + preview -和行头一样,列头单元格的**宽度**始终和数值单元格一致,调整数值单元格的宽度相当于也调整了**列头的宽度** +和行头一样,列头单元格**叶子节点**的**宽度**始终和数值单元格一致,调整数值单元格的宽度相当于也调整了**列头的宽度** + +如果想给每一列设置**不同**的宽度,可以根据当前列头节点信息动态调整宽度,返回 `null` 代表使用默认宽度 + +```ts +const s2Options = { + style: { + colCfg: { + width: (colNode) => { + console.log('colNode: ', colNode); + return colNode.colIndex <= 2 ? 100 : 50 + }, + }, + }, +} +``` -如果想给每一列设置不同的宽度,可以通过 `colCfg` 的 `widthByFieldValue` 来实现,此时 `fieldValue` 对应 `s2DataConfig.fields.columns` 中配置的列头字段 +还可以通过 `colCfg.widthByFieldValue` 来预设宽度实现,S2 表格内部使用该属性用来做拖拽调整宽高的数据存储,此时 `fieldValue` 对应 `s2DataConfig.fields.columns` 中配置的列头数值 ```ts const s2Options = { diff --git a/s2-site/examples/layout/custom/demo/custom-row-col-cell-width.ts b/s2-site/examples/layout/custom/demo/custom-row-col-cell-width.ts new file mode 100644 index 0000000000..610eb73c5e --- /dev/null +++ b/s2-site/examples/layout/custom/demo/custom-row-col-cell-width.ts @@ -0,0 +1,42 @@ +import { PivotSheet } from '@antv/s2'; + +fetch( + 'https://gw.alipayobjects.com/os/bmw-prod/2a5dbbc8-d0a7-4d02-b7c9-34f6ca63cff6.json', +) + .then((res) => res.json()) + .then((dataCfg) => { + const container = document.getElementById('container'); + + // 详情请查看: https://s2.antv.vision/zh/docs/manual/advanced/custom/cell-size + const s2Options = { + width: 600, + height: 480, + hierarchyType: 'grid', + style: { + rowCfg: { + // 固定配置: 行头单元格 100px + // width: 100, + // 动态配置: 叶子节点 300px, 非叶子节点 200px + width: (row) => { + console.log('row: ', row); + return row.isLeaf ? 300 : 200; + }, + }, + colCfg: { + // 固定配置: 每列 100px + // width: 100, + // 动态配置: 偶数列 100px, 奇数列 200px + width: (col) => { + console.log('col: ', col); + return col.colIndex % 2 === 0 ? 100 : 200; + }, + }, + cellCfg: { + height: 50, + }, + }, + }; + + const s2 = new PivotSheet(container, dataCfg, s2Options); + s2.render(); + }); diff --git a/s2-site/examples/layout/custom/demo/meta.json b/s2-site/examples/layout/custom/demo/meta.json index 1c6f1d2ee8..d08f3df300 100644 --- a/s2-site/examples/layout/custom/demo/meta.json +++ b/s2-site/examples/layout/custom/demo/meta.json @@ -20,6 +20,14 @@ }, "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/oIjIixviI/ccba0c66-c8ba-4285-b0ec-fc776d0a4cdf.png" }, + { + "filename": "custom-row-col-cell-width.ts", + "title": { + "zh": "自定义行列单元格宽度", + "en": "Custom Row/Column Cell Height" + }, + "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/gzR%26xlnjG/7b23ff29-0789-4420-ad23-e1df96e4489d.png" + }, { "filename": "custom-tree-row-width.ts", "title": {