From b03838d8fd31b79f70e38ef798ce0cbd3c9f4f56 Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Thu, 16 May 2024 16:47:05 +0800 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20=E6=98=8E=E7=BB=86=E8=A1=A8?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=A9=BA=E6=95=B0=E6=8D=AE=E5=8D=A0=E4=BD=8D?= =?UTF-8?q?=E7=AC=A6=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: s2Options.placeholder 配置更改为 cell 和 empty --- ...interaction-brush-selection-scroll-spec.ts | 4 +- .../__tests__/spreadsheet/table-sheet-spec.ts | 4 +- packages/s2-core/src/common/constant/basic.ts | 4 + .../s2-core/src/common/constant/options.ts | 8 +- .../s2-core/src/common/icons/svg/index.ts | 1 + packages/s2-core/src/common/icons/svg/svgs.ts | 2 + .../s2-core/src/common/interface/s2Options.ts | 38 ++++++-- .../s2-core/src/common/interface/theme.ts | 28 +++++- packages/s2-core/src/facet/base-facet.ts | 28 +++--- packages/s2-core/src/facet/frozen-facet.ts | 2 +- packages/s2-core/src/facet/table-facet.ts | 88 ++++++++++++++++++- packages/s2-core/src/theme/index.ts | 20 +++++ packages/s2-core/src/utils/text.ts | 3 +- .../s2-react/__tests__/data/strategy-data.ts | 4 +- .../spreadsheet/table-sheet-spec.tsx | 4 +- packages/s2-react/playground/config.tsx | 10 ++- packages/s2-react/playground/index.tsx | 8 +- s2-site/docs/api/general/S2Theme.zh.md | 10 +++ .../manual/basic/sheet-type/table-mode.zh.md | 6 ++ s2-site/docs/manual/migration-v2.zh.md | 37 +++++++- s2-site/examples/basic/table/demo/table.ts | 17 +++- .../case/kpi-strategy/demo/covid-trend.tsx | 4 +- .../custom-cell/demo/data-cell-placeholder.ts | 22 +++-- .../custom-cell/demo/empty-placeholder.ts | 59 +++++++++++++ .../custom/custom-cell/demo/meta.json | 9 ++ .../theme/custom/demo/custom-schema.ts | 32 ++++++- 26 files changed, 396 insertions(+), 56 deletions(-) create mode 100644 s2-site/examples/custom/custom-cell/demo/empty-placeholder.ts diff --git a/packages/s2-core/__tests__/spreadsheet/interaction-brush-selection-scroll-spec.ts b/packages/s2-core/__tests__/spreadsheet/interaction-brush-selection-scroll-spec.ts index 7dfec4a89b..d0d83bcb9a 100644 --- a/packages/s2-core/__tests__/spreadsheet/interaction-brush-selection-scroll-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/interaction-brush-selection-scroll-spec.ts @@ -56,7 +56,9 @@ const options: S2Options = { seriesNumber: { enable: true, }, - placeholder: '', + placeholder: { + cell: '', + }, style: { layoutWidthType: LayoutWidthType.Compact, dataCell: { diff --git a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts index 78c4cd5d74..9400a0eaff 100644 --- a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts @@ -74,7 +74,9 @@ const options: S2Options = { seriesNumber: { enable: true, }, - placeholder: '', + placeholder: { + cell: '', + }, style: { layoutWidthType: LayoutWidthType.Compact, dataCell: { diff --git a/packages/s2-core/src/common/constant/basic.ts b/packages/s2-core/src/common/constant/basic.ts index a8d854534c..9c012e2af1 100644 --- a/packages/s2-core/src/common/constant/basic.ts +++ b/packages/s2-core/src/common/constant/basic.ts @@ -17,6 +17,9 @@ export const PANEL_GRID_GROUP_Z_INDEX = 2; export const PANEL_MERGE_GROUP_Z_INDEX = 3; export const PANEL_GROUP_FROZEN_GROUP_Z_INDEX = 4; +// emptyPlaceholderGroup 上的 children 层叠顺序 +export const EMPTY_PLACEHOLDER_GROUP_CONTAINER_Z_INDEX = 4; + // group's key export const KEY_GROUP_BACK_GROUND = 'backGroundGroup'; export const KEY_GROUP_FORE_GROUND = 'foreGroundGroup'; @@ -42,6 +45,7 @@ export const KEY_GROUP_COL_FROZEN_TRAILING = 'colFrozenTrailingGroup'; export const KEY_GROUP_GRID_GROUP = 'gridGroup'; export const KEY_GROUP_ROW_SCROLL = 'rowScrollGroup'; export const KEY_GROUP_ROW_HEADER_FROZEN = 'rowHeaderFrozenGroup'; +export const KEY_GROUP_EMPTY_PLACEHOLDER = 'emptyPlaceholderGroup'; export const HORIZONTAL_RESIZE_AREA_KEY_PRE = 'horizontal-resize-area-'; diff --git a/packages/s2-core/src/common/constant/options.ts b/packages/s2-core/src/common/constant/options.ts index a4f23c4884..6a0562463d 100644 --- a/packages/s2-core/src/common/constant/options.ts +++ b/packages/s2-core/src/common/constant/options.ts @@ -135,5 +135,11 @@ export const DEFAULT_OPTIONS: S2Options = { hd: true, cornerText: '', cornerExtraFieldText: '', - placeholder: EMPTY_PLACEHOLDER, + placeholder: { + cell: EMPTY_PLACEHOLDER, + empty: { + icon: 'Empty', + description: '暂无数据', + }, + }, }; diff --git a/packages/s2-core/src/common/icons/svg/index.ts b/packages/s2-core/src/common/icons/svg/index.ts index 9f83c403af..86bb41bde7 100644 --- a/packages/s2-core/src/common/icons/svg/index.ts +++ b/packages/s2-core/src/common/icons/svg/index.ts @@ -19,4 +19,5 @@ export { Trend, DrillDownIcon, EyeOutlined, + Empty, } from './svgs'; diff --git a/packages/s2-core/src/common/icons/svg/svgs.ts b/packages/s2-core/src/common/icons/svg/svgs.ts index 9609b0c73a..48ff778157 100644 --- a/packages/s2-core/src/common/icons/svg/svgs.ts +++ b/packages/s2-core/src/common/icons/svg/svgs.ts @@ -175,3 +175,5 @@ export const DrillDownIcon = ``; + +export const Empty = ``; diff --git a/packages/s2-core/src/common/interface/s2Options.ts b/packages/s2-core/src/common/interface/s2Options.ts index 8d8a603bc0..1064c6baec 100644 --- a/packages/s2-core/src/common/interface/s2Options.ts +++ b/packages/s2-core/src/common/interface/s2Options.ts @@ -126,14 +126,36 @@ export interface S2BasicOptions< hd?: boolean; /** - * 空值单元格占位符 - * @see https://s2.antv.antgroup.com/zh/examples/custom/custom-cell/#data-cell-placeholder - */ - placeholder?: - | ((meta: Record) => string | undefined | null) - | string - | undefined - | null; + * 占位符 + */ + placeholder?: { + /** + * 空值单元格占位符 + * @see https://s2.antv.antgroup.com/zh/examples/custom/custom-cell/#data-cell-placeholder + */ + + cell?: + | ((meta: Record) => string | undefined | null) + | string + | null; + + /** + * 空数据占位符 (明细表有效) + */ + empty?: { + /** + * 自定义 Icon, 支持 customSVGIcons 自定义注册和内置的 Icon + * @see https://s2.antv.antgroup.com/manual/advanced/custom/custom-icon + */ + icon?: string; + + /** + * 自定义描述内容 + * @example description: "暂无数据" + */ + description?: string; + }; + }; /** * 设备类型: pc / mobile diff --git a/packages/s2-core/src/common/interface/theme.ts b/packages/s2-core/src/common/interface/theme.ts index 37e94b851f..b263c72790 100644 --- a/packages/s2-core/src/common/interface/theme.ts +++ b/packages/s2-core/src/common/interface/theme.ts @@ -1,4 +1,5 @@ import type { LineStyleProps, TextStyleProps } from '@antv/g'; +import type { Omit } from 'lodash'; import type { CellType } from '../../common/constant/interaction'; import type { InteractionStateName } from '../constant'; import type { PALETTE_MAP } from '../constant/theme'; @@ -69,11 +70,31 @@ export interface Padding { left?: number; } -export interface Background { +export interface BackgroundTheme { opacity?: number; color?: string; } +export interface EmptyTheme { + /** 空状态图标 */ + icon?: Omit & { + width?: number; + height?: number; + }; + + /** 空状态文案 */ + description?: Pick< + TextStyleProps, + | 'fontFamily' + | 'fontSize' + | 'fontWeight' + | 'fill' + | 'opacity' + | 'fontStyle' + | 'fontVariant' + >; +} + export interface InteractionStateTheme { /** 背景透明度 */ backgroundOpacity?: number; @@ -321,7 +342,10 @@ export interface S2Theme extends CellThemes { prepareSelectMask?: InteractionStateTheme; /** 画布背景底色 */ - background?: Background; + background?: BackgroundTheme; + + /** 空数据占位符 */ + empty?: EmptyTheme; } export type ThemeName = keyof typeof PALETTE_MAP; diff --git a/packages/s2-core/src/facet/base-facet.ts b/packages/s2-core/src/facet/base-facet.ts index 9cd354bfaa..9830bf468a 100644 --- a/packages/s2-core/src/facet/base-facet.ts +++ b/packages/s2-core/src/facet/base-facet.ts @@ -226,29 +226,31 @@ export abstract class BaseFacet { }; protected initGroups() { - const container = this.spreadsheet.container; + this.initBackgroundGroup(); + this.initPanelGroups(); + this.initForegroundGroup(); + } - this.backgroundGroup = container.appendChild( + private initForegroundGroup() { + this.foregroundGroup = this.spreadsheet.container.appendChild( new Group({ - name: KEY_GROUP_BACK_GROUND, - style: { zIndex: BACK_GROUND_GROUP_CONTAINER_Z_INDEX }, + name: KEY_GROUP_FORE_GROUND, + style: { zIndex: FRONT_GROUND_GROUP_CONTAINER_Z_INDEX }, }), ); + } - this.initPanelGroups(); - - this.foregroundGroup = container.appendChild( + private initBackgroundGroup() { + this.backgroundGroup = this.spreadsheet.container.appendChild( new Group({ - name: KEY_GROUP_FORE_GROUND, - style: { zIndex: FRONT_GROUND_GROUP_CONTAINER_Z_INDEX }, + name: KEY_GROUP_BACK_GROUND, + style: { zIndex: BACK_GROUND_GROUP_CONTAINER_Z_INDEX }, }), ); } protected initPanelGroups() { - const container = this.spreadsheet.container; - - this.panelGroup = container.appendChild( + this.panelGroup = this.spreadsheet.container.appendChild( new Group({ name: KEY_GROUP_PANEL_GROUND, style: { zIndex: PANEL_GROUP_GROUP_CONTAINER_Z_INDEX }, @@ -746,7 +748,7 @@ export abstract class BaseFacet { return heights.getTotalHeight(); }; - clearAllGroup() { + public clearAllGroup() { const { children = [] } = this.panelGroup; for (let i = children.length - 1; i >= 0; i--) { diff --git a/packages/s2-core/src/facet/frozen-facet.ts b/packages/s2-core/src/facet/frozen-facet.ts index d87531cc70..30b28d6a4d 100644 --- a/packages/s2-core/src/facet/frozen-facet.ts +++ b/packages/s2-core/src/facet/frozen-facet.ts @@ -588,7 +588,7 @@ export abstract class FrozenFacet extends BaseFacet { } }; - public render(): void { + public render() { this.calculateFrozenGroupInfo(); this.renderFrozenPanelCornerGroup(); super.render(); diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index 2e5527a2a0..eac215c2cd 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -1,4 +1,4 @@ -import { Group } from '@antv/g'; +import { Group, Rect } from '@antv/g'; import { isBoolean, isEmpty, @@ -11,6 +11,8 @@ import { } from 'lodash'; import { TableDataCell, TableSeriesNumberCell } from '../cell'; import { + EMPTY_PLACEHOLDER_GROUP_CONTAINER_Z_INDEX, + KEY_GROUP_EMPTY_PLACEHOLDER, KEY_GROUP_FROZEN_ROW_RESIZE_AREA, KEY_GROUP_ROW_RESIZE_AREA, LayoutWidthType, @@ -31,6 +33,7 @@ import type { } from '../common/interface'; import type { TableDataSet } from '../data-set'; import type { SpreadSheet } from '../sheet-type'; +import { renderIcon, renderText } from '../utils'; import { getDataCellId } from '../utils/cell/data-cell'; import { getOccupiedWidthForTableCol } from '../utils/cell/table-col-cell'; import { getIndexRangeWithOffsets } from '../utils/facet'; @@ -48,17 +51,100 @@ import { Node } from './layout/node'; import { getFrozenLeafNodesCount, isFrozenTrailingRow } from './utils'; export class TableFacet extends FrozenFacet { + public emptyPlaceholderGroup: Group; + public constructor(spreadsheet: SpreadSheet) { super(spreadsheet); this.spreadsheet.on(S2Event.RANGE_SORT, this.onSortHandler); this.spreadsheet.on(S2Event.RANGE_FILTER, this.onFilterHandler); } + protected initGroups() { + super.initGroups(); + this.initEmptyPlaceholderGroup(); + } + public init() { super.init(); this.initRowOffsets(); } + public render() { + super.render(); + this.renderEmptyPlaceholder(); + } + + public clearAllGroup() { + super.clearAllGroup(); + this.emptyPlaceholderGroup.removeChildren(); + } + + private initEmptyPlaceholderGroup() { + this.emptyPlaceholderGroup = this.spreadsheet.container.appendChild( + new Group({ + name: KEY_GROUP_EMPTY_PLACEHOLDER, + style: { zIndex: EMPTY_PLACEHOLDER_GROUP_CONTAINER_Z_INDEX }, + }), + ); + } + + private renderEmptyPlaceholder() { + if (!this.spreadsheet.dataSet?.isEmpty()) { + return; + } + + const { empty } = this.spreadsheet.options.placeholder!; + const { icon, description } = this.spreadsheet.theme.empty; + const { + horizontalBorderWidth, + horizontalBorderColor, + horizontalBorderColorOpacity, + } = this.spreadsheet.theme.dataCell.cell!; + const { maxY, width, height } = this.panelBBox; + const iconX = width / 2 - icon.width / 2; + const iconY = height / 2 + maxY - icon.height / 2 + icon.margin.top; + const text = empty?.description || ''; + const descWidth = this.spreadsheet.measureTextWidth(text, description); + const descX = width / 2 - descWidth / 2; + const descY = iconY + icon.height + icon.margin.bottom; + + // 边框 + const border = new Rect({ + style: { + x: 0, + y: maxY, + width, + height, + stroke: horizontalBorderColor, + strokeWidth: horizontalBorderWidth, + strokeOpacity: horizontalBorderColorOpacity, + }, + }); + + this.emptyPlaceholderGroup.appendChild(border); + + // 空状态 Icon + renderIcon(this.emptyPlaceholderGroup, { + ...icon, + name: empty?.icon!, + x: iconX, + y: iconY, + width: icon.width, + height: icon.height, + }); + + // 空状态描述文本 + renderText({ + group: this.emptyPlaceholderGroup, + style: { + ...description, + text, + x: descX, + y: descY, + }, + }); + } + private getDataCellAdaptiveHeight(viewMeta: ViewMeta): number { const node = { id: String(viewMeta?.rowIndex) } as Node; const rowHeight = this.getRowCellHeight(node); diff --git a/packages/s2-core/src/theme/index.ts b/packages/s2-core/src/theme/index.ts index 3f8c1c279e..274e93ac5d 100644 --- a/packages/s2-core/src/theme/index.ts +++ b/packages/s2-core/src/theme/index.ts @@ -482,5 +482,25 @@ export const getTheme = ( color: basicColors[8], opacity: 1, }, + empty: { + icon: { + fill: '', + width: 64, + height: 41, + margin: { + top: 0, + right: 0, + bottom: 24, + left: 0, + }, + }, + description: { + fontFamily: FONT_FAMILY, + fontSize: 12, + fontWeight: 'normal', + fill: basicColors[14], + opacity: 1, + }, + }, }; }; diff --git a/packages/s2-core/src/utils/text.ts b/packages/s2-core/src/utils/text.ts index 11233f8a1c..6bdbeee3c0 100644 --- a/packages/s2-core/src/utils/text.ts +++ b/packages/s2-core/src/utils/text.ts @@ -178,7 +178,8 @@ const getCurrentTextStyle = ({ export const getEmptyPlaceholder = ( meta: Record, placeHolder: S2Options['placeholder'], -) => (isFunction(placeHolder) ? placeHolder(meta) : placeHolder); +) => + isFunction(placeHolder?.cell) ? placeHolder?.cell(meta) : placeHolder?.cell; /** * @desc 获取多指标情况下每一个指标的内容包围盒 diff --git a/packages/s2-react/__tests__/data/strategy-data.ts b/packages/s2-react/__tests__/data/strategy-data.ts index 2742c30ddc..5816b5a6fc 100644 --- a/packages/s2-react/__tests__/data/strategy-data.ts +++ b/packages/s2-react/__tests__/data/strategy-data.ts @@ -387,7 +387,9 @@ export const StrategySheetDataConfig: S2DataConfig = { export const StrategyOptions: SheetComponentOptions = { height: 800, cornerText: '指标', - placeholder: (v) => (v?.['fieldValue'] ? '-' : ''), + placeholder: { + cell: (v) => (v?.['fieldValue'] ? '-' : ''), + }, interaction: { selectedCellsSpotlight: true, resize: { diff --git a/packages/s2-react/__tests__/spreadsheet/table-sheet-spec.tsx b/packages/s2-react/__tests__/spreadsheet/table-sheet-spec.tsx index 10d3ef9f14..471d0313a9 100644 --- a/packages/s2-react/__tests__/spreadsheet/table-sheet-spec.tsx +++ b/packages/s2-react/__tests__/spreadsheet/table-sheet-spec.tsx @@ -128,7 +128,9 @@ function MainLayout({ callback }: Props) { seriesNumber: { enable: true, }, - placeholder: '', + placeholder: { + cell: '', + }, style: { dataCell: { height: 32, diff --git a/packages/s2-react/playground/config.tsx b/packages/s2-react/playground/config.tsx index c87f7ec4ee..7e12011fd5 100644 --- a/packages/s2-react/playground/config.tsx +++ b/packages/s2-react/playground/config.tsx @@ -56,7 +56,7 @@ export const tableSheetMultipleColumns: CustomTreeNode[] = [ ]; export const tableSheetDataCfg: S2DataConfig = { - data, + data: [], totalData, meta: [ { field: 'number', name: '数值', formatter: (v) => `${v}-@` }, @@ -314,8 +314,14 @@ export const S2TooltipOptions: SheetComponentOptions['tooltip'] = { export const s2Options: SheetComponentOptions = { debug: true, width: 800, - height: 600, + height: 400, hierarchyType: 'grid', + placeholder: { + empty: { + icon: 'Trend', + description: '暂无数据', + }, + }, seriesNumber: { enable: false, }, diff --git a/packages/s2-react/playground/index.tsx b/packages/s2-react/playground/index.tsx index 6b97397dbb..b467cfc4ac 100644 --- a/packages/s2-react/playground/index.tsx +++ b/packages/s2-react/playground/index.tsx @@ -18,6 +18,7 @@ import { type TargetCellInfo, type ThemeCfg, type TooltipAutoAdjustBoundary, + safeJsonParse, } from '@antv/s2'; import type { Adaptive, SheetType } from '@antv/s2-shared'; import corePkg from '@antv/s2/package.json'; @@ -410,10 +411,9 @@ function MainLayout() { <> ](#icontheme) & { width: number, height: number } | `{ fill: '', width: 64, height: 41, margin: { top: 0, right: 0, bottom: 24, left: 0, } }` | | +| text | 文本 | [TextTheme](#texttheme) | `{ fontSize: 12, fontWeight: 'normal', opacity: 1 }` | | + #### MiniChartTheme 功能描述:迷你图配置。查看 [文档](/manual/advanced/chart-in-cell) 和 [示例](examples/custom/custom-cell/#mini-chart) diff --git a/s2-site/docs/manual/basic/sheet-type/table-mode.zh.md b/s2-site/docs/manual/basic/sheet-type/table-mode.zh.md index b690a42f5c..546adf3505 100644 --- a/s2-site/docs/manual/basic/sheet-type/table-mode.zh.md +++ b/s2-site/docs/manual/basic/sheet-type/table-mode.zh.md @@ -187,3 +187,9 @@ const s2Options = { ### 列头自定义分组 列头结构默认根据传入的维值进行分组,同时支持自定义分组,可实现多级列头。[了解更多](/manual/advanced/custom/custom-header) + +### 空数据占位符 + +当数据为空时,可以自定义展示图标和描述。图标支持 [customSVGIcons](/manual/advanced/custom/custom-icon) 自定义注册和内置的 Icon, 图标,文字的大小和间距可以通过 [主题配置](/api/general/s2-theme#empty) 修改。 + + diff --git a/s2-site/docs/manual/migration-v2.zh.md b/s2-site/docs/manual/migration-v2.zh.md index a76c4b2ab1..010edc441f 100644 --- a/s2-site/docs/manual/migration-v2.zh.md +++ b/s2-site/docs/manual/migration-v2.zh.md @@ -485,7 +485,7 @@ const s2Options = { #### Facet 变更 -1. 静态属性 `layoutResult` 废弃,使用 `s2.facet.getLayoutResult()` 动态获取。 +1. 静态属性 `layoutResult` 废弃,使用 `s2.facet.getLayoutResult()` 动态获取,现在包含 `角头节点 (cornerNodes)` 和 `序号节点 (seriesNumberNodes)`。 ```diff - s2.facet.layoutResult @@ -671,6 +671,41 @@ s2.interaction.getState() + import { setupOptions, setupDataConfig } from '@antv/s2' ``` +### 空数据占位符配置变更 + +除了支持配置单元格的空数据占位符,现在支持配置明细表的 [空数据状态](/examples/custom/custom-cell/#empty-placeholder),类似于 [Ant Design 的 Empty 组件](https://ant-design.antgroup.com/components/empty-cn) 的空状态效果,配置独立为 `cell` 和 `empty` 两个配置项,以区分两种状态。 + +```diff +const s2Options = { +- placeholder: "-", ++ placeholder: { ++ cell: '-' ++ } +} +``` + +```diff +const s2Options = { ++ placeholder: { ++ empty: { ++ icon: 'Empty', ++ description: '暂无数据' ++ } ++ } +} +``` + +具体请查看 [自定义空数据占位符](/examples/custom/custom-cell/#empty-placeholder) 和 [自定义单元格空数据占位符](/examples/custom/custom-cell/#data-cell-placeholder) 示例。 + +### 内部常量重命名 + +```diff +- import { ROOT_ID, ID_SEPARATOR } from '@antv/s2' ++ import { ROOT_NODE_ID, NODE_ID_SEPARATOR } from '@antv/s2' +``` + +如有消费请注意修改,具体请查看 [源代码定义](https://github.com/antvis/S2/tree/next/packages/s2-core/src/common/constant). + ### 组件层 @antv/s2-react #### 支持 React 18 和 Ant Design 5.0 diff --git a/s2-site/examples/basic/table/demo/table.ts b/s2-site/examples/basic/table/demo/table.ts index 8a96fb0835..a77f0b140e 100644 --- a/s2-site/examples/basic/table/demo/table.ts +++ b/s2-site/examples/basic/table/demo/table.ts @@ -40,10 +40,19 @@ fetch('https://assets.antv.antgroup.com/s2/basic-table-mode.json') enable: true, text: '序号', }, - // 自定义空数据单元格占位符 - // placeholder: '-', - placeholder(meta) { - return '-'; + placeholder: { + // 自定义空数据单元格占位符 + cell: '-', + // cell: (meta) => '-', + // 自定义空数据占位符: 文本,图标的大小和间距可以通过主题配置修改 https://s2.antv.antgroup.com/api/general/s2-theme#empty + empty: { + /** + * 自定义 Icon, 支持 customSVGIcons 自定义注册和内置的 Icon + * @see https://s2.antv.antgroup.com/manual/advanced/custom/custom-icon + */ + icon: 'Empty', + description: '暂无数据', + }, }, }; diff --git a/s2-site/examples/case/kpi-strategy/demo/covid-trend.tsx b/s2-site/examples/case/kpi-strategy/demo/covid-trend.tsx index fff30530f9..fe4a1bbcc0 100644 --- a/s2-site/examples/case/kpi-strategy/demo/covid-trend.tsx +++ b/s2-site/examples/case/kpi-strategy/demo/covid-trend.tsx @@ -24,7 +24,9 @@ fetch( const s2Options: SheetComponentOptions = { width: 1200, height: 600, - placeholder: '', + placeholder: { + cell: '', + }, hierarchyType: 'tree', cornerText: '指标', style: { diff --git a/s2-site/examples/custom/custom-cell/demo/data-cell-placeholder.ts b/s2-site/examples/custom/custom-cell/demo/data-cell-placeholder.ts index 412c6ea41a..3058c7e1e2 100644 --- a/s2-site/examples/custom/custom-cell/demo/data-cell-placeholder.ts +++ b/s2-site/examples/custom/custom-cell/demo/data-cell-placeholder.ts @@ -25,16 +25,20 @@ fetch( width: 600, height: 480, // 默认 "-" - // placeholder: '', - placeholder: (cell) => { - // 或者根据当前单元格动态设置 - console.log('cell: ', cell); - if (cell.cellType === 'dataCell') { - return '*****'; - } + // placeholder: { + // cell: '', + // }, + placeholder: { + cell: (cell) => { + // 或者根据当前单元格动态设置 + console.log('cell: ', cell); + if (cell.cellType === 'dataCell') { + return '*****'; + } - // 返回 null, 使用默认值 ("-") - return null; + // 返回 null, 使用默认值 ("-") + return null; + }, }, }; diff --git a/s2-site/examples/custom/custom-cell/demo/empty-placeholder.ts b/s2-site/examples/custom/custom-cell/demo/empty-placeholder.ts new file mode 100644 index 0000000000..10d6b00389 --- /dev/null +++ b/s2-site/examples/custom/custom-cell/demo/empty-placeholder.ts @@ -0,0 +1,59 @@ +import { S2DataConfig, S2Options, TableSheet } from '@antv/s2'; + +fetch('https://assets.antv.antgroup.com/s2/basic-table-mode.json') + .then((res) => res.json()) + .then(async (data) => { + const container = document.getElementById('container'); + const s2DataConfig: S2DataConfig = { + fields: { + columns: ['province', 'city', 'type', 'price', 'cost'], + }, + meta: [ + { + field: 'province', + name: '省份', + }, + { + field: 'city', + name: '城市', + }, + { + field: 'type', + name: '商品类别', + }, + { + field: 'price', + name: '价格', + }, + { + field: 'cost', + name: '成本', + }, + ], + data: [], + }; + + const s2Options: S2Options = { + width: 600, + height: 480, + seriesNumber: { + enable: true, + text: '序号', + }, + // 自定义空数据占位符: 文本,图标的大小和间距可以通过主题配置修改 https://s2.antv.antgroup.com/api/general/s2-theme#empty + placeholder: { + empty: { + /** + * 自定义 Icon, 支持 customSVGIcons 自定义注册和内置的 Icon + * @see https://s2.antv.antgroup.com/manual/advanced/custom/custom-icon + */ + icon: 'Empty', + description: '暂无数据', + }, + }, + }; + + const s2 = new TableSheet(container, s2DataConfig, s2Options); + + await s2.render(); + }); diff --git a/s2-site/examples/custom/custom-cell/demo/meta.json b/s2-site/examples/custom/custom-cell/demo/meta.json index 4f5ce24aa2..44ab7f1e50 100644 --- a/s2-site/examples/custom/custom-cell/demo/meta.json +++ b/s2-site/examples/custom/custom-cell/demo/meta.json @@ -102,6 +102,15 @@ }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*B-VMT7kCWL0AAAAAAAAAAAAADmJ7AQ/original", "new": true + }, + { + "filename": "empty-placeholder.ts", + "title": { + "zh": "自定义空数据占位符", + "en": "custom empty placeholder" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*pejXR4SODQMAAAAAAAAAAAAADmJ7AQ/original", + "new": true } ] } diff --git a/s2-site/examples/theme/custom/demo/custom-schema.ts b/s2-site/examples/theme/custom/demo/custom-schema.ts index 26e6539173..8f3325d82b 100644 --- a/s2-site/examples/theme/custom/demo/custom-schema.ts +++ b/s2-site/examples/theme/custom/demo/custom-schema.ts @@ -1,9 +1,13 @@ /* eslint-disable max-lines-per-function */ -import { S2DataConfig, S2Options, S2Theme, TableSheet } from '@antv/s2'; +import { + FONT_FAMILY, + S2DataConfig, + S2Options, + S2Theme, + TableSheet, +} from '@antv/s2'; -fetch( - 'https://render.alipay.com/p/yuyan/180020010001215413/s2/basic.json', -) +fetch('https://render.alipay.com/p/yuyan/180020010001215413/s2/basic.json') .then((res) => res.json()) .then(async (data) => { const container = document.getElementById('container'); @@ -50,6 +54,26 @@ fetch( background: { color: HEADER_BACK_COLOR, }, + empty: { + icon: { + fill: '#fff', + width: 64, + height: 41, + margin: { + top: 0, + right: 0, + bottom: 24, + left: 0, + }, + }, + description: { + fontFamily: FONT_FAMILY, + fontSize: 12, + fontWeight: 'normal', + fill: '#fff', + opacity: 1, + }, + }, cornerCell: { cell: { horizontalBorderColor: BORDER_COLOR, From 5c2e3a0e2bfa43332282381af37b44ad5f3d8d85 Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Thu, 16 May 2024 17:21:13 +0800 Subject: [PATCH 2/9] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/table-sheet-spec.ts.snap | 178 ++++++++++++++++++ .../__tests__/spreadsheet/table-sheet-spec.ts | 76 ++++++++ .../s2-core/src/common/interface/s2Options.ts | 8 +- packages/s2-react/playground/config.tsx | 6 +- s2-site/docs/manual/migration-v2.zh.md | 4 +- .../custom-cell/demo/empty-placeholder.ts | 104 +++++----- .../custom/custom-cell/demo/meta.json | 2 +- 7 files changed, 316 insertions(+), 62 deletions(-) create mode 100644 packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap new file mode 100644 index 0000000000..b666907a20 --- /dev/null +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap @@ -0,0 +1,178 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TableSheet normal spec should render empty placeholder 1`] = ` +Object { + "height": 562, + "stroke": CSSRGB { + "alpha": 1, + "b": 253, + "colorSpace": "rgb", + "g": 233, + "isNone": false, + "r": 224, + }, + "strokeOpacity": 1, + "strokeWidth": 1, + "width": 799, + "x": 0, + "y": 32, +} +`; + +exports[`TableSheet normal spec should render empty placeholder 2`] = ` +Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "name": "Empty", + "width": 64, + "x": 367.5, + "y": 292.5, +} +`; + +exports[`TableSheet normal spec should render empty placeholder 3`] = ` +Object { + "fill": CSSRGB { + "alpha": 1, + "b": 0, + "colorSpace": "rgb", + "g": 0, + "isNone": false, + "r": 0, + }, + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontStyle": "normal", + "fontVariant": "normal", + "fontWeight": "normal", + "lineWidth": 1, + "opacity": 1, + "text": "暂无数据", + "x": 375.5, + "y": 357.5, +} +`; + +exports[`TableSheet normal spec should render empty placeholder by custom icon and description 1`] = ` +Object { + "height": 562, + "stroke": CSSRGB { + "alpha": 1, + "b": 253, + "colorSpace": "rgb", + "g": 233, + "isNone": false, + "r": 224, + }, + "strokeOpacity": 1, + "strokeWidth": 1, + "width": 799, + "x": 0, + "y": 32, +} +`; + +exports[`TableSheet normal spec should render empty placeholder by custom icon and description 2`] = ` +Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "name": "Trend", + "width": 64, + "x": 367.5, + "y": 292.5, +} +`; + +exports[`TableSheet normal spec should render empty placeholder by custom icon and description 3`] = ` +Object { + "fill": CSSRGB { + "alpha": 1, + "b": 0, + "colorSpace": "rgb", + "g": 0, + "isNone": false, + "r": 0, + }, + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontStyle": "normal", + "fontVariant": "normal", + "fontWeight": "normal", + "lineWidth": 1, + "opacity": 1, + "text": "暂无数据", + "x": 375.5, + "y": 357.5, +} +`; + +exports[`TableSheet normal spec should render empty placeholder by custom icon and description style 1`] = ` +Object { + "height": 562, + "stroke": CSSRGB { + "alpha": 1, + "b": 253, + "colorSpace": "rgb", + "g": 233, + "isNone": false, + "r": 224, + }, + "strokeOpacity": 1, + "strokeWidth": 1, + "width": 799, + "x": 0, + "y": 32, +} +`; + +exports[`TableSheet normal spec should render empty placeholder by custom icon and description style 2`] = ` +Object { + "fill": "green", + "height": 100, + "margin": Object { + "bottom": 80, + "left": 0, + "right": 0, + "top": 0, + }, + "name": "Empty", + "width": 100, + "x": 349.5, + "y": 263, +} +`; + +exports[`TableSheet normal spec should render empty placeholder by custom icon and description style 3`] = ` +Object { + "fill": CSSRGB { + "alpha": 1, + "b": 0, + "colorSpace": "rgb", + "g": 0, + "isNone": false, + "r": 255, + }, + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 20, + "fontStyle": "normal", + "fontVariant": "normal", + "fontWeight": "normal", + "lineWidth": 1, + "opacity": 1, + "text": "暂无数据", + "x": 359.5, + "y": 443, +} +`; diff --git a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts index 9400a0eaff..6a71819835 100644 --- a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts @@ -1,4 +1,5 @@ import { getContainer, getMockData, sleep } from 'tests/util/helpers'; +import type { SpreadSheet, TableFacet } from '../../esm'; import { DeviceType, ResizeType, @@ -109,6 +110,22 @@ const options: S2Options = { }; describe('TableSheet normal spec', () => { + const expectEmptyPlaceholder = async (s2: SpreadSheet) => { + s2.setDataCfg({ + data: [], + }); + await s2.render(); + const [rect, icon, text] = (s2.facet as TableFacet).emptyPlaceholderGroup + .children; + + expect( + (s2.facet as TableFacet).emptyPlaceholderGroup.children, + ).toHaveLength(3); + expect(rect.parsedStyle).toMatchSnapshot(); + expect(icon.getCfg()).toMatchSnapshot(); + expect(text.parsedStyle).toMatchSnapshot(); + }; + test('scrollWithAnimation with duration and callback', async () => { const s2 = new TableSheet(getContainer(), dataCfg, options); @@ -287,4 +304,63 @@ describe('TableSheet normal spec', () => { 'root[&]profit', ]); }); + + test('should render empty placeholder', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { ...options, frozen: {} }, + ); + + await expectEmptyPlaceholder(s2); + }); + + test('should render empty placeholder by custom icon and description', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { + ...options, + frozen: {}, + placeholder: { + empty: { + icon: 'Trend', + describe: '没有数据', + }, + }, + }, + ); + + await expectEmptyPlaceholder(s2); + }); + + test('should render empty placeholder by custom icon and description style', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { + ...options, + frozen: {}, + }, + ); + + s2.setTheme({ + empty: { + icon: { + fill: 'green', + width: 100, + height: 100, + margin: { + bottom: 80, + }, + }, + description: { + fontSize: 20, + fill: 'red', + }, + }, + }); + + await expectEmptyPlaceholder(s2); + }); }); diff --git a/packages/s2-core/src/common/interface/s2Options.ts b/packages/s2-core/src/common/interface/s2Options.ts index 1064c6baec..7df4459ad8 100644 --- a/packages/s2-core/src/common/interface/s2Options.ts +++ b/packages/s2-core/src/common/interface/s2Options.ts @@ -131,9 +131,9 @@ export interface S2BasicOptions< placeholder?: { /** * 空值单元格占位符 - * @see https://s2.antv.antgroup.com/zh/examples/custom/custom-cell/#data-cell-placeholder + * @default '-' + * @see https://s2.antv.antgroup.com/examples/custom/custom-cell/#data-cell-placeholder */ - cell?: | ((meta: Record) => string | undefined | null) | string @@ -141,17 +141,19 @@ export interface S2BasicOptions< /** * 空数据占位符 (明细表有效) + * @see https://s2.antv.antgroup.com/examples/custom/custom-cell/#empty-placeholder */ empty?: { /** * 自定义 Icon, 支持 customSVGIcons 自定义注册和内置的 Icon + * @default "Empty" * @see https://s2.antv.antgroup.com/manual/advanced/custom/custom-icon */ icon?: string; /** * 自定义描述内容 - * @example description: "暂无数据" + * @default "暂无数据" */ description?: string; }; diff --git a/packages/s2-react/playground/config.tsx b/packages/s2-react/playground/config.tsx index 7e12011fd5..c65889f6fe 100644 --- a/packages/s2-react/playground/config.tsx +++ b/packages/s2-react/playground/config.tsx @@ -7,6 +7,7 @@ import { type S2DataConfig, type S2TableSheetFrozenOptions, type ThemeCfg, + EMPTY_PLACEHOLDER, } from '@antv/s2'; import { getBaseSheetComponentOptions } from '@antv/s2-shared'; import { PivotSheetMultiLineTextDataCfg } from '@antv/s2/__tests__/data/data-multi-line-text'; @@ -56,7 +57,7 @@ export const tableSheetMultipleColumns: CustomTreeNode[] = [ ]; export const tableSheetDataCfg: S2DataConfig = { - data: [], + data, totalData, meta: [ { field: 'number', name: '数值', formatter: (v) => `${v}-@` }, @@ -314,9 +315,10 @@ export const S2TooltipOptions: SheetComponentOptions['tooltip'] = { export const s2Options: SheetComponentOptions = { debug: true, width: 800, - height: 400, + height: 600, hierarchyType: 'grid', placeholder: { + cell: EMPTY_PLACEHOLDER, empty: { icon: 'Trend', description: '暂无数据', diff --git a/s2-site/docs/manual/migration-v2.zh.md b/s2-site/docs/manual/migration-v2.zh.md index 010edc441f..3dbd1050af 100644 --- a/s2-site/docs/manual/migration-v2.zh.md +++ b/s2-site/docs/manual/migration-v2.zh.md @@ -664,14 +664,14 @@ s2.interaction.getState() + stateName: "dataCellBrushSelected" ``` -#### 配置预处理 API 变更 +##### 配置预处理 API 变更 ```diff - import { getSafetyOptions, getSafetyDataConfig } from '@antv/s2' + import { setupOptions, setupDataConfig } from '@antv/s2' ``` -### 空数据占位符配置变更 +#### 空数据占位符配置变更 除了支持配置单元格的空数据占位符,现在支持配置明细表的 [空数据状态](/examples/custom/custom-cell/#empty-placeholder),类似于 [Ant Design 的 Empty 组件](https://ant-design.antgroup.com/components/empty-cn) 的空状态效果,配置独立为 `cell` 和 `empty` 两个配置项,以区分两种状态。 diff --git a/s2-site/examples/custom/custom-cell/demo/empty-placeholder.ts b/s2-site/examples/custom/custom-cell/demo/empty-placeholder.ts index 10d6b00389..fcd6112c4e 100644 --- a/s2-site/examples/custom/custom-cell/demo/empty-placeholder.ts +++ b/s2-site/examples/custom/custom-cell/demo/empty-placeholder.ts @@ -1,59 +1,55 @@ import { S2DataConfig, S2Options, TableSheet } from '@antv/s2'; -fetch('https://assets.antv.antgroup.com/s2/basic-table-mode.json') - .then((res) => res.json()) - .then(async (data) => { - const container = document.getElementById('container'); - const s2DataConfig: S2DataConfig = { - fields: { - columns: ['province', 'city', 'type', 'price', 'cost'], - }, - meta: [ - { - field: 'province', - name: '省份', - }, - { - field: 'city', - name: '城市', - }, - { - field: 'type', - name: '商品类别', - }, - { - field: 'price', - name: '价格', - }, - { - field: 'cost', - name: '成本', - }, - ], - data: [], - }; +const container = document.getElementById('container'); +const s2DataConfig: S2DataConfig = { + fields: { + columns: ['province', 'city', 'type', 'price', 'cost'], + }, + meta: [ + { + field: 'province', + name: '省份', + }, + { + field: 'city', + name: '城市', + }, + { + field: 'type', + name: '商品类别', + }, + { + field: 'price', + name: '价格', + }, + { + field: 'cost', + name: '成本', + }, + ], + data: [], +}; - const s2Options: S2Options = { - width: 600, - height: 480, - seriesNumber: { - enable: true, - text: '序号', - }, - // 自定义空数据占位符: 文本,图标的大小和间距可以通过主题配置修改 https://s2.antv.antgroup.com/api/general/s2-theme#empty - placeholder: { - empty: { - /** - * 自定义 Icon, 支持 customSVGIcons 自定义注册和内置的 Icon - * @see https://s2.antv.antgroup.com/manual/advanced/custom/custom-icon - */ - icon: 'Empty', - description: '暂无数据', - }, - }, - }; +const s2Options: S2Options = { + width: 600, + height: 480, + seriesNumber: { + enable: true, + text: '序号', + }, + // 自定义空数据占位符: 文本,图标的大小和间距可以通过主题配置修改 https://s2.antv.antgroup.com/api/general/s2-theme#empty + placeholder: { + empty: { + /** + * 自定义 Icon, 支持 customSVGIcons 自定义注册和内置的 Icon + * @see https://s2.antv.antgroup.com/manual/advanced/custom/custom-icon + */ + icon: 'Empty', + description: '暂无数据', + }, + }, +}; - const s2 = new TableSheet(container, s2DataConfig, s2Options); +const s2 = new TableSheet(container, s2DataConfig, s2Options); - await s2.render(); - }); +s2.render(); diff --git a/s2-site/examples/custom/custom-cell/demo/meta.json b/s2-site/examples/custom/custom-cell/demo/meta.json index 44ab7f1e50..556fcb5036 100644 --- a/s2-site/examples/custom/custom-cell/demo/meta.json +++ b/s2-site/examples/custom/custom-cell/demo/meta.json @@ -106,7 +106,7 @@ { "filename": "empty-placeholder.ts", "title": { - "zh": "自定义空数据占位符", + "zh": "自定义明细表空数据占位符", "en": "custom empty placeholder" }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*pejXR4SODQMAAAAAAAAAAAAADmJ7AQ/original", From f34f7fd2dd6b61dbd9a7fe2aaf83a497a8e89075 Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Fri, 17 May 2024 10:09:22 +0800 Subject: [PATCH 3/9] =?UTF-8?q?fix:=20=E5=85=BC=E5=AE=B9=E6=BB=9A=E5=8A=A8?= =?UTF-8?q?=E6=9D=A1=E7=9A=84=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/table-sheet-spec.ts.snap | 136 ++++++++++++++++-- .../__tests__/spreadsheet/table-sheet-spec.ts | 129 +++++++++++------ packages/s2-core/src/facet/base-facet.ts | 6 +- packages/s2-core/src/facet/table-facet.ts | 14 ++ packages/s2-react/playground/config.tsx | 8 +- 5 files changed, 232 insertions(+), 61 deletions(-) diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap index b666907a20..cc9ab5fdd0 100644 --- a/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TableSheet normal spec should render empty placeholder 1`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder 1`] = ` Object { "height": 562, "stroke": CSSRGB { @@ -19,7 +19,7 @@ Object { } `; -exports[`TableSheet normal spec should render empty placeholder 2`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder 2`] = ` Object { "fill": "", "height": 41, @@ -36,7 +36,7 @@ Object { } `; -exports[`TableSheet normal spec should render empty placeholder 3`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder 3`] = ` Object { "fill": CSSRGB { "alpha": 1, @@ -59,7 +59,66 @@ Object { } `; -exports[`TableSheet normal spec should render empty placeholder by custom icon and description 1`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom col height 1`] = ` +Object { + "height": 272, + "stroke": CSSRGB { + "alpha": 1, + "b": 253, + "colorSpace": "rgb", + "g": 233, + "isNone": false, + "r": 224, + }, + "strokeOpacity": 1, + "strokeWidth": 1, + "width": 599, + "x": 0, + "y": 202, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom col height 2`] = ` +Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "name": "Empty", + "width": 64, + "x": 267.5, + "y": 317.5, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom col height 3`] = ` +Object { + "fill": CSSRGB { + "alpha": 1, + "b": 0, + "colorSpace": "rgb", + "g": 0, + "isNone": false, + "r": 0, + }, + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontStyle": "normal", + "fontVariant": "normal", + "fontWeight": "normal", + "lineWidth": 1, + "opacity": 1, + "text": "暂无数据", + "x": 275.5, + "y": 382.5, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom icon and description 1`] = ` Object { "height": 562, "stroke": CSSRGB { @@ -78,7 +137,7 @@ Object { } `; -exports[`TableSheet normal spec should render empty placeholder by custom icon and description 2`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom icon and description 2`] = ` Object { "fill": "", "height": 41, @@ -95,7 +154,7 @@ Object { } `; -exports[`TableSheet normal spec should render empty placeholder by custom icon and description 3`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom icon and description 3`] = ` Object { "fill": CSSRGB { "alpha": 1, @@ -118,7 +177,7 @@ Object { } `; -exports[`TableSheet normal spec should render empty placeholder by custom icon and description style 1`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom icon and description style 1`] = ` Object { "height": 562, "stroke": CSSRGB { @@ -137,7 +196,7 @@ Object { } `; -exports[`TableSheet normal spec should render empty placeholder by custom icon and description style 2`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom icon and description style 2`] = ` Object { "fill": "green", "height": 100, @@ -154,7 +213,7 @@ Object { } `; -exports[`TableSheet normal spec should render empty placeholder by custom icon and description style 3`] = ` +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom icon and description style 3`] = ` Object { "fill": CSSRGB { "alpha": 1, @@ -176,3 +235,62 @@ Object { "y": 443, } `; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder if contains horizontal scrollbar 1`] = ` +Object { + "height": 562, + "stroke": CSSRGB { + "alpha": 1, + "b": 253, + "colorSpace": "rgb", + "g": 233, + "isNone": false, + "r": 224, + }, + "strokeOpacity": 1, + "strokeWidth": 1, + "width": 799, + "x": 0, + "y": 32, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder if contains horizontal scrollbar 2`] = ` +Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "name": "Empty", + "width": 64, + "x": 367.5, + "y": 292.5, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder if contains horizontal scrollbar 3`] = ` +Object { + "fill": CSSRGB { + "alpha": 1, + "b": 0, + "colorSpace": "rgb", + "g": 0, + "isNone": false, + "r": 0, + }, + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontStyle": "normal", + "fontVariant": "normal", + "fontWeight": "normal", + "lineWidth": 1, + "opacity": 1, + "text": "暂无数据", + "x": 375.5, + "y": 357.5, +} +`; diff --git a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts index 6a71819835..33ba4bab3d 100644 --- a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable jest/expect-expect */ import { getContainer, getMockData, sleep } from 'tests/util/helpers'; import type { SpreadSheet, TableFacet } from '../../esm'; import { @@ -305,62 +306,96 @@ describe('TableSheet normal spec', () => { ]); }); - test('should render empty placeholder', async () => { - const s2 = new TableSheet( - getContainer(), - { ...dataCfg, data: [] }, - { ...options, frozen: {} }, - ); + describe('Empty Placeholder', () => { + test('should render empty placeholder', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { ...options, frozen: {} }, + ); - await expectEmptyPlaceholder(s2); - }); + await expectEmptyPlaceholder(s2); + }); - test('should render empty placeholder by custom icon and description', async () => { - const s2 = new TableSheet( - getContainer(), - { ...dataCfg, data: [] }, - { - ...options, - frozen: {}, - placeholder: { - empty: { - icon: 'Trend', - describe: '没有数据', + test('should render empty placeholder by custom icon and description', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { + ...options, + frozen: {}, + placeholder: { + empty: { + icon: 'Trend', + describe: '没有数据', + }, }, }, - }, - ); + ); - await expectEmptyPlaceholder(s2); - }); - - test('should render empty placeholder by custom icon and description style', async () => { - const s2 = new TableSheet( - getContainer(), - { ...dataCfg, data: [] }, - { - ...options, - frozen: {}, - }, - ); + await expectEmptyPlaceholder(s2); + }); - s2.setTheme({ - empty: { - icon: { - fill: 'green', - width: 100, - height: 100, - margin: { - bottom: 80, - }, + test('should render empty placeholder by custom icon and description style', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { + ...options, + frozen: {}, }, - description: { - fontSize: 20, - fill: 'red', + ); + + s2.setTheme({ + empty: { + icon: { + fill: 'green', + width: 100, + height: 100, + margin: { + bottom: 80, + }, + }, + description: { + fontSize: 20, + fill: 'red', + }, }, - }, + }); + + await expectEmptyPlaceholder(s2); }); - await expectEmptyPlaceholder(s2); + test('should render empty placeholder if contains horizontal scrollbar', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { ...options, frozen: {} }, + ); + + await expectEmptyPlaceholder(s2); + expect(s2.facet.hScrollBar.position).toEqual({ + x: 4, + y: 594, + }); + }); + + test('should render empty placeholder by custom col height', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { + options, + frozen: {}, + style: { + colCell: { + height: 200, + }, + }, + }, + ); + + await expectEmptyPlaceholder(s2); + }); }); }); diff --git a/packages/s2-core/src/facet/base-facet.ts b/packages/s2-core/src/facet/base-facet.ts index 9830bf468a..c0a6cc48c0 100644 --- a/packages/s2-core/src/facet/base-facet.ts +++ b/packages/s2-core/src/facet/base-facet.ts @@ -1022,7 +1022,7 @@ export abstract class BaseFacet { } }; - private getScrollbarPosition = () => { + protected getScrollbarPosition() { const { maxX, maxY } = this.panelBBox; const { width, height } = this.getCanvasSize(); const isContentMode = @@ -1031,9 +1031,9 @@ export abstract class BaseFacet { return { maxX: (isContentMode ? maxX : width) - this.scrollBarSize, - maxY: isContentMode ? maxY : height - this.scrollBarSize, + maxY: (isContentMode ? maxY : height) - this.scrollBarSize, }; - }; + } renderVScrollBar = (height: number, realHeight: number, scrollY: number) => { if (height < realHeight) { diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index eac215c2cd..a6b544c29f 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -743,6 +743,20 @@ export class TableFacet extends FrozenFacet { return null; } + protected getScrollbarPosition() { + const { height } = this.getCanvasSize(); + const position = super.getScrollbarPosition(); + // 滚动条有两种模式, 一种是根据实际内容撑开, 一种是根据 Canvas 高度撑开, 现在有空数据占位符, 对于这种, 滚动条需要撑满 + const maxY = this.spreadsheet.dataSet.isEmpty() + ? height - this.scrollBarSize + : position.maxY; + + return { + ...position, + maxY, + }; + } + /** * 获取序号单元格 * @description 明细表序号单元格是基于 DataCell 实现 diff --git a/packages/s2-react/playground/config.tsx b/packages/s2-react/playground/config.tsx index c65889f6fe..e95907d87d 100644 --- a/packages/s2-react/playground/config.tsx +++ b/packages/s2-react/playground/config.tsx @@ -320,7 +320,7 @@ export const s2Options: SheetComponentOptions = { placeholder: { cell: EMPTY_PLACEHOLDER, empty: { - icon: 'Trend', + icon: 'Empty', description: '暂无数据', }, }, @@ -392,7 +392,11 @@ export const s2Options: SheetComponentOptions = { // ], // ], tooltip: S2TooltipOptions, - style: {}, + style: { + colCell: { + width: 500, + }, + }, }; export const sliderOptions: SliderSingleProps = { From 9528521424fbcccd5bb2063e9c5adaf7dec5c9dd Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Fri, 17 May 2024 11:12:41 +0800 Subject: [PATCH 4/9] =?UTF-8?q?test:=20=E5=8D=95=E6=B5=8B=E5=92=8C?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/spread-sheet-spec.ts.snap | 8 +- .../__snapshots__/theme-spec.ts.snap | 120 ++++++++++++++++++ .../spreadsheet/miss-dimension-values-spec.ts | 8 +- .../unit/common/icons/factory-spec.ts | 2 +- .../utils/__snapshots__/merge-spec.ts.snap | 8 +- .../s2-core/__tests__/unit/utils/text-spec.ts | 6 +- s2-site/docs/manual/contribution.zh.md | 11 +- 7 files changed, 153 insertions(+), 10 deletions(-) diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/spread-sheet-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/spread-sheet-spec.ts.snap index 919cc5169c..359fac0ad8 100644 --- a/packages/s2-core/__tests__/spreadsheet/__snapshots__/spread-sheet-spec.ts.snap +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/spread-sheet-spec.ts.snap @@ -59,7 +59,13 @@ Object { "selectedCellHighlight": false, "selectedCellsSpotlight": false, }, - "placeholder": "-", + "placeholder": Object { + "cell": "-", + "empty": Object { + "description": "暂无数据", + "icon": "Empty", + }, + }, "seriesNumber": Object { "enable": false, }, diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/theme-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/theme-spec.ts.snap index 01e1e4b6d0..7c44b545ce 100644 --- a/packages/s2-core/__tests__/spreadsheet/__snapshots__/theme-spec.ts.snap +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/theme-spec.ts.snap @@ -259,6 +259,26 @@ Object { "textBaseline": "middle", }, }, + "empty": Object { + "description": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "opacity": 1, + }, + "icon": Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "width": 64, + }, + }, "mergedCell": Object { "bolderText": Object { "fill": "#000000", @@ -787,6 +807,26 @@ Object { "textBaseline": "middle", }, }, + "empty": Object { + "description": Object { + "fill": "#dcdcdc", + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "opacity": 1, + }, + "icon": Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "width": 64, + }, + }, "mergedCell": Object { "bolderText": Object { "fill": "#f0f0f0", @@ -1315,6 +1355,26 @@ Object { "textBaseline": "middle", }, }, + "empty": Object { + "description": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "opacity": 1, + }, + "icon": Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "width": 64, + }, + }, "mergedCell": Object { "bolderText": Object { "fill": "#000000", @@ -1843,6 +1903,26 @@ Object { "textBaseline": "middle", }, }, + "empty": Object { + "description": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "opacity": 1, + }, + "icon": Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "width": 64, + }, + }, "mergedCell": Object { "bolderText": Object { "fill": "#000000", @@ -2371,6 +2451,26 @@ Object { "textBaseline": "middle", }, }, + "empty": Object { + "description": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "opacity": 1, + }, + "icon": Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "width": 64, + }, + }, "mergedCell": Object { "bolderText": Object { "fill": "#000000", @@ -2899,6 +2999,26 @@ Object { "textBaseline": "middle", }, }, + "empty": Object { + "description": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "opacity": 1, + }, + "icon": Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "width": 64, + }, + }, "mergedCell": Object { "bolderText": Object { "fill": "#000000", diff --git a/packages/s2-core/__tests__/spreadsheet/miss-dimension-values-spec.ts b/packages/s2-core/__tests__/spreadsheet/miss-dimension-values-spec.ts index 7fd84b7ba9..61a54f9528 100644 --- a/packages/s2-core/__tests__/spreadsheet/miss-dimension-values-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/miss-dimension-values-spec.ts @@ -202,10 +202,12 @@ describe('Miss Dimension Values Tests', () => { }); test('should get correctly empty dimension values and use custom placeholder text', async () => { - const placeholder = '*'; + const cellPlaceholder = '*'; s2.setOptions({ - placeholder, + placeholder: { + cell: cellPlaceholder, + }, }); await s2.render(false); @@ -213,7 +215,7 @@ describe('Miss Dimension Values Tests', () => { const emptyDimensionValueNode = s2.facet.getRowNodes()[0].children[0]; expect(emptyDimensionValueNode.belongsCell!.getActualText()).toEqual( - placeholder, + cellPlaceholder, ); }); diff --git a/packages/s2-core/__tests__/unit/common/icons/factory-spec.ts b/packages/s2-core/__tests__/unit/common/icons/factory-spec.ts index 5c0c08edc1..8135dae1f5 100644 --- a/packages/s2-core/__tests__/unit/common/icons/factory-spec.ts +++ b/packages/s2-core/__tests__/unit/common/icons/factory-spec.ts @@ -6,7 +6,7 @@ describe('GuiIcon Factory Tests', () => { test('should get default icon', () => { const icons = keys(InternalSvgIcons); - expect(icons).toHaveLength(20); + expect(icons).toHaveLength(21); icons.forEach((name) => { expect(getIcon(name)).toBeTruthy(); }); diff --git a/packages/s2-core/__tests__/unit/utils/__snapshots__/merge-spec.ts.snap b/packages/s2-core/__tests__/unit/utils/__snapshots__/merge-spec.ts.snap index d2ff4b01d5..a3db939cca 100644 --- a/packages/s2-core/__tests__/unit/utils/__snapshots__/merge-spec.ts.snap +++ b/packages/s2-core/__tests__/unit/utils/__snapshots__/merge-spec.ts.snap @@ -59,7 +59,13 @@ Object { "selectedCellHighlight": false, "selectedCellsSpotlight": false, }, - "placeholder": "-", + "placeholder": Object { + "cell": "-", + "empty": Object { + "description": "暂无数据", + "icon": "Empty", + }, + }, "seriesNumber": Object { "enable": false, }, diff --git a/packages/s2-core/__tests__/unit/utils/text-spec.ts b/packages/s2-core/__tests__/unit/utils/text-spec.ts index 93b977a1e8..d77df9bbd0 100644 --- a/packages/s2-core/__tests__/unit/utils/text-spec.ts +++ b/packages/s2-core/__tests__/unit/utils/text-spec.ts @@ -84,7 +84,7 @@ describe('Text Utils Tests', () => { field: '', }; - const placeholder = getEmptyPlaceholder(meta, '*'); + const placeholder = getEmptyPlaceholder(meta, { cell: '*' }); expect(placeholder).toEqual('*'); }); @@ -95,7 +95,9 @@ describe('Text Utils Tests', () => { value: 'test', }; - const placeholder = getEmptyPlaceholder(meta, (meta) => meta['value']); + const placeholder = getEmptyPlaceholder(meta, { + cell: (meta) => meta['value'], + }); expect(placeholder).toEqual('test'); }); diff --git a/s2-site/docs/manual/contribution.zh.md b/s2-site/docs/manual/contribution.zh.md index 7b08452d41..4e55ea44c1 100644 --- a/s2-site/docs/manual/contribution.zh.md +++ b/s2-site/docs/manual/contribution.zh.md @@ -67,7 +67,7 @@ S2 基于 `AntV/G` 渲染引擎绘制,如果想像 DOM 一样调试的话, preview -1. 开始调试 +2. 开始调试 preview @@ -77,10 +77,17 @@ S2 基于 `AntV/G` 渲染引擎绘制,如果想像 DOM 一样调试的话, 1. 选择单测 -命令行运行 `pnpm core:start` 或者 `pnpm react:start` +命令行运行 `pnpm core:start` 或者 `pnpm react:start`, 可以选择测试来运行 preview +也可以指定具体的测试文件名,跳过选择的步骤直接运行。 + +```bash +pnpm core:start packages/s2-core/__tests__/spreadsheet/scroll-spec.ts +pnpm react:start packages/s2-react/__tests__/spreadsheet/spread-sheet-spec.tsx +``` + 2. 查看结果 因为本质上就是一个浏览器,如果单测结果不符合预期,可以正常打断点进行调试,快速分析原因。 From bbf26da72db08294ac7caf99de60c070eefece37 Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Fri, 17 May 2024 11:19:38 +0800 Subject: [PATCH 5/9] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=E6=BB=9A?= =?UTF-8?q?=E5=8A=A8=E6=9D=A1=E4=BD=8D=E7=BD=AE=E5=8D=95=E6=B5=8B=E6=96=AD?= =?UTF-8?q?=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/s2-core/__tests__/spreadsheet/scroll-spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/s2-core/__tests__/spreadsheet/scroll-spec.ts b/packages/s2-core/__tests__/spreadsheet/scroll-spec.ts index 3973a7241c..25e44d0127 100644 --- a/packages/s2-core/__tests__/spreadsheet/scroll-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/scroll-spec.ts @@ -468,8 +468,8 @@ describe('Scroll Tests', () => { s2.changeSheetSize(100, 1000); // 横向滚动条 await s2.render(false); - expect(s2.facet.hScrollBar.getBBox().y).toBe(225); - expect(s2.facet.hRowScrollBar.getBBox().y).toBe(225); + expect(s2.facet.hScrollBar.getBBox().y).toBe(219); + expect(s2.facet.hRowScrollBar.getBBox().y).toBe(219); s2.changeSheetSize(1000, 150); // 纵向滚动条 await s2.render(false); From 713d81aa71646fb917beba3f8bb8ceeaf1daf01b Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Fri, 17 May 2024 11:35:56 +0800 Subject: [PATCH 6/9] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=20shared=20?= =?UTF-8?q?=E5=8C=85=E5=BF=AB=E7=85=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unit/utils/__snapshots__/options-spec.ts.snap | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/s2-shared/__tests__/unit/utils/__snapshots__/options-spec.ts.snap b/packages/s2-shared/__tests__/unit/utils/__snapshots__/options-spec.ts.snap index 970df8d3bd..8e8402c2cd 100644 --- a/packages/s2-shared/__tests__/unit/utils/__snapshots__/options-spec.ts.snap +++ b/packages/s2-shared/__tests__/unit/utils/__snapshots__/options-spec.ts.snap @@ -78,7 +78,13 @@ Object { "selectedCellHighlight": false, "selectedCellsSpotlight": false, }, - "placeholder": "-", + "placeholder": Object { + "cell": "-", + "empty": Object { + "description": "暂无数据", + "icon": "Empty", + }, + }, "seriesNumber": Object { "enable": false, }, From 2c4178ea70b20cecf1910083137669b89df74984 Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Fri, 17 May 2024 16:48:33 +0800 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=8B=B1=E6=96=87?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E4=B8=8B=E6=9C=AA=E5=B1=95=E7=A4=BA=E8=8B=B1?= =?UTF-8?q?=E6=96=87=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/spread-sheet-spec.ts.snap | 1 - .../__snapshots__/table-sheet-spec.ts.snap | 59 +++++++++++++++++++ .../__tests__/spreadsheet/table-sheet-spec.ts | 13 ++++ .../utils/__snapshots__/merge-spec.ts.snap | 1 - .../s2-core/src/common/constant/options.ts | 1 - packages/s2-core/src/common/i18n/en_US.ts | 1 + packages/s2-core/src/common/i18n/zh_CN.ts | 1 + packages/s2-core/src/facet/table-facet.ts | 3 +- .../utils/__snapshots__/options-spec.ts.snap | 1 - 9 files changed, 76 insertions(+), 5 deletions(-) diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/spread-sheet-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/spread-sheet-spec.ts.snap index 359fac0ad8..0feb8e1aac 100644 --- a/packages/s2-core/__tests__/spreadsheet/__snapshots__/spread-sheet-spec.ts.snap +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/spread-sheet-spec.ts.snap @@ -62,7 +62,6 @@ Object { "placeholder": Object { "cell": "-", "empty": Object { - "description": "暂无数据", "icon": "Empty", }, }, diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap index cc9ab5fdd0..70dca01783 100644 --- a/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap @@ -236,6 +236,65 @@ Object { } `; +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder for en_US lang 1`] = ` +Object { + "height": 562, + "stroke": CSSRGB { + "alpha": 1, + "b": 253, + "colorSpace": "rgb", + "g": 233, + "isNone": false, + "r": 224, + }, + "strokeOpacity": 1, + "strokeWidth": 1, + "width": 799, + "x": 0, + "y": 32, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder for en_US lang 2`] = ` +Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "name": "Empty", + "width": 64, + "x": 367.5, + "y": 292.5, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder for en_US lang 3`] = ` +Object { + "fill": CSSRGB { + "alpha": 1, + "b": 0, + "colorSpace": "rgb", + "g": 0, + "isNone": false, + "r": 0, + }, + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontStyle": "normal", + "fontVariant": "normal", + "fontWeight": "normal", + "lineWidth": 1, + "opacity": 1, + "text": "No Data", + "x": 377.4892578125, + "y": 357.5, +} +`; + exports[`TableSheet normal spec Empty Placeholder should render empty placeholder if contains horizontal scrollbar 1`] = ` Object { "height": 562, diff --git a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts index 33ba4bab3d..defda3f51e 100644 --- a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts @@ -1,6 +1,7 @@ /* eslint-disable jest/expect-expect */ import { getContainer, getMockData, sleep } from 'tests/util/helpers'; import type { SpreadSheet, TableFacet } from '../../esm'; +import { setLang } from '../../src'; import { DeviceType, ResizeType, @@ -397,5 +398,17 @@ describe('TableSheet normal spec', () => { await expectEmptyPlaceholder(s2); }); + + test('should render empty placeholder for en_US lang', async () => { + setLang('en_US'); + + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { ...options, frozen: {} }, + ); + + await expectEmptyPlaceholder(s2); + }); }); }); diff --git a/packages/s2-core/__tests__/unit/utils/__snapshots__/merge-spec.ts.snap b/packages/s2-core/__tests__/unit/utils/__snapshots__/merge-spec.ts.snap index a3db939cca..a1fa020502 100644 --- a/packages/s2-core/__tests__/unit/utils/__snapshots__/merge-spec.ts.snap +++ b/packages/s2-core/__tests__/unit/utils/__snapshots__/merge-spec.ts.snap @@ -62,7 +62,6 @@ Object { "placeholder": Object { "cell": "-", "empty": Object { - "description": "暂无数据", "icon": "Empty", }, }, diff --git a/packages/s2-core/src/common/constant/options.ts b/packages/s2-core/src/common/constant/options.ts index 6a0562463d..73abc317e2 100644 --- a/packages/s2-core/src/common/constant/options.ts +++ b/packages/s2-core/src/common/constant/options.ts @@ -139,7 +139,6 @@ export const DEFAULT_OPTIONS: S2Options = { cell: EMPTY_PLACEHOLDER, empty: { icon: 'Empty', - description: '暂无数据', }, }, }; diff --git a/packages/s2-core/src/common/i18n/en_US.ts b/packages/s2-core/src/common/i18n/en_US.ts index fb88221d5c..4bf431de2c 100644 --- a/packages/s2-core/src/common/i18n/en_US.ts +++ b/packages/s2-core/src/common/i18n/en_US.ts @@ -15,5 +15,6 @@ export const EN_US = { 升序: 'ASC', 降序: 'DESC', 不排序: 'No order', + 暂无数据: 'No Data', ',': ', ', }; diff --git a/packages/s2-core/src/common/i18n/zh_CN.ts b/packages/s2-core/src/common/i18n/zh_CN.ts index 45913deb78..7dae96801a 100644 --- a/packages/s2-core/src/common/i18n/zh_CN.ts +++ b/packages/s2-core/src/common/i18n/zh_CN.ts @@ -16,5 +16,6 @@ export const ZH_CN = { 降序: '降序', 组内降序: '组内降序', 不排序: '不排序', + 暂无数据: '暂无数据', ',': ',', }; diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index a6b544c29f..93099fae16 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -40,6 +40,7 @@ import { getIndexRangeWithOffsets } from '../utils/facet'; import { getAllChildCells } from '../utils/get-all-child-cells'; import { getValidFrozenOptions } from '../utils/layout/frozen'; import { floor } from '../utils/math'; +import { i18n } from '../common'; import { CornerBBox } from './bbox/corner-bbox'; import { FrozenFacet } from './frozen-facet'; import { ColHeader, Frame } from './header'; @@ -103,7 +104,7 @@ export class TableFacet extends FrozenFacet { const { maxY, width, height } = this.panelBBox; const iconX = width / 2 - icon.width / 2; const iconY = height / 2 + maxY - icon.height / 2 + icon.margin.top; - const text = empty?.description || ''; + const text = empty?.description ?? i18n('暂无数据'); const descWidth = this.spreadsheet.measureTextWidth(text, description); const descX = width / 2 - descWidth / 2; const descY = iconY + icon.height + icon.margin.bottom; diff --git a/packages/s2-shared/__tests__/unit/utils/__snapshots__/options-spec.ts.snap b/packages/s2-shared/__tests__/unit/utils/__snapshots__/options-spec.ts.snap index 8e8402c2cd..fb966c7a85 100644 --- a/packages/s2-shared/__tests__/unit/utils/__snapshots__/options-spec.ts.snap +++ b/packages/s2-shared/__tests__/unit/utils/__snapshots__/options-spec.ts.snap @@ -81,7 +81,6 @@ Object { "placeholder": Object { "cell": "-", "empty": Object { - "description": "暂无数据", "icon": "Empty", }, }, From 73c56bb87ebfee3edef845e905ddfb7c7b311c2e Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Fri, 17 May 2024 17:34:56 +0800 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=88=97=E5=A4=B4?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E5=AE=BD=E5=BA=A6=E5=BE=88=E5=B0=8F?= =?UTF-8?q?=E6=97=B6=E5=8D=A0=E4=BD=8D=E7=AC=A6=E5=9D=90=E6=A0=87=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/table-sheet-spec.ts.snap | 59 +++++++++++++++++++ .../__tests__/spreadsheet/table-sheet-spec.ts | 18 ++++++ packages/s2-core/src/facet/table-facet.ts | 8 +-- packages/s2-react/playground/config.tsx | 6 +- 4 files changed, 82 insertions(+), 9 deletions(-) diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap index 70dca01783..73c1b4d610 100644 --- a/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/table-sheet-spec.ts.snap @@ -118,6 +118,65 @@ Object { } `; +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom col width 1`] = ` +Object { + "height": 442, + "stroke": CSSRGB { + "alpha": 1, + "b": 253, + "colorSpace": "rgb", + "g": 233, + "isNone": false, + "r": 224, + }, + "strokeOpacity": 1, + "strokeWidth": 1, + "width": 510, + "x": 0, + "y": 32, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom col width 2`] = ` +Object { + "fill": "", + "height": 41, + "margin": Object { + "bottom": 24, + "left": 0, + "right": 0, + "top": 0, + }, + "name": "Empty", + "width": 64, + "x": 223, + "y": 232.5, +} +`; + +exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom col width 3`] = ` +Object { + "fill": CSSRGB { + "alpha": 1, + "b": 0, + "colorSpace": "rgb", + "g": 0, + "isNone": false, + "r": 0, + }, + "fontFamily": "Roboto, PingFangSC, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontStyle": "normal", + "fontVariant": "normal", + "fontWeight": "normal", + "lineWidth": 1, + "opacity": 1, + "text": "暂无数据", + "x": 231, + "y": 297.5, +} +`; + exports[`TableSheet normal spec Empty Placeholder should render empty placeholder by custom icon and description 1`] = ` Object { "height": 562, diff --git a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts index defda3f51e..800a55359e 100644 --- a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.ts @@ -399,6 +399,24 @@ describe('TableSheet normal spec', () => { await expectEmptyPlaceholder(s2); }); + test('should render empty placeholder by custom col width', async () => { + const s2 = new TableSheet( + getContainer(), + { ...dataCfg, data: [] }, + { + options, + frozen: {}, + style: { + colCell: { + width: 30, + }, + }, + }, + ); + + await expectEmptyPlaceholder(s2); + }); + test('should render empty placeholder for en_US lang', async () => { setLang('en_US'); diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index 93099fae16..8b80fbd61a 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -101,12 +101,12 @@ export class TableFacet extends FrozenFacet { horizontalBorderColor, horizontalBorderColorOpacity, } = this.spreadsheet.theme.dataCell.cell!; - const { maxY, width, height } = this.panelBBox; - const iconX = width / 2 - icon.width / 2; + const { maxY, viewportWidth, height } = this.panelBBox; + const iconX = viewportWidth / 2 - icon.width / 2; const iconY = height / 2 + maxY - icon.height / 2 + icon.margin.top; const text = empty?.description ?? i18n('暂无数据'); const descWidth = this.spreadsheet.measureTextWidth(text, description); - const descX = width / 2 - descWidth / 2; + const descX = viewportWidth / 2 - descWidth / 2; const descY = iconY + icon.height + icon.margin.bottom; // 边框 @@ -114,7 +114,7 @@ export class TableFacet extends FrozenFacet { style: { x: 0, y: maxY, - width, + width: viewportWidth, height, stroke: horizontalBorderColor, strokeWidth: horizontalBorderWidth, diff --git a/packages/s2-react/playground/config.tsx b/packages/s2-react/playground/config.tsx index e95907d87d..77f4d8e001 100644 --- a/packages/s2-react/playground/config.tsx +++ b/packages/s2-react/playground/config.tsx @@ -392,11 +392,7 @@ export const s2Options: SheetComponentOptions = { // ], // ], tooltip: S2TooltipOptions, - style: { - colCell: { - width: 500, - }, - }, + style: {}, }; export const sliderOptions: SliderSingleProps = { From 25fb09b7f1a7bd14f306c71b06e4250e2b304a9c Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Fri, 17 May 2024 17:50:13 +0800 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=B6=8B=E5=8A=BF?= =?UTF-8?q?=E5=88=86=E6=9E=90=E8=A1=A8=E5=AF=BC=E5=87=BA=E5=8D=A0=E4=BD=8D?= =?UTF-8?q?=E7=AC=A6=E8=A7=A3=E6=9E=90=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/export/strategy-copy.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/packages/s2-react/src/components/export/strategy-copy.ts b/packages/s2-react/src/components/export/strategy-copy.ts index 689a61ea8e..c86a528695 100644 --- a/packages/s2-react/src/components/export/strategy-copy.ts +++ b/packages/s2-react/src/components/export/strategy-copy.ts @@ -1,6 +1,7 @@ import { PivotDataCellCopy, assembleMatrix, + getEmptyPlaceholder, getHeaderList, getNodeFormatData, safeJsonParse, @@ -10,16 +11,7 @@ import { type SheetCopyConstructorParams, type ViewMeta, } from '@antv/s2'; -import { - flatten, - forEach, - get, - isArray, - isFunction, - isNil, - isObject, - map, -} from 'lodash'; +import { flatten, forEach, get, isArray, isNil, isObject, map } from 'lodash'; /** * Process the multi-measure with single-lines @@ -53,10 +45,8 @@ class StrategyCopyData extends PivotDataCellCopy { private getPlaceholder = (viewMeta: ViewMeta, leafNode: Node) => { const label = getHeaderLabel(leafNode.value); const labelLength = isArray(label) ? label.length : 1; - const placeholder = this.spreadsheet.options.placeholder; - const placeholderStr = isFunction(placeholder) - ? placeholder(viewMeta) - : placeholder; + const { placeholder } = this.spreadsheet.options; + const placeholderStr = getEmptyPlaceholder(viewMeta, placeholder); return Array(labelLength).fill(placeholderStr); };