From 23d15ff61f56477595229386149f5bbff0cb5bd6 Mon Sep 17 00:00:00 2001 From: lijinke666 Date: Thu, 30 Nov 2023 17:12:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=88=B7=E9=80=89?= =?UTF-8?q?=E6=97=B6=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E7=9A=84=20tooltip=20=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cell/__snapshots__/data-cell-spec.ts.snap | 6 +-- .../__tests__/unit/cell/data-cell-spec.ts | 15 ++++++ .../__tests__/unit/utils/tooltip-spec.ts | 38 ++++++++++++- packages/s2-core/src/cell/data-cell.ts | 46 ++++++++++------ .../utils/export/copy/pivot-data-cell-copy.ts | 20 ++++--- packages/s2-core/src/utils/tooltip.ts | 9 +++- .../sheets/chart-sheet/index-spec.tsx | 25 +-------- .../playground/components/ChartSheet.tsx | 1 + packages/s2-react/playground/config.tsx | 2 + packages/s2-react/playground/index.tsx | 54 +++++++++++++++++++ .../components/sheets/chart-sheet/index.tsx | 11 ---- 11 files changed, 163 insertions(+), 64 deletions(-) diff --git a/packages/s2-core/__tests__/unit/cell/__snapshots__/data-cell-spec.ts.snap b/packages/s2-core/__tests__/unit/cell/__snapshots__/data-cell-spec.ts.snap index 6e7840e4aa..1c3989532b 100644 --- a/packages/s2-core/__tests__/unit/cell/__snapshots__/data-cell-spec.ts.snap +++ b/packages/s2-core/__tests__/unit/cell/__snapshots__/data-cell-spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Cell Tests Data Cell Formatter & Method Tests should get empty chart data 1`] = ` +exports[`Data Cell Tests Data Cell Formatter & Method Tests should get empty chart data and default options 1`] = ` Object { "autoFit": true, "height": 83, @@ -13,7 +13,7 @@ Object { } `; -exports[`Data Cell Tests Data Cell Formatter & Method Tests should get multiple chart data 1`] = ` +exports[`Data Cell Tests Data Cell Formatter & Method Tests should get multiple chart data and all options 1`] = ` Object { "autoFit": true, "data": Array [ @@ -31,7 +31,7 @@ Object { } `; -exports[`Data Cell Tests Data Cell Formatter & Method Tests should get multiple chart data 2`] = ` +exports[`Data Cell Tests Data Cell Formatter & Method Tests should get multiple chart data and all options 2`] = ` Object { "autoFit": true, "data": Array [ diff --git a/packages/s2-core/__tests__/unit/cell/data-cell-spec.ts b/packages/s2-core/__tests__/unit/cell/data-cell-spec.ts index 6629357e02..096ccf74bf 100644 --- a/packages/s2-core/__tests__/unit/cell/data-cell-spec.ts +++ b/packages/s2-core/__tests__/unit/cell/data-cell-spec.ts @@ -142,10 +142,24 @@ describe('Data Cell Tests', () => { const dataCell = new DataCell(meta, s2); expect(dataCell.isMultiData()).toBeFalsy(); + expect(dataCell.isChartData()).toBeFalsy(); expect(dataCell.getRenderChartData()).toBeUndefined(); expect(dataCell.getRenderChartOptions()).toMatchSnapshot(); }); + test('should get correctly cell data status', () => { + const multipleMeta = { + fieldValue: { + values: [1, 2, 3], + }, + } as unknown as ViewMeta; + + const dataCell = new DataCell(multipleMeta, s2); + + expect(dataCell.isMultiData()).toBeTruthy(); + expect(dataCell.isChartData()).toBeFalsy(); + }); + test('should get multiple chart data and all options', () => { s2.setThemeCfg({ name: 'dark' }); @@ -177,6 +191,7 @@ describe('Data Cell Tests', () => { const dataCell = new DataCell(multipleMeta, s2); expect(dataCell.isMultiData()).toBeTruthy(); + expect(dataCell.isChartData()).toBeTruthy(); expect(dataCell.getRenderChartData()).toMatchSnapshot(); expect(dataCell.getRenderChartOptions()).toMatchSnapshot(); }); diff --git a/packages/s2-core/__tests__/unit/utils/tooltip-spec.ts b/packages/s2-core/__tests__/unit/utils/tooltip-spec.ts index 93d4283a4e..d0a348b6a5 100644 --- a/packages/s2-core/__tests__/unit/utils/tooltip-spec.ts +++ b/packages/s2-core/__tests__/unit/utils/tooltip-spec.ts @@ -34,6 +34,7 @@ import { PivotSheet, type S2DataConfig, type S2Options, + type TooltipOperatorMenuItems, } from '@/index'; import type { BaseFacet } from '@/facet/base-facet'; import type { BBox } from '@/engine'; @@ -256,6 +257,9 @@ describe('Tooltip Utils Tests', () => { options: { tooltip, }, + interaction: { + getInteractedCells: jest.fn(() => []), + }, } as unknown as SpreadSheet; expect(getTooltipOptions(spreadsheet, {} as Event)).toEqual({ @@ -306,6 +310,9 @@ describe('Tooltip Utils Tests', () => { options: { tooltip, }, + interaction: { + getInteractedCells: jest.fn(() => []), + }, } as unknown as SpreadSheet; const tooltipOptions = omit( @@ -330,16 +337,43 @@ describe('Tooltip Utils Tests', () => { }, ); + test('should use interacted cell type if cannot get current cell type', () => { + const mockInteractedCell = { cellType: CellType.DATA_CELL }; + + const tooltip: Tooltip = { + enable: true, + [CellType.DATA_CELL]: { + enable: false, + }, + content: '', + operation: {}, + }; + + const spreadsheet = { + getCellType: () => undefined, + options: { + tooltip, + }, + interaction: { + getInteractedCells: jest.fn(() => [mockInteractedCell]), + }, + } as unknown as SpreadSheet; + + const tooltipOptions = getTooltipOptions(spreadsheet, {} as Event); + + expect(tooltipOptions?.enable).toBeFalsy(); + }); + test('should filter not displayed tooltip operation menus', () => { const mockCell = { cellType: CellType.DATA_CELL, } as unknown as S2CellType; const onClick = jest.fn(); - const defaultMenus = [ + const defaultMenus: TooltipOperatorMenuItems = [ { key: 'default-menu', - text: 'default-menu', + label: 'default-menu', }, ]; diff --git a/packages/s2-core/src/cell/data-cell.ts b/packages/s2-core/src/cell/data-cell.ts index 089928a5fa..35f6ea7bbc 100644 --- a/packages/s2-core/src/cell/data-cell.ts +++ b/packages/s2-core/src/cell/data-cell.ts @@ -7,34 +7,38 @@ import { isEmpty, isEqual, isObject, + isPlainObject, merge, } from 'lodash'; import { BaseCell } from '../cell/base-cell'; +import { EMPTY_PLACEHOLDER } from '../common/constant/basic'; import { CellType, InteractionStateName, SHAPE_STYLE_MAP, } from '../common/constant/interaction'; -import { - CellBorderPosition, - CellClipBox, - type HeaderActionNameOptions, - type IconCondition, - type InteractionStateTheme, - type RenderTextShapeOptions, -} from '../common/interface'; import type { + BaseChartData, CellMeta, Condition, - FormatResult, ConditionMappingResult, + FormatResult, + MiniChartData, + MultiData, TextTheme, + ThemeName, ViewMeta, ViewMetaIndexType, - MultiData, - BaseChartData, - ThemeName, } from '../common/interface'; +import { + CellBorderPosition, + CellClipBox, + type HeaderActionNameOptions, + type IconCondition, + type InteractionStateTheme, + type RenderTextShapeOptions, +} from '../common/interface'; +import { getFieldValueOfViewMetaData } from '../data-set/cell-data'; import { getHorizontalTextIconPosition, getVerticalIconPosition, @@ -45,12 +49,10 @@ import { shouldUpdateBySelectedCellsHighlight, updateBySelectedCellsHighlight, } from '../utils/cell/data-cell'; +import { groupIconsByPosition } from '../utils/cell/header-cell'; import { getIconPosition } from '../utils/condition/condition'; -import { updateShapeAttr } from '../utils/g-renders'; -import { EMPTY_PLACEHOLDER } from '../common/constant/basic'; import { drawInterval } from '../utils/g-mini-charts'; -import { getFieldValueOfViewMetaData } from '../data-set/cell-data'; -import { groupIconsByPosition } from '../utils/cell/header-cell'; +import { updateShapeAttr } from '../utils/g-renders'; import type { RawData } from './../common/interface/s2DataConfig'; /** @@ -74,7 +76,17 @@ export class DataCell extends BaseCell { } public isMultiData() { - return isObject(this.getMeta().fieldValue); + const fieldValue = this.getFieldValue(); + + return isObject(fieldValue); + } + + public isChartData() { + const fieldValue = this.getFieldValue(); + + return isPlainObject( + (fieldValue as unknown as MultiData)?.values, + ); } public getRenderChartData(): BaseChartData { diff --git a/packages/s2-core/src/utils/export/copy/pivot-data-cell-copy.ts b/packages/s2-core/src/utils/export/copy/pivot-data-cell-copy.ts index 8e5bcafe3c..1df16a9f85 100644 --- a/packages/s2-core/src/utils/export/copy/pivot-data-cell-copy.ts +++ b/packages/s2-core/src/utils/export/copy/pivot-data-cell-copy.ts @@ -1,16 +1,18 @@ -import { find, isEmpty, map, slice, zip } from 'lodash'; +import { find, isEmpty, isPlainObject, map, slice, zip } from 'lodash'; import { AsyncRenderThreshold, - type CellMeta, - type DataItem, EXTRA_FIELD, VALUE_FIELD, + type CellMeta, + type DataItem, + type MiniChartData, + type MultiData, } from '../../../common'; import type { Node } from '../../../facet/layout/node'; import type { SpreadSheet } from '../../../sheet-type'; import type { - CopyableList, CopyAllDataParams, + CopyableList, MeasureQuery, SheetCopyConstructorParams, } from '../interface'; @@ -22,6 +24,7 @@ import { getSelectedRows, } from '../method'; import type { BaseDataSet } from './../../../data-set/base-data-set'; +import { BaseDataCellCopy } from './base-data-cell-copy'; import { assembleMatrix, completeMatrix, @@ -30,7 +33,6 @@ import { getNodeFormatData, } from './common'; import { getHeaderNodeFromMeta } from './core'; -import { BaseDataCellCopy } from './base-data-cell-copy'; export class PivotDataCellCopy extends BaseDataCellCopy { protected leafRowNodes: Node[] = []; @@ -229,7 +231,13 @@ export class PivotDataCellCopy extends BaseDataCellCopy { dataSet, ); - return formatter(cellData?.[VALUE_FIELD] ?? ''); + const fieldValue = cellData?.[VALUE_FIELD]; + const isChartData = isPlainObject( + (fieldValue as MultiData)?.values, + ); + const value = isChartData ? '' : fieldValue; + + return formatter(value ?? ''); }; protected getCornerMatrix = (rowMatrix?: string[][]): string[][] => { diff --git a/packages/s2-core/src/utils/tooltip.ts b/packages/s2-core/src/utils/tooltip.ts index ace09ccb27..f061b29c34 100644 --- a/packages/s2-core/src/utils/tooltip.ts +++ b/packages/s2-core/src/utils/tooltip.ts @@ -704,9 +704,16 @@ export const getTooltipOptions = ( return null; } + const { options, interaction } = spreadsheet; const cellType = spreadsheet.getCellType?.(event?.target); - return getTooltipOptionsByCellType(spreadsheet.options.tooltip!, cellType!); + // 如果没有 cellType, 说明是刷选丢失 event target 的场景, 此时从产生过交互状态的单元格里取, 避免刷选读取不到争取 tooltip 配置的问题 + const sampleCell = interaction.getInteractedCells()[0]; + + return getTooltipOptionsByCellType( + options.tooltip!, + cellType || sampleCell.cellType!, + ); }; export const getTooltipVisibleOperator = ( diff --git a/packages/s2-react/__tests__/unit/components/sheets/chart-sheet/index-spec.tsx b/packages/s2-react/__tests__/unit/components/sheets/chart-sheet/index-spec.tsx index 2ab4740644..af8d465bb1 100644 --- a/packages/s2-react/__tests__/unit/components/sheets/chart-sheet/index-spec.tsx +++ b/packages/s2-react/__tests__/unit/components/sheets/chart-sheet/index-spec.tsx @@ -6,7 +6,7 @@ import { waitFor } from '@testing-library/react'; import React from 'react'; import type { Root } from 'react-dom/client'; import { ChartDataConfig } from '../../../../data/data-g2-chart'; -import { renderComponent, sleep } from '../../../../util/helpers'; +import { renderComponent } from '../../../../util/helpers'; import { SheetComponent, type SheetComponentOptions, @@ -79,27 +79,4 @@ describe(' Tests', () => { }); }); }); - - test('should not throw g2 error after render chart', async () => { - const errorSpy = jest - .spyOn(console, 'error') - .mockImplementationOnce(() => {}); - - renderChartSheet(null, { - onDataCellRender, - }); - - await waitFor(async () => { - s2.updateScrollOffset({ offsetY: { value: 800, animate: true } }); - - await sleep(1000); - - expect(errorSpy).not.toHaveBeenCalledWith( - `Uncaught (in promise) TypeError: Cannot read property 'defaultView' of null`, - ); - expect(errorSpy).not.toHaveBeenCalledWith( - `Uncaught (in promise) TypeError: Cannot read properties of null (reading 'createElement')`, - ); - }); - }); }); diff --git a/packages/s2-react/playground/components/ChartSheet.tsx b/packages/s2-react/playground/components/ChartSheet.tsx index 81ad024054..7816e9b1de 100644 --- a/packages/s2-react/playground/components/ChartSheet.tsx +++ b/packages/s2-react/playground/components/ChartSheet.tsx @@ -14,6 +14,7 @@ const options: SheetComponentOptions = { height: 900, interaction: { enableCopy: true, + copyWithFormat: true, brushSelection: { rowCell: true, colCell: true, diff --git a/packages/s2-react/playground/config.tsx b/packages/s2-react/playground/config.tsx index d9eb67f4a5..54f7066879 100644 --- a/packages/s2-react/playground/config.tsx +++ b/packages/s2-react/playground/config.tsx @@ -215,6 +215,7 @@ export const TableSheetFrozenOptions: S2TableSheetFrozenOptions = { }; export const S2TooltipOptions: SheetComponentOptions['tooltip'] = { + enable: true, operation: { hiddenColumns: true, menu: { @@ -287,6 +288,7 @@ export const s2Options: SheetComponentOptions = { cornerText: '测试测试测试测试测试测试测试测试测试测试', interaction: { enableCopy: true, + copyWithFormat: true, // 防止 mac 触摸板横向滚动触发浏览器返回, 和移动端下拉刷新 overscrollBehavior: 'none', brushSelection: { diff --git a/packages/s2-react/playground/index.tsx b/packages/s2-react/playground/index.tsx index 519e83e4f7..ec83c917f4 100644 --- a/packages/s2-react/playground/index.tsx +++ b/packages/s2-react/playground/index.tsx @@ -1093,6 +1093,60 @@ function MainLayout() { + + + 复制 + + + + { + updateOptions({ + interaction: { + enableCopy: checked, + }, + }); + }} + /> + + + { + updateOptions({ + interaction: { + copyWithHeader: checked, + }, + }); + }} + /> + + + { + updateOptions({ + interaction: { + copyWithFormat: checked, + }, + }); + }} + /> + + ), }, diff --git a/packages/s2-react/src/components/sheets/chart-sheet/index.tsx b/packages/s2-react/src/components/sheets/chart-sheet/index.tsx index ad7d9b1559..d134fd98a6 100644 --- a/packages/s2-react/src/components/sheets/chart-sheet/index.tsx +++ b/packages/s2-react/src/components/sheets/chart-sheet/index.tsx @@ -27,18 +27,7 @@ export const ChartSheet: React.FC = React.memo( height: 400, }, }, - // TODO: 刷选时获取不到正确的 tooltip 配置 tooltip: { - // cornerCell: { - // enable: true, - // }, - // colCell: { - // enable: true, - // }, - // rowCell: { - // enable: true, - // }, - // enable: false, enable: true, }, };