From 2d14ebb146c4837ee16eb25259bc3c5b58191c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=98=A4=E5=98=A4=E5=98=A4?= Date: Sat, 18 Sep 2021 15:23:17 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20separate=20Tab?= =?UTF-8?q?leSheet=20and=20PivotSheet=20from=20the=20SpreadSheet=20and=20c?= =?UTF-8?q?lose=20=20#301=20(#310)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: :recycle: add TableSheet and PivotSheet based on the SpreadSheet * refactor: :recycle: remove the mode from S2Options * chore: :white_check_mark: add test for checking sheetType switch * chore: :pencil2: correct type defination * fix: optimize the pagination --- README.en-US.md | 4 +- README.md | 4 +- packages/s2-core/README.en-US.md | 4 +- packages/s2-core/README.md | 4 +- .../s2-core/__tests__/bugs/issue-285-spec.tsx | 2 +- .../spreadsheet/custom-tree-header-spec.tsx | 12 +- .../spreadsheet/layout-hooks-spec.tsx | 8 +- .../spreadsheet/merge-cells-spec.tsx | 22 +- .../spreadsheet/multiple-values-cell-spec.tsx | 4 +- .../spreadsheet/part-drill-down-spec.tsx | 1 - .../spreadsheet/pressure-test-spec.tsx | 5 +- .../spreadsheet/spread-sheet-spec.tsx | 39 +- .../spreadsheet/table-sheet-spec.tsx | 10 +- .../spreadsheet/tabularSheet-spec.tsx | 4 +- .../unit/data-accuracy-one-measure-spec.tsx | 4 +- .../unit/data-accuracy-two-measures-spec.tsx | 4 +- .../unit/data-process/pivot-spec.tsx | 4 +- .../unit/data-process/table-spec.tsx | 6 +- .../dataset/pivot-dataset-row-value-spec.ts | 16 +- .../unit/dataset/pivot-dataset-spec.ts | 16 +- .../unit/dataset/pivot-dataset-total-spec.ts | 16 +- .../unit/dataset/table-dataset-spec.ts | 8 +- .../unit/interaction/brush-selection-spec.ts | 3 +- .../build-table-hierarchy-spec.tsx.snap | 425 ++++-------- .../unit/utils/build-table-hierarchy-spec.tsx | 3 +- .../s2-core/__tests__/util/sheet-entry.tsx | 19 +- .../s2-core/src/common/interface/basic.ts | 2 +- .../s2-core/src/common/interface/s2Options.ts | 3 - packages/s2-core/src/components/index.tsx | 10 +- .../components/sheets/base-sheet/index.tsx | 9 +- .../src/components/sheets/interface.ts | 5 + .../components/sheets/table-sheet/index.tsx | 279 ++++++++ .../components/sheets/tabular-sheet/index.tsx | 4 +- packages/s2-core/src/facet/table-facet.ts | 95 +-- packages/s2-core/src/index.ts | 6 +- packages/s2-core/src/sheet-type/index.ts | 655 +----------------- .../s2-core/src/sheet-type/pivot-sheet.ts | 145 ++++ .../s2-core/src/sheet-type/spread-sheet.ts | 514 ++++++++++++++ .../s2-core/src/sheet-type/table-sheet.ts | 127 ++++ s2-site/examples/basic/pivot/demo/grid.ts | 4 +- s2-site/examples/basic/pivot/demo/tree.ts | 4 +- yarn.lock | 95 ++- 42 files changed, 1436 insertions(+), 1168 deletions(-) create mode 100644 packages/s2-core/src/components/sheets/table-sheet/index.tsx create mode 100644 packages/s2-core/src/sheet-type/pivot-sheet.ts create mode 100644 packages/s2-core/src/sheet-type/spread-sheet.ts create mode 100644 packages/s2-core/src/sheet-type/table-sheet.ts diff --git a/README.en-US.md b/README.en-US.md index d23cef5261..48953cc71a 100644 --- a/README.en-US.md +++ b/README.en-US.md @@ -138,12 +138,12 @@ const s2options = { ``` ```ts -import { SpreadSheet } from '@antv/s2'; +import { PivotSheet } from '@antv/s2'; import '@antv/s2/dist/s2.min.css' const container = document.getElementById('container'); -const s2 = new SpreadSheet(container, s2DataCfg, s2options) +const s2 = new PivotSheet(container, s2DataCfg, s2options) s2.render() ``` diff --git a/README.md b/README.md index 2d114084ca..8f7a13a5c4 100644 --- a/README.md +++ b/README.md @@ -134,12 +134,12 @@ const s2options = { ``` ```ts -import { SpreadSheet } from '@antv/s2'; +import { PivotSheet } from '@antv/s2'; import '@antv/s2/dist/s2.min.css' const container = document.getElementById('container'); -const s2 = new SpreadSheet(container, s2DataConfig, s2options) +const s2 = new PivotSheet(container, s2DataConfig, s2options) s2.render() ``` diff --git a/packages/s2-core/README.en-US.md b/packages/s2-core/README.en-US.md index db1848b6df..92c13216e5 100644 --- a/packages/s2-core/README.en-US.md +++ b/packages/s2-core/README.en-US.md @@ -138,12 +138,12 @@ const s2options = { ``` ```ts -import { SpreadSheet } from '@antv/s2'; +import { PivotSheet } from '@antv/s2'; import '@antv/s2/dist/s2.min.css' const container = document.getElementById('container'); -const s2 = new SpreadSheet(container, s2DataCfg, s2options) +const s2 = new PivotSheet(container, s2DataCfg, s2options) s2.render() ``` diff --git a/packages/s2-core/README.md b/packages/s2-core/README.md index cea1cfc91c..4dc453951e 100644 --- a/packages/s2-core/README.md +++ b/packages/s2-core/README.md @@ -135,12 +135,12 @@ const s2options = { ``` ```ts -import { SpreadSheet } from '@antv/s2'; +import { PivotSheet } from '@antv/s2'; import '@antv/s2/dist/s2.min.css' const container = document.getElementById('container'); -const s2 = new SpreadSheet(container, s2DataConfig, s2options) +const s2 = new PivotSheet(container, s2DataConfig, s2options) s2.render() ``` diff --git a/packages/s2-core/__tests__/bugs/issue-285-spec.tsx b/packages/s2-core/__tests__/bugs/issue-285-spec.tsx index e45fd8a219..6d6bc1f0ed 100644 --- a/packages/s2-core/__tests__/bugs/issue-285-spec.tsx +++ b/packages/s2-core/__tests__/bugs/issue-285-spec.tsx @@ -30,7 +30,7 @@ function MainLayout() { dataCfg={dataCfg} options={{}} themeCfg={{ name: 'default' }} - forceUpdate={true} + forceUpdateDataCfg={true} header={ { - return new SpreadSheet(dom, dataCfg, options); + return new PivotSheet(dom, dataCfg, options); }; const getDataCfg = () => { @@ -50,7 +47,6 @@ const getOptions = () => { hierarchyType: 'customTree', hierarchyCollapse: false, freezeRowHeader: false, - mode: 'pivot', style: { treeRowsWidth: 120, collapsedRows: {}, diff --git a/packages/s2-core/__tests__/spreadsheet/layout-hooks-spec.tsx b/packages/s2-core/__tests__/spreadsheet/layout-hooks-spec.tsx index 7f65e35344..87f31d3e28 100644 --- a/packages/s2-core/__tests__/spreadsheet/layout-hooks-spec.tsx +++ b/packages/s2-core/__tests__/spreadsheet/layout-hooks-spec.tsx @@ -2,6 +2,7 @@ import { act } from 'react-dom/test-utils'; import 'antd/dist/antd.min.css'; import ReactDOM from 'react-dom'; import React from 'react'; +import { getContainer, getMockData } from '../util/helpers'; import { GetCellMeta, Node, @@ -9,10 +10,10 @@ import { S2Options, SheetComponent, SpreadSheet, + PivotSheet, SpreadSheetFacetCfg, ViewMeta, -} from '../../src'; -import { getContainer, getMockData } from '../util/helpers'; +} from '@/index'; import { LayoutHierarchyReturnType } from '@/common/interface/hooks'; import { generateId } from '@/utils/layout/generate-id'; const data = getMockData('../data/tableau-supermarket.csv'); @@ -23,7 +24,7 @@ const getSpreadSheet = ( dataCfg: S2DataConfig, options: S2Options, ) => { - innerSS = new SpreadSheet(dom, dataCfg, options); + innerSS = new PivotSheet(dom, dataCfg, options); return innerSS; }; @@ -160,7 +161,6 @@ const getOptions = () => { hierarchyType: 'grid', hierarchyCollapse: false, freezeRowHeader: true, - mode: 'pivot', style: { treeRowsWidth: 120, collapsedRows: {}, diff --git a/packages/s2-core/__tests__/spreadsheet/merge-cells-spec.tsx b/packages/s2-core/__tests__/spreadsheet/merge-cells-spec.tsx index 3ac870e4b9..380bd4d8c8 100644 --- a/packages/s2-core/__tests__/spreadsheet/merge-cells-spec.tsx +++ b/packages/s2-core/__tests__/spreadsheet/merge-cells-spec.tsx @@ -12,7 +12,8 @@ import { S2DataConfig, S2Options, SheetComponent, - SpreadSheet, + PivotSheet, + SheetType, } from '@/index'; let data = getMockData('../data/tableau-supermarket.csv'); @@ -30,7 +31,7 @@ const getSpreadSheet = ( dataCfg: S2DataConfig, options: S2Options, ) => { - return new SpreadSheet(dom, dataCfg, options); + return new PivotSheet(dom, dataCfg, options); }; const baseDataCfg: S2DataConfig = { @@ -103,7 +104,6 @@ const baseOptions = { hierarchyCollapse: false, showSeriesNumber: true, freezeRowHeader: false, - mode: 'pivot', valueInCols: true, conditions: { text: [], @@ -339,31 +339,31 @@ const tabularOptions = { ], } as S2Options; -const getDataCfg = (sheetType: 'base' | 'tabular') => { +const getDataCfg = (sheetType: SheetType) => { switch (sheetType) { case 'tabular': return tabularDataCfg; - case 'base': + case 'pivot': default: return baseDataCfg; } }; -const getOptions = (sheetType: 'base' | 'tabular') => { +const getOptions = (sheetType: SheetType) => { switch (sheetType) { case 'tabular': return tabularOptions; - case 'base': + case 'pivot': default: return baseOptions; } }; function MainLayout() { - const [sheetType, setSheetType] = React.useState<'base' | 'tabular'>('base'); - const [options, setOptions] = React.useState(getOptions('base')); + const [sheetType, setSheetType] = React.useState('pivot'); + const [options, setOptions] = React.useState(getOptions('pivot')); const [dataCfg, setDataCfg] = React.useState( - getDataCfg('base'), + getDataCfg('pivot'), ); let sheet; @@ -408,7 +408,7 @@ function MainLayout() { }; const onCheckChanged = (checked) => { - const type = checked ? 'base' : 'tabular'; + const type = checked ? 'pivot' : 'tabular'; setSheetType(type); setDataCfg(getDataCfg(type)); setOptions(getOptions(type)); diff --git a/packages/s2-core/__tests__/spreadsheet/multiple-values-cell-spec.tsx b/packages/s2-core/__tests__/spreadsheet/multiple-values-cell-spec.tsx index f16fee6be0..820679ad24 100644 --- a/packages/s2-core/__tests__/spreadsheet/multiple-values-cell-spec.tsx +++ b/packages/s2-core/__tests__/spreadsheet/multiple-values-cell-spec.tsx @@ -9,6 +9,7 @@ import { S2Options, SheetComponent, SpreadSheet, + PivotSheet, } from '../../src'; import { multipleDataWithBottom, @@ -23,7 +24,7 @@ const getSpreadSheet = ( dataCfg: S2DataConfig, options: S2Options, ) => { - sheet = new SpreadSheet(dom, dataCfg, options); + sheet = new PivotSheet(dom, dataCfg, options); (window as any).sheet = sheet; return sheet; }; @@ -84,7 +85,6 @@ const getOptions = (): S2Options => { hierarchyCollapse: false, showSeriesNumber: true, freezeRowHeader: false, - mode: 'pivot', conditions: { text: [], interval: [ diff --git a/packages/s2-core/__tests__/spreadsheet/part-drill-down-spec.tsx b/packages/s2-core/__tests__/spreadsheet/part-drill-down-spec.tsx index 57b08ae7cc..cd351ea907 100644 --- a/packages/s2-core/__tests__/spreadsheet/part-drill-down-spec.tsx +++ b/packages/s2-core/__tests__/spreadsheet/part-drill-down-spec.tsx @@ -52,7 +52,6 @@ const getOptions = () => { hierarchyCollapse: false, showSeriesNumber: false, freezeRowHeader: false, - mode: 'pivot', style: { treeRowsWidth: 100, collapsedRows: {}, diff --git a/packages/s2-core/__tests__/spreadsheet/pressure-test-spec.tsx b/packages/s2-core/__tests__/spreadsheet/pressure-test-spec.tsx index 086c4e99ac..696b640b23 100644 --- a/packages/s2-core/__tests__/spreadsheet/pressure-test-spec.tsx +++ b/packages/s2-core/__tests__/spreadsheet/pressure-test-spec.tsx @@ -7,7 +7,7 @@ import { S2DataConfig, S2Options, SheetComponent, - SpreadSheet, + PivotSheet, } from '../../src'; import { getContainer } from '../util/helpers'; @@ -29,7 +29,7 @@ const getSpreadSheet = ( dataCfg: S2DataConfig, options: S2Options, ) => { - return new SpreadSheet(dom, dataCfg, options); + return new PivotSheet(dom, dataCfg, options); }; const getDataCfg = () => { @@ -61,7 +61,6 @@ const getOptions = () => { hierarchyCollapse: false, showSeriesNumber: false, freezeRowHeader: false, - mode: 'pivot', totals: { row: { showGrandTotals: true, diff --git a/packages/s2-core/__tests__/spreadsheet/spread-sheet-spec.tsx b/packages/s2-core/__tests__/spreadsheet/spread-sheet-spec.tsx index f19b53ea45..f670095e3c 100644 --- a/packages/s2-core/__tests__/spreadsheet/spread-sheet-spec.tsx +++ b/packages/s2-core/__tests__/spreadsheet/spread-sheet-spec.tsx @@ -3,18 +3,27 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { act } from 'react-dom/test-utils'; import { getContainer } from '../util/helpers'; -import { SheetEntry } from '../util/sheet-entry'; +import { SheetEntry, assembleDataCfg } from '../util/sheet-entry'; +// import * as tableData from '../data/mock-dataset.json'; import { CustomTooltip } from './custom/custom-tooltip'; -import { ThemeName } from '@/index'; +import { ThemeName, SheetType } from '@/index'; + +const tableDataFields = { + fields: { + columns: ['province', 'city', 'type', 'sub_type', 'price'], + valueInCols: true, + }, +}; function MainLayout() { + const [dataCfg, setDataCfg] = React.useState(assembleDataCfg({})); const [render, setRender] = React.useState(true); - + const [sheetType, setSheetType] = React.useState('pivot'); const [spotLight, setSpotLight] = React.useState(true); + const [isPivotSheet, setIsPivotSheet] = React.useState(true); const [hoverHighlight, setHoverHighlight] = React.useState(true); const [showPagination, setShowPagination] = React.useState(false); const [showTooltip, setShowTooltip] = React.useState(true); - const [themeName, setThemeName] = React.useState('default'); const onToggleRender = () => { @@ -38,6 +47,19 @@ function MainLayout() { selectedCellsSpotlight: spotLight, hoverHighlight: hoverHighlight, }; + + const onSheetTypeChange = (checked) => { + setIsPivotSheet(checked); + // 透视表 + if (checked) { + setSheetType('pivot'); + setDataCfg(assembleDataCfg({})); + } else { + setSheetType('table'); + setDataCfg(assembleDataCfg(tableDataFields)); + } + }; + return (
@@ -50,9 +72,10 @@ function MainLayout() { {render && ( @@ -86,6 +109,12 @@ function MainLayout() { checked={showTooltip} onChange={setShowTooltip} /> + } /> diff --git a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.tsx b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.tsx index f5d0cb697a..a6c55e1ceb 100644 --- a/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.tsx +++ b/packages/s2-core/__tests__/spreadsheet/table-sheet-spec.tsx @@ -4,21 +4,21 @@ import 'antd/dist/antd.min.css'; import React, { useEffect } from 'react'; import ReactDOM from 'react-dom'; import { act } from 'react-dom/test-utils'; +import { getContainer, getMockData } from '../util/helpers'; import { S2DataConfig, S2Event, S2Options, SheetComponent, SpreadSheet, -} from '../../src'; -import { getContainer, getMockData } from '../util/helpers'; - + TableSheet, +} from '@/index'; const data = getMockData('../data/tableau-supermarket.csv'); const getSpreadSheet = (ref) => (dom: string | HTMLElement, dataCfg: S2DataConfig, options: S2Options) => { - const s2 = new SpreadSheet(dom, dataCfg, options); + const s2 = new TableSheet(dom, dataCfg, options); ref.current = s2; return s2; }; @@ -85,7 +85,6 @@ function MainLayout() { width: 800, height: 600, showSeriesNumber: true, - mode: 'table', enableCopy: true, style: { colCfg: { @@ -141,6 +140,7 @@ function MainLayout() { dataCfg={dataCfg} adaptive={false} options={options} + sheetType={'table'} spreadsheet={getSpreadSheet(s2Ref)} />
diff --git a/packages/s2-core/__tests__/spreadsheet/tabularSheet-spec.tsx b/packages/s2-core/__tests__/spreadsheet/tabularSheet-spec.tsx index 23fadf53ec..0711393ee8 100644 --- a/packages/s2-core/__tests__/spreadsheet/tabularSheet-spec.tsx +++ b/packages/s2-core/__tests__/spreadsheet/tabularSheet-spec.tsx @@ -3,14 +3,14 @@ import 'antd/dist/antd.min.css'; import ReactDOM from 'react-dom'; import React from 'react'; import { getContainer } from '../util/helpers'; -import { S2DataConfig, S2Options, SheetComponent, SpreadSheet } from '@/index'; +import { S2DataConfig, S2Options, SheetComponent, PivotSheet } from '@/index'; const getSpreadSheet = ( dom: string | HTMLElement, dataCfg: S2DataConfig, options: S2Options, ) => { - return new SpreadSheet(dom, dataCfg, options); + return new PivotSheet(dom, dataCfg, options); }; const mockData = { diff --git a/packages/s2-core/__tests__/unit/data-accuracy-one-measure-spec.tsx b/packages/s2-core/__tests__/unit/data-accuracy-one-measure-spec.tsx index 0dde5a9d31..8fe1fc77b8 100644 --- a/packages/s2-core/__tests__/unit/data-accuracy-one-measure-spec.tsx +++ b/packages/s2-core/__tests__/unit/data-accuracy-one-measure-spec.tsx @@ -22,6 +22,7 @@ import { S2Options, SheetComponent, SpreadSheet, + PivotSheet, } from '@/index'; let spreadsheet1: SpreadSheet; @@ -31,7 +32,7 @@ const setSpreadSheet = ( options: S2Options, index: number, ) => { - const ss = new SpreadSheet(dom, dataCfg, options); + const ss = new PivotSheet(dom, dataCfg, options); if (index === 1) { spreadsheet1 = ss; } @@ -110,7 +111,6 @@ const getOptions = () => { hierarchyCollapse: false, showSeriesNumber: false, freezeRowHeader: false, - mode: 'pivot', totals: { row: { showGrandTotals: true, diff --git a/packages/s2-core/__tests__/unit/data-accuracy-two-measures-spec.tsx b/packages/s2-core/__tests__/unit/data-accuracy-two-measures-spec.tsx index 5ede18867b..f29bfaa0a0 100644 --- a/packages/s2-core/__tests__/unit/data-accuracy-two-measures-spec.tsx +++ b/packages/s2-core/__tests__/unit/data-accuracy-two-measures-spec.tsx @@ -15,6 +15,7 @@ import { getContainer } from '../util/helpers'; import { auto, EXTRA_FIELD, + PivotSheet, S2DataConfig, S2Options, SheetComponent, @@ -29,7 +30,7 @@ const setSpreadSheet = ( options: S2Options, index: number, ) => { - const ss = new SpreadSheet(dom, dataCfg, options); + const ss = new PivotSheet(dom, dataCfg, options); if (index === 1) { spreadsheet1 = ss; } @@ -104,7 +105,6 @@ const getOptions = () => { hierarchyCollapse: false, showSeriesNumber: false, freezeRowHeader: false, - mode: 'pivot', totals: { row: { showGrandTotals: true, diff --git a/packages/s2-core/__tests__/unit/data-process/pivot-spec.tsx b/packages/s2-core/__tests__/unit/data-process/pivot-spec.tsx index aa744ade8b..77671fb04f 100644 --- a/packages/s2-core/__tests__/unit/data-process/pivot-spec.tsx +++ b/packages/s2-core/__tests__/unit/data-process/pivot-spec.tsx @@ -7,10 +7,10 @@ import { getContainer } from '../../util/helpers'; import { data } from '../../data/mock-dataset.json'; import { EXTRA_FIELD, VALUE_FIELD } from '@/common/constant'; import { PivotDataSet } from '@/data-set/pivot-data-set'; -import { SpreadSheet } from '@/sheet-type'; +import { PivotSheet } from '@/sheet-type'; describe('Pivot Table Core Data Process', () => { - const ss = new SpreadSheet( + const ss = new PivotSheet( getContainer(), assembleDataCfg({ totalData: [], diff --git a/packages/s2-core/__tests__/unit/data-process/table-spec.tsx b/packages/s2-core/__tests__/unit/data-process/table-spec.tsx index 9164a8586b..e9b735df0b 100644 --- a/packages/s2-core/__tests__/unit/data-process/table-spec.tsx +++ b/packages/s2-core/__tests__/unit/data-process/table-spec.tsx @@ -5,12 +5,12 @@ * - 明细表不需要生成 Row Hierarchy(但为了流程一致会生成空结构) */ import { get } from 'lodash'; -import { SpreadSheet } from 'src/sheet-type'; +import { TableSheet } from 'src/sheet-type'; import { assembleDataCfg, assembleOptions } from '../../util/sheet-entry'; import { getContainer } from '../../util/helpers'; describe('List Table Core Data Process', () => { - const ss = new SpreadSheet( + const ss = new TableSheet( getContainer(), assembleDataCfg({ meta: [], @@ -18,7 +18,7 @@ describe('List Table Core Data Process', () => { columns: ['province', 'city', 'type', 'sub_type', 'price'], }, }), - assembleOptions({ mode: 'table' }), + assembleOptions({}), ); ss.render(); diff --git a/packages/s2-core/__tests__/unit/dataset/pivot-dataset-row-value-spec.ts b/packages/s2-core/__tests__/unit/dataset/pivot-dataset-row-value-spec.ts index 3cc1ca267e..8d8ca76db4 100644 --- a/packages/s2-core/__tests__/unit/dataset/pivot-dataset-row-value-spec.ts +++ b/packages/s2-core/__tests__/unit/dataset/pivot-dataset-row-value-spec.ts @@ -1,16 +1,16 @@ /** * pivot mode data-set test when value in row. */ -import { EXTRA_FIELD, VALUE_FIELD } from 'src/common/constant'; -import { S2DataConfig } from 'src/common/interface'; -import { SpreadSheet } from 'src/sheet-type'; -import { PivotDataSet } from 'src/data-set/pivot-data-set'; import { get } from 'lodash'; -import { assembleDataCfg } from 'tests/util/sheet-entry'; +import { assembleDataCfg } from '../../util/sheet-entry'; +import { EXTRA_FIELD, VALUE_FIELD } from '@/common/constant'; +import { S2DataConfig } from '@/common/interface'; +import { PivotSheet } from '@/sheet-type'; +import { PivotDataSet } from '@/data-set/pivot-data-set'; jest.mock('src/sheet-type'); jest.mock('src/facet/layout/node'); -const MockSpreadSheet = SpreadSheet as any as jest.Mock; +const MockPivotSheet = PivotSheet as any as jest.Mock; describe('Pivot Mode Test When Value In Row', () => { let dataSet: PivotDataSet; @@ -24,8 +24,8 @@ describe('Pivot Mode Test When Value In Row', () => { }); beforeEach(() => { - MockSpreadSheet.mockClear(); - dataSet = new PivotDataSet(new MockSpreadSheet()); + MockPivotSheet.mockClear(); + dataSet = new PivotDataSet(new MockPivotSheet()); dataSet.setDataCfg(dataCfg); }); diff --git a/packages/s2-core/__tests__/unit/dataset/pivot-dataset-spec.ts b/packages/s2-core/__tests__/unit/dataset/pivot-dataset-spec.ts index 180f273843..995213802c 100644 --- a/packages/s2-core/__tests__/unit/dataset/pivot-dataset-spec.ts +++ b/packages/s2-core/__tests__/unit/dataset/pivot-dataset-spec.ts @@ -1,16 +1,16 @@ /** * pivot mode base data-set test. */ -import { EXTRA_FIELD, VALUE_FIELD } from 'src/common/constant'; -import { S2DataConfig } from 'src/common/interface'; -import { SpreadSheet } from 'src/sheet-type'; -import { PivotDataSet } from 'src/data-set/pivot-data-set'; import { get } from 'lodash'; -import { assembleDataCfg } from 'tests/util/sheet-entry'; +import { assembleDataCfg } from '../../util/sheet-entry'; +import { EXTRA_FIELD, VALUE_FIELD } from '@/common/constant'; +import { S2DataConfig } from '@/common/interface'; +import { PivotSheet } from '@/sheet-type'; +import { PivotDataSet } from '@/data-set/pivot-data-set'; jest.mock('src/sheet-type'); jest.mock('src/facet/layout/node'); -const MockSpreadSheet = SpreadSheet as any as jest.Mock; +const MockPivotSheet = PivotSheet as any as jest.Mock; describe('Pivot Dataset Test', () => { let dataSet: PivotDataSet; @@ -20,8 +20,8 @@ describe('Pivot Dataset Test', () => { }); beforeEach(() => { - MockSpreadSheet.mockClear(); - dataSet = new PivotDataSet(new MockSpreadSheet()); + MockPivotSheet.mockClear(); + dataSet = new PivotDataSet(new MockPivotSheet()); dataSet.setDataCfg(dataCfg); }); diff --git a/packages/s2-core/__tests__/unit/dataset/pivot-dataset-total-spec.ts b/packages/s2-core/__tests__/unit/dataset/pivot-dataset-total-spec.ts index bc40356f95..fe3256f1a2 100644 --- a/packages/s2-core/__tests__/unit/dataset/pivot-dataset-total-spec.ts +++ b/packages/s2-core/__tests__/unit/dataset/pivot-dataset-total-spec.ts @@ -1,24 +1,24 @@ /** * pivot mode base data-set test. */ -import { EXTRA_FIELD, VALUE_FIELD } from 'src/common/constant'; -import { S2DataConfig } from 'src/common/interface'; -import { SpreadSheet } from 'src/sheet-type'; -import { PivotDataSet } from 'src/data-set/pivot-data-set'; -import { assembleDataCfg } from 'tests/util/sheet-entry'; import { get } from 'lodash'; +import { assembleDataCfg } from '../../util/sheet-entry'; +import { EXTRA_FIELD, VALUE_FIELD } from '@/common/constant'; +import { S2DataConfig } from '@/common/interface'; +import { PivotSheet } from '@/sheet-type'; +import { PivotDataSet } from '@/data-set/pivot-data-set'; jest.mock('src/sheet-type'); jest.mock('src/facet/layout/node'); -const MockSpreadSheet = SpreadSheet as any as jest.Mock; +const MockPivotSheet = PivotSheet as any as jest.Mock; describe('Pivot Dataset Total Test', () => { let dataSet: PivotDataSet; let dataCfg: S2DataConfig; beforeEach(() => { - MockSpreadSheet.mockClear(); - dataSet = new PivotDataSet(new MockSpreadSheet()); + MockPivotSheet.mockClear(); + dataSet = new PivotDataSet(new MockPivotSheet()); dataCfg = assembleDataCfg({ meta: [], diff --git a/packages/s2-core/__tests__/unit/dataset/table-dataset-spec.ts b/packages/s2-core/__tests__/unit/dataset/table-dataset-spec.ts index cd3a4c663e..e1f57a9465 100644 --- a/packages/s2-core/__tests__/unit/dataset/table-dataset-spec.ts +++ b/packages/s2-core/__tests__/unit/dataset/table-dataset-spec.ts @@ -3,12 +3,12 @@ */ import { assembleDataCfg } from '../../util/sheet-entry'; import { S2DataConfig } from '@/common/interface'; -import { SpreadSheet } from '@/sheet-type'; +import { TableSheet } from '@/sheet-type'; import { TableDataSet } from '@/data-set/table-data-set'; jest.mock('src/sheet-type'); jest.mock('src/facet/layout/node'); -const MockSpreadSheet = SpreadSheet as any as jest.Mock; +const MockTableSheet = TableSheet as any as jest.Mock; describe('Table Mode Dataset Test', () => { let dataSet: TableDataSet; @@ -20,8 +20,8 @@ describe('Table Mode Dataset Test', () => { }, }; beforeEach(() => { - MockSpreadSheet.mockClear(); - dataSet = new TableDataSet(new MockSpreadSheet()); + MockTableSheet.mockClear(); + dataSet = new TableDataSet(new MockTableSheet()); dataSet.setDataCfg(dataCfg); }); diff --git a/packages/s2-core/__tests__/unit/interaction/brush-selection-spec.ts b/packages/s2-core/__tests__/unit/interaction/brush-selection-spec.ts index d4b2004aa0..7e793e8fcc 100644 --- a/packages/s2-core/__tests__/unit/interaction/brush-selection-spec.ts +++ b/packages/s2-core/__tests__/unit/interaction/brush-selection-spec.ts @@ -8,6 +8,7 @@ import { InteractionBrushSelectionStage, InterceptType, OriginalEvent, + PivotSheet, S2CellType, S2Event, SpreadSheet, @@ -73,7 +74,7 @@ describe('Interaction Brush Selection Tests', () => { beforeEach(() => { MockRootInteraction.mockClear(); - mockSpreadSheetInstance = new SpreadSheet( + mockSpreadSheetInstance = new PivotSheet( document.createElement('div'), null, null, diff --git a/packages/s2-core/__tests__/unit/utils/__snapshots__/build-table-hierarchy-spec.tsx.snap b/packages/s2-core/__tests__/unit/utils/__snapshots__/build-table-hierarchy-spec.tsx.snap index b27c2adecc..523bc72f6e 100644 --- a/packages/s2-core/__tests__/unit/utils/__snapshots__/build-table-hierarchy-spec.tsx.snap +++ b/packages/s2-core/__tests__/unit/utils/__snapshots__/build-table-hierarchy-spec.tsx.snap @@ -8,25 +8,25 @@ Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "$$series_number$$", + "field": "area", "height": 0, "id": "root[&]序号", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "$$series_number$$", + "key": "area", "label": "序号", "level": 0, "padding": 0, "query": Object { - "$$series_number$$": "序号", + "area": "序号", }, - "rowIndex": 0, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "序号", @@ -44,7 +44,7 @@ Object { "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, @@ -56,7 +56,7 @@ Object { "query": Object { "area": "area", }, - "rowIndex": 1, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "area", @@ -68,25 +68,25 @@ Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "province", + "field": "area", "height": 0, "id": "root[&]province", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "province", + "key": "area", "label": "province", "level": 0, "padding": 0, "query": Object { - "province": "province", + "area": "province", }, - "rowIndex": 2, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "province", @@ -98,25 +98,25 @@ Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "city", + "field": "area", "height": 0, "id": "root[&]city", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "city", + "key": "area", "label": "city", "level": 0, "padding": 0, "query": Object { - "city": "city", + "area": "city", }, - "rowIndex": 3, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "city", @@ -128,25 +128,25 @@ Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "type", + "field": "area", "height": 0, "id": "root[&]type", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "type", + "key": "area", "label": "type", "level": 0, "padding": 0, "query": Object { - "type": "type", + "area": "type", }, - "rowIndex": 4, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "type", @@ -158,25 +158,25 @@ Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "sub_type", + "field": "area", "height": 0, "id": "root[&]sub_type", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "sub_type", + "key": "area", "label": "sub_type", "level": 0, "padding": 0, "query": Object { - "sub_type": "sub_type", + "area": "sub_type", }, - "rowIndex": 5, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "sub_type", @@ -188,25 +188,25 @@ Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "profit", + "field": "area", "height": 0, "id": "root[&]profit", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "profit", + "key": "area", "label": "profit", "level": 0, "padding": 0, "query": Object { - "profit": "profit", + "area": "profit", }, - "rowIndex": 6, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "profit", @@ -218,25 +218,25 @@ Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "count", + "field": "area", "height": 0, "id": "root[&]count", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "count", + "key": "area", "label": "count", "level": 0, "padding": 0, "query": Object { - "count": "count", + "area": "count", }, - "rowIndex": 7, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "count", @@ -244,6 +244,36 @@ Object { "x": 0, "y": 0, }, + Object { + "belongsCell": undefined, + "children": Array [], + "colIndex": -1, + "field": "area", + "height": 0, + "id": "root[&]数值", + "inCollapseNode": undefined, + "isCollapsed": false, + "isGrandTotals": false, + "isLeaf": false, + "isPivotMode": undefined, + "isSubTotals": false, + "isTotalMeasure": false, + "isTotals": false, + "key": "area", + "label": "数值", + "level": 0, + "padding": 0, + "query": Object { + "area": "数值", + }, + "rowIndex": undefined, + "seriesNumberWidth": undefined, + "toJSON": [Function], + "value": "数值", + "width": 0, + "x": 0, + "y": 0, + }, ], "colIndex": -1, "field": undefined, @@ -279,25 +309,25 @@ Hierarchy { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "$$series_number$$", + "field": "area", "height": 0, "id": "root[&]序号", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "$$series_number$$", + "key": "area", "label": "序号", "level": 0, "padding": 0, "query": Object { - "$$series_number$$": "序号", + "area": "序号", }, - "rowIndex": 0, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "序号", @@ -315,7 +345,7 @@ Hierarchy { "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, @@ -327,7 +357,7 @@ Hierarchy { "query": Object { "area": "area", }, - "rowIndex": 1, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "area", @@ -339,25 +369,25 @@ Hierarchy { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "province", + "field": "area", "height": 0, "id": "root[&]province", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "province", + "key": "area", "label": "province", "level": 0, "padding": 0, "query": Object { - "province": "province", + "area": "province", }, - "rowIndex": 2, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "province", @@ -369,25 +399,25 @@ Hierarchy { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "city", + "field": "area", "height": 0, "id": "root[&]city", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "city", + "key": "area", "label": "city", "level": 0, "padding": 0, "query": Object { - "city": "city", + "area": "city", }, - "rowIndex": 3, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "city", @@ -399,25 +429,25 @@ Hierarchy { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "type", + "field": "area", "height": 0, "id": "root[&]type", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "type", + "key": "area", "label": "type", "level": 0, "padding": 0, "query": Object { - "type": "type", + "area": "type", }, - "rowIndex": 4, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "type", @@ -429,25 +459,25 @@ Hierarchy { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "sub_type", + "field": "area", "height": 0, "id": "root[&]sub_type", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "sub_type", + "key": "area", "label": "sub_type", "level": 0, "padding": 0, "query": Object { - "sub_type": "sub_type", + "area": "sub_type", }, - "rowIndex": 5, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "sub_type", @@ -459,25 +489,25 @@ Hierarchy { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "profit", + "field": "area", "height": 0, "id": "root[&]profit", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "profit", + "key": "area", "label": "profit", "level": 0, "padding": 0, "query": Object { - "profit": "profit", + "area": "profit", }, - "rowIndex": 6, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "profit", @@ -489,25 +519,25 @@ Hierarchy { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "count", + "field": "area", "height": 0, "id": "root[&]count", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "count", + "key": "area", "label": "count", "level": 0, "padding": 0, "query": Object { - "count": "count", + "area": "count", }, - "rowIndex": 7, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "count", @@ -515,274 +545,63 @@ Hierarchy { "x": 0, "y": 0, }, - ], - "height": 0, - "indexNode": Array [ - Object { - "belongsCell": undefined, - "children": Array [], - "colIndex": -1, - "field": "$$series_number$$", - "height": 0, - "id": "root[&]序号", - "inCollapseNode": undefined, - "isCollapsed": false, - "isGrandTotals": false, - "isLeaf": true, - "isPivotMode": undefined, - "isSubTotals": false, - "isTotalMeasure": false, - "isTotals": false, - "key": "$$series_number$$", - "label": "序号", - "level": 0, - "padding": 0, - "query": Object { - "$$series_number$$": "序号", - }, - "rowIndex": 0, - "seriesNumberWidth": undefined, - "toJSON": [Function], - "value": "序号", - "width": 0, - "x": 0, - "y": 0, - }, Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, "field": "area", "height": 0, - "id": "root[&]area", + "id": "root[&]数值", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, "key": "area", - "label": "area", - "level": 0, - "padding": 0, - "query": Object { - "area": "area", - }, - "rowIndex": 1, - "seriesNumberWidth": undefined, - "toJSON": [Function], - "value": "area", - "width": 0, - "x": 0, - "y": 0, - }, - Object { - "belongsCell": undefined, - "children": Array [], - "colIndex": -1, - "field": "province", - "height": 0, - "id": "root[&]province", - "inCollapseNode": undefined, - "isCollapsed": false, - "isGrandTotals": false, - "isLeaf": true, - "isPivotMode": undefined, - "isSubTotals": false, - "isTotalMeasure": false, - "isTotals": false, - "key": "province", - "label": "province", - "level": 0, - "padding": 0, - "query": Object { - "province": "province", - }, - "rowIndex": 2, - "seriesNumberWidth": undefined, - "toJSON": [Function], - "value": "province", - "width": 0, - "x": 0, - "y": 0, - }, - Object { - "belongsCell": undefined, - "children": Array [], - "colIndex": -1, - "field": "city", - "height": 0, - "id": "root[&]city", - "inCollapseNode": undefined, - "isCollapsed": false, - "isGrandTotals": false, - "isLeaf": true, - "isPivotMode": undefined, - "isSubTotals": false, - "isTotalMeasure": false, - "isTotals": false, - "key": "city", - "label": "city", - "level": 0, - "padding": 0, - "query": Object { - "city": "city", - }, - "rowIndex": 3, - "seriesNumberWidth": undefined, - "toJSON": [Function], - "value": "city", - "width": 0, - "x": 0, - "y": 0, - }, - Object { - "belongsCell": undefined, - "children": Array [], - "colIndex": -1, - "field": "type", - "height": 0, - "id": "root[&]type", - "inCollapseNode": undefined, - "isCollapsed": false, - "isGrandTotals": false, - "isLeaf": true, - "isPivotMode": undefined, - "isSubTotals": false, - "isTotalMeasure": false, - "isTotals": false, - "key": "type", - "label": "type", - "level": 0, - "padding": 0, - "query": Object { - "type": "type", - }, - "rowIndex": 4, - "seriesNumberWidth": undefined, - "toJSON": [Function], - "value": "type", - "width": 0, - "x": 0, - "y": 0, - }, - Object { - "belongsCell": undefined, - "children": Array [], - "colIndex": -1, - "field": "sub_type", - "height": 0, - "id": "root[&]sub_type", - "inCollapseNode": undefined, - "isCollapsed": false, - "isGrandTotals": false, - "isLeaf": true, - "isPivotMode": undefined, - "isSubTotals": false, - "isTotalMeasure": false, - "isTotals": false, - "key": "sub_type", - "label": "sub_type", + "label": "数值", "level": 0, "padding": 0, "query": Object { - "sub_type": "sub_type", + "area": "数值", }, - "rowIndex": 5, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], - "value": "sub_type", - "width": 0, - "x": 0, - "y": 0, - }, - Object { - "belongsCell": undefined, - "children": Array [], - "colIndex": -1, - "field": "profit", - "height": 0, - "id": "root[&]profit", - "inCollapseNode": undefined, - "isCollapsed": false, - "isGrandTotals": false, - "isLeaf": true, - "isPivotMode": undefined, - "isSubTotals": false, - "isTotalMeasure": false, - "isTotals": false, - "key": "profit", - "label": "profit", - "level": 0, - "padding": 0, - "query": Object { - "profit": "profit", - }, - "rowIndex": 6, - "seriesNumberWidth": undefined, - "toJSON": [Function], - "value": "profit", - "width": 0, - "x": 0, - "y": 0, - }, - Object { - "belongsCell": undefined, - "children": Array [], - "colIndex": -1, - "field": "count", - "height": 0, - "id": "root[&]count", - "inCollapseNode": undefined, - "isCollapsed": false, - "isGrandTotals": false, - "isLeaf": true, - "isPivotMode": undefined, - "isSubTotals": false, - "isTotalMeasure": false, - "isTotals": false, - "key": "count", - "label": "count", - "level": 0, - "padding": 0, - "query": Object { - "count": "count", - }, - "rowIndex": 7, - "seriesNumberWidth": undefined, - "toJSON": [Function], - "value": "count", + "value": "数值", "width": 0, "x": 0, "y": 0, }, ], + "height": 0, + "indexNode": Array [], "maxLevel": 0, "sampleNodeForLastLevel": Object { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "$$series_number$$", + "field": "area", "height": 0, "id": "root[&]序号", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "$$series_number$$", + "key": "area", "label": "序号", "level": 0, "padding": 0, "query": Object { - "$$series_number$$": "序号", + "area": "序号", }, - "rowIndex": 0, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "序号", @@ -795,25 +614,25 @@ Hierarchy { "belongsCell": undefined, "children": Array [], "colIndex": -1, - "field": "$$series_number$$", + "field": "area", "height": 0, "id": "root[&]序号", "inCollapseNode": undefined, "isCollapsed": false, "isGrandTotals": false, - "isLeaf": true, + "isLeaf": false, "isPivotMode": undefined, "isSubTotals": false, "isTotalMeasure": false, "isTotals": false, - "key": "$$series_number$$", + "key": "area", "label": "序号", "level": 0, "padding": 0, "query": Object { - "$$series_number$$": "序号", + "area": "序号", }, - "rowIndex": 0, + "rowIndex": undefined, "seriesNumberWidth": undefined, "toJSON": [Function], "value": "序号", diff --git a/packages/s2-core/__tests__/unit/utils/build-table-hierarchy-spec.tsx b/packages/s2-core/__tests__/unit/utils/build-table-hierarchy-spec.tsx index 4b7bb83d1e..63faa6bce2 100644 --- a/packages/s2-core/__tests__/unit/utils/build-table-hierarchy-spec.tsx +++ b/packages/s2-core/__tests__/unit/utils/build-table-hierarchy-spec.tsx @@ -8,6 +8,7 @@ import { S2Options, SheetComponent, SpreadSheet, + PivotSheet, Node, Hierarchy, } from '@/index'; @@ -22,7 +23,7 @@ const getSpreadSheet = ( dataCfg: S2DataConfig, options: S2Options, ) => { - spreadsheetIns = new SpreadSheet(dom, dataCfg, options); + spreadsheetIns = new PivotSheet(dom, dataCfg, options); return spreadsheetIns; }; diff --git a/packages/s2-core/__tests__/util/sheet-entry.tsx b/packages/s2-core/__tests__/util/sheet-entry.tsx index 488908a84f..6c82f2eb13 100644 --- a/packages/s2-core/__tests__/util/sheet-entry.tsx +++ b/packages/s2-core/__tests__/util/sheet-entry.tsx @@ -16,6 +16,7 @@ import { SheetComponent, SpreadSheet, ThemeCfg, + SheetType, } from '@/index'; import 'antd/dist/antd.min.css'; @@ -58,9 +59,10 @@ export const assembleDataCfg = (...dataCfg: Partial[]) => interface SheetEntryProps { options: Partial; dataCfg: Partial; - forceUpdate?: boolean; // 是否强制替换 options 和 dataCfg + forceUpdateDataCfg?: boolean; // 是否强制替换 dataCfg themeCfg?: ThemeCfg; header?: ReactNode; + sheetType?: SheetType; } // eslint-disable-next-line react/display-name @@ -69,11 +71,9 @@ export const SheetEntry = forwardRef( const [mode, setMode] = useState('grid'); const [valueInCols, setValueInCols] = useState(true); const [freezeRowHeader, setFreezeRowHeader] = useState(true); - const initOptions = props.forceUpdate - ? props.options - : assembleOptions(props.options); + const initOptions = assembleOptions(props.options); - const initDataCfg = props.forceUpdate + const initDataCfg = props.forceUpdateDataCfg ? props.dataCfg : assembleOptions(props.dataCfg); const [options, setOptions] = useState(() => initOptions); @@ -109,15 +109,11 @@ export const SheetEntry = forwardRef( }; useEffect(() => { - if (props.forceUpdate) { - setOptions(props.options); - } else { - setOptions(assembleOptions(options, props.options)); - } + setOptions(assembleOptions(options, props.options)); }, [props.options]); useEffect(() => { - if (props.forceUpdate) { + if (props.forceUpdateDataCfg) { setDataCfg(props.dataCfg); } else { setDataCfg(assembleDataCfg(dataCfg, props.dataCfg)); @@ -151,6 +147,7 @@ export const SheetEntry = forwardRef( { if (ref) { diff --git a/packages/s2-core/src/common/interface/basic.ts b/packages/s2-core/src/common/interface/basic.ts index d0ea62260a..ce69736ae8 100644 --- a/packages/s2-core/src/common/interface/basic.ts +++ b/packages/s2-core/src/common/interface/basic.ts @@ -75,7 +75,7 @@ export interface Fields { columns?: string[]; // value fields values?: string[]; - // measure values in cols as new col, only works in 'pivot' mode + // measure values in cols as new col, only works for PivotSheet valueInCols?: boolean; } diff --git a/packages/s2-core/src/common/interface/s2Options.ts b/packages/s2-core/src/common/interface/s2Options.ts index 1f64dfb967..5823499705 100644 --- a/packages/s2-core/src/common/interface/s2Options.ts +++ b/packages/s2-core/src/common/interface/s2Options.ts @@ -33,8 +33,6 @@ export interface S2PartialOptions { readonly width: number; // canvas's height readonly height: number; - // s2 mode - readonly mode?: 'pivot' | 'table'; // debug info for developer readonly debug?: boolean; // row header hierarchy type only work in pivot mode @@ -162,7 +160,6 @@ export const defaultStyle: Style = { export const defaultOptions: S2Options = { width: 600, height: 480, - mode: 'pivot', debug: false, hierarchyType: 'grid', conditions: {}, diff --git a/packages/s2-core/src/components/index.tsx b/packages/s2-core/src/components/index.tsx index 3eb6c748cc..9ea4320fd5 100644 --- a/packages/s2-core/src/components/index.tsx +++ b/packages/s2-core/src/components/index.tsx @@ -1,16 +1,16 @@ import React from 'react'; import { BaseSheet } from './sheets/base-sheet'; import { TabularSheet } from './sheets/tabular-sheet'; -import { BaseSheetProps } from './sheets/interface'; +import { TableSheet } from './sheets/table-sheet'; +import { SpreadsheetProps } from './sheets/interface'; +export { SpreadsheetProps, SheetType } from './sheets/interface'; export { PartDrillDown, PartDrillDownInfo } from './sheets/interface'; -export interface SpreadsheetProps extends BaseSheetProps { - sheetType?: 'base' | 'tabular'; -} - export const SheetComponent = (props: SpreadsheetProps) => { const { sheetType } = props; switch (sheetType) { + case 'table': + return ; case 'tabular': return ; default: diff --git a/packages/s2-core/src/components/sheets/base-sheet/index.tsx b/packages/s2-core/src/components/sheets/base-sheet/index.tsx index 24010f5537..e8059c93c7 100644 --- a/packages/s2-core/src/components/sheets/base-sheet/index.tsx +++ b/packages/s2-core/src/components/sheets/base-sheet/index.tsx @@ -22,7 +22,7 @@ import { EmitterType } from '@/common/interface/emitter'; import { DrillDown } from '@/components/drill-down'; import { Header } from '@/components/header'; import { BaseSheetProps } from '@/components/sheets/interface'; -import { SpreadSheet } from '@/sheet-type'; +import { SpreadSheet, PivotSheet } from '@/sheet-type'; import { HandleDrillDown, HandleDrillDownIcon, @@ -71,11 +71,11 @@ export const BaseSheet: React.FC = memo((props) => { const getSpreadSheet = (): SpreadSheet => { const params: S2Constructor = [container.current, dataCfg, options]; - // TODO: 改个名字 spreadsheet => customSpreadsheet 之类的? + if (spreadsheet) { return spreadsheet(...params); } - return new SpreadSheet(...params); + return new PivotSheet(...params); }; const bindEvent = () => { @@ -228,7 +228,6 @@ export const BaseSheet: React.FC = memo((props) => { if (isEmpty(paginationCfg)) { return null; } - const pageSize = get(paginationCfg, 'pageSize', Infinity); // only show the pagination when the pageSize > 5 const showQuickJumper = total / pageSize > 5; const preCls = `${S2_PREFIX_CLS}-pagination`; @@ -236,7 +235,7 @@ export const BaseSheet: React.FC = memo((props) => { return (
[]; diff --git a/packages/s2-core/src/components/sheets/table-sheet/index.tsx b/packages/s2-core/src/components/sheets/table-sheet/index.tsx new file mode 100644 index 0000000000..548e0c67da --- /dev/null +++ b/packages/s2-core/src/components/sheets/table-sheet/index.tsx @@ -0,0 +1,279 @@ +// TODO 所有表组件抽取公共hook +import { Event as GEvent } from '@antv/g-canvas'; +import { Pagination, Spin } from 'antd'; +import { debounce, forIn, get, isEmpty, isFunction, merge } from 'lodash'; +import React, { memo, StrictMode, useEffect, useRef, useState } from 'react'; +import { S2Event } from '@/common/constant'; +import { S2_PREFIX_CLS } from '@/common/constant/classnames'; +import { i18n } from '@/common/i18n'; +import { + CellScrollPosition, + ListSortParams, + Pagination as PaginationCfg, + S2Constructor, + S2Options, + safetyDataConfig, + safetyOptions, + TargetLayoutNode, +} from '@/common/interface'; +import { EmitterType } from '@/common/interface/emitter'; +import { Header } from '@/components/header'; +import { BaseSheetProps } from '@/components/sheets/interface'; +import { SpreadSheet, TableSheet as BaseTableSheet } from '@/sheet-type'; +import { getBaseCellData } from '@/utils/interaction/formatter'; + +export const TableSheet: React.FC = memo((props) => { + const { + spreadsheet, + dataCfg, + options, + adaptive = true, + header, + themeCfg, + isLoading, + onListSort, + onRowCellScroll, + onColCellScroll, + onCellScroll, + onRowCellClick, + onColCellClick, + onMergedCellsClick, + onDataCellMouseUp, + getSpreadsheet, + } = props; + const container = useRef(); + const baseSpreadsheet = useRef(); + + const [ownSpreadsheet, setOwnSpreadsheet] = useState(); + const [resizeTimeStamp, setResizeTimeStamp] = useState(null); + const [loading, setLoading] = useState(true); + const [total, setTotal] = useState(); + const [current, setCurrent] = useState( + options?.pagination?.current || 1, + ); + const [pageSize, setPageSize] = useState( + options?.pagination?.pageSize || 10, + ); + + const getSpreadSheet = (): SpreadSheet => { + const params: S2Constructor = [container.current, dataCfg, options]; + + if (spreadsheet) { + return spreadsheet(...params); + } + return new BaseTableSheet(...params); + }; + + const bindEvent = () => { + const EVENT_LISTENER_CONFIG: Record< + string, + (...args: unknown[]) => unknown + > = { + [S2Event.LAYOUT_PAGINATION]: (data: PaginationCfg) => { + setTotal(data?.total); + }, + [S2Event.DATA_CELL_MOUSE_UP]: (ev: GEvent) => { + onDataCellMouseUp?.(getBaseCellData(ev)); + }, + [S2Event.MERGED_CELLS_CLICK]: (ev: GEvent) => { + onMergedCellsClick?.(getBaseCellData(ev)); + }, + [S2Event.ROW_CELL_CLICK]: (ev: GEvent) => { + onRowCellClick?.(getBaseCellData(ev)); + }, + [S2Event.COL_CELL_CLICK]: (ev: GEvent) => { + onColCellClick?.(getBaseCellData(ev)); + }, + [S2Event.LAYOUT_ROW_NODE_BORDER_REACHED]: ( + targetRow: TargetLayoutNode, + ) => { + onRowCellScroll?.(targetRow); + }, + [S2Event.LAYOUT_COL_NODE_BORDER_REACHED]: ( + targetCol: TargetLayoutNode, + ) => { + onColCellScroll?.(targetCol); + }, + [S2Event.LAYOUT_CELL_SCROLL]: (value: CellScrollPosition) => { + onCellScroll?.(value); + }, + [S2Event.RANGE_SORT]: (value: ListSortParams) => { + onListSort?.(value); + }, + }; + + forIn(EVENT_LISTENER_CONFIG, (handler, event: keyof EmitterType) => { + baseSpreadsheet.current.on(event, handler); + }); + }; + + const unBindEvent = () => { + [ + S2Event.LAYOUT_AFTER_HEADER_LAYOUT, + S2Event.LAYOUT_PAGINATION, + S2Event.LAYOUT_ROW_NODE_BORDER_REACHED, + S2Event.LAYOUT_COL_NODE_BORDER_REACHED, + S2Event.LAYOUT_CELL_SCROLL, + S2Event.RANGE_SORT, + S2Event.MERGED_CELLS_CLICK, + S2Event.ROW_CELL_CLICK, + S2Event.COL_CELL_CLICK, + S2Event.DATA_CELL_MOUSE_UP, + ].forEach((eventName) => { + baseSpreadsheet.current.off(eventName); + }); + }; + + const setOptions = (newOptions?: S2Options) => { + const curOptions = newOptions || options; + ownSpreadsheet.setOptions(safetyOptions(curOptions)); + }; + + const setDataCfg = () => { + // reset the options since it could be changed by layout + setOptions(); + ownSpreadsheet.setDataCfg(safetyDataConfig(dataCfg)); + }; + + const update = (reset?: () => void, reloadData = true) => { + if (!ownSpreadsheet) return; + if (isFunction(reset)) reset(); + ownSpreadsheet.render(reloadData); + setLoading(false); + }; + + const debounceResize = debounce((e: Event) => { + setResizeTimeStamp(e.timeStamp); + }, 200); + + const renderPagination = (): JSX.Element => { + const paginationCfg = get(options, 'pagination', false); + // not show the pagination + if (isEmpty(paginationCfg)) { + return null; + } + // only show the pagination when the pageSize > 5 + const showQuickJumper = total / pageSize > 5; + const preCls = `${S2_PREFIX_CLS}-pagination`; + + return ( +
+ { + setCurrent(1); + setPageSize(size); + }} + size={'small'} + showQuickJumper={showQuickJumper} + onChange={(page) => setCurrent(page)} + /> + + {i18n('共计')} + {total || ' - '} + {i18n('条')} + +
+ ); + }; + + const buildSpreadSheet = () => { + if (baseSpreadsheet.current) { + return; + } + baseSpreadsheet.current = getSpreadSheet(); + bindEvent(); + baseSpreadsheet.current.setDataCfg(safetyDataConfig(dataCfg)); + baseSpreadsheet.current.setOptions(safetyOptions(options)); + baseSpreadsheet.current.setThemeCfg(themeCfg); + baseSpreadsheet.current.render(); + setLoading(false); + setOwnSpreadsheet(baseSpreadsheet.current); + getSpreadsheet?.(baseSpreadsheet.current); + }; + + useEffect(() => { + buildSpreadSheet(); + // 监听窗口变化 + if (adaptive) window.addEventListener('resize', debounceResize); + return () => { + unBindEvent(); + baseSpreadsheet.current.destroy(); + if (adaptive) window.removeEventListener('resize', debounceResize); + }; + }, []); + + useEffect(() => { + if (!container.current || !ownSpreadsheet) return; + + const style = getComputedStyle(container.current); + + const box = { + width: parseInt(style.getPropertyValue('width').replace('px', ''), 10), + height: parseInt(style.getPropertyValue('height').replace('px', ''), 10), + }; + + ownSpreadsheet.changeSize(box?.width, box?.height); + ownSpreadsheet.render(false); + }, [resizeTimeStamp]); + + useEffect(() => { + update(setDataCfg); + }, [dataCfg]); + + useEffect(() => { + update(setOptions, false); + }, [options]); + + useEffect(() => { + update(() => { + ownSpreadsheet.setThemeCfg(themeCfg); + }); + }, [JSON.stringify(themeCfg)]); + + useEffect(() => { + if (!ownSpreadsheet) return; + buildSpreadSheet(); + }, [spreadsheet]); + + useEffect(() => { + if (!ownSpreadsheet || isEmpty(options?.pagination)) return; + const newOptions = merge({}, options, { + pagination: { + current: current, + }, + }); + + setOptions(newOptions); + update(); + }, [current]); + + useEffect(() => { + if (!ownSpreadsheet || isEmpty(options?.pagination)) return; + const newOptions = merge({}, options, { + pagination: { + pageSize: pageSize, + }, + }); + + setOptions(newOptions); + update(); + }, [pageSize]); + + return ( + + + {header &&
} +
+ {renderPagination()} + + + ); +}); diff --git a/packages/s2-core/src/components/sheets/tabular-sheet/index.tsx b/packages/s2-core/src/components/sheets/tabular-sheet/index.tsx index 9a4d28e50b..863d31a2d0 100644 --- a/packages/s2-core/src/components/sheets/tabular-sheet/index.tsx +++ b/packages/s2-core/src/components/sheets/tabular-sheet/index.tsx @@ -19,7 +19,7 @@ import { TabularTheme } from './tabular-theme'; import { S2Event } from '@/common/constant'; import { getBaseCellData } from '@/utils/interaction/formatter'; import { safetyDataConfig, safetyOptions, S2Options } from '@/common/interface'; -import { SpreadSheet } from '@/sheet-type'; +import { SpreadSheet, PivotSheet } from '@/sheet-type'; export const TabularSheet = (props: BaseSheetProps) => { const { @@ -108,7 +108,7 @@ export const TabularSheet = (props: BaseSheetProps) => { if (spreadsheet) { return spreadsheet(container, dataCfg, buildOptions()); } - return new SpreadSheet(container, dataCfg, buildOptions()); + return new PivotSheet(container, dataCfg, buildOptions()); }; const bindEvent = () => { diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index d44bfa9dfa..b78a9b6905 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -1,6 +1,6 @@ import { IGroup } from '@antv/g-base'; import { Group } from '@antv/g-canvas'; -import { get, maxBy, set, forEach } from 'lodash'; +import { get, maxBy, set } from 'lodash'; import type { LayoutResult, S2CellType, @@ -196,17 +196,10 @@ export class TableFacet extends BaseFacet { const { frozenTrailingColCount } = this.spreadsheet?.options; let preLeafNode = Node.blankNode(); const allNodes = colsHierarchy.getNodes(); - - let maxColHeight = 0; - - forEach(allNodes, (node) => { - const height = this.getColNodeHeight(node); - if (height > maxColHeight) { - maxColHeight = height; - } - }); - - colsHierarchy.height = maxColHeight; + for (const levelSample of colsHierarchy.sampleNodesForAllLevels) { + levelSample.height = this.getColNodeHeight(levelSample); + colsHierarchy.height += levelSample.height; + } const nodes = []; @@ -220,7 +213,7 @@ export class TableFacet extends BaseFacet { preLeafNode = currentNode; currentNode.y = 0; - currentNode.height = maxColHeight; + currentNode.height = this.getColNodeHeight(currentNode); nodes.push(currentNode); @@ -257,6 +250,7 @@ export class TableFacet extends BaseFacet { private calculateColLeafNodesWidth(col: Node): number { const { cellCfg, colCfg, dataSet, spreadsheet } = this.cfg; + const userDragWidth = get( get(colCfg, 'widthByFieldValue'), `${col.value}`, @@ -569,83 +563,10 @@ export class TableFacet extends BaseFacet { } public render() { + super.render(); this.renderFrozenPanelCornerGroup(); this.initFrozenGroupPosition(); this.renderFrozenGroupSplitLine(); - super.render(); - } - - // 对 panelScrollGroup 以及四个方向的 frozenGroup 做 Clip,避免有透明度时冻结分组和滚动分组展示重叠 - protected clip(scrollX: number, scrollY: number) { - const { - frozenRowGroup, - frozenColGroup, - frozenTrailingColGroup, - frozenTrailingRowGroup, - panelScrollGroup, - } = this.spreadsheet; - const frozenColGroupWidth = frozenColGroup.getBBox().width; - const frozenRowGroupHeight = frozenRowGroup.getBBox().height; - const frozenTrailingRowGroupHeight = - frozenTrailingRowGroup.getBBox().height; - const panelScrollGroupWidth = - this.panelBBox.width - - frozenColGroupWidth - - frozenTrailingColGroup.getBBox().width; - const panelScrollGroupHeight = - this.panelBBox.height - - frozenRowGroupHeight - - frozenTrailingRowGroupHeight; - - panelScrollGroup.setClip({ - type: 'rect', - attrs: { - x: scrollX + frozenColGroupWidth, - y: scrollY + frozenRowGroupHeight, - width: panelScrollGroupWidth, - height: panelScrollGroupHeight, - }, - }); - - frozenRowGroup.setClip({ - type: 'rect', - attrs: { - x: scrollX + frozenColGroupWidth, - y: 0, - width: panelScrollGroupWidth, - height: frozenRowGroupHeight, - }, - }); - - frozenTrailingRowGroup.setClip({ - type: 'rect', - attrs: { - x: scrollX + frozenColGroupWidth, - y: frozenTrailingRowGroup.getBBox().minY, - width: panelScrollGroupWidth, - height: frozenTrailingRowGroupHeight, - }, - }); - - frozenColGroup.setClip({ - type: 'rect', - attrs: { - x: 0, - y: scrollY + frozenRowGroupHeight, - width: frozenColGroupWidth, - height: panelScrollGroupHeight, - }, - }); - - frozenTrailingColGroup.setClip({ - type: 'rect', - attrs: { - x: frozenTrailingColGroup.getBBox().minX, - y: scrollY + frozenRowGroupHeight, - width: frozenColGroupWidth, - height: panelScrollGroupHeight, - }, - }); } protected translateRelatedGroups( diff --git a/packages/s2-core/src/index.ts b/packages/s2-core/src/index.ts index 9e404c8d37..b6fbb25ab9 100644 --- a/packages/s2-core/src/index.ts +++ b/packages/s2-core/src/index.ts @@ -5,12 +5,8 @@ export { Node } from './facet/layout/node'; export { Hierarchy } from './facet/layout/hierarchy'; export { BaseEvent, BaseEventImplement } from './interaction/base-interaction'; export { GuiIcon } from './common/icons/gui-icon'; -export { - SheetComponent, - SpreadsheetProps, - PartDrillDown, -} from './components/index'; export { DrillDown, DrillDownProps } from './components/drill-down'; +export * from './components/index'; export * from './utils'; export * from './cell'; export * from './common/interface/index'; diff --git a/packages/s2-core/src/sheet-type/index.ts b/packages/s2-core/src/sheet-type/index.ts index 8c359b9ddf..1d58062e8f 100644 --- a/packages/s2-core/src/sheet-type/index.ts +++ b/packages/s2-core/src/sheet-type/index.ts @@ -1,652 +1,5 @@ -import EE from '@antv/event-emitter'; -import { Canvas, Event as CanvasEvent, IGroup } from '@antv/g-canvas'; -import { clone, get, includes, isString, merge, size } from 'lodash'; -import { BaseCell, DataCell, TableDataCell, TableRowCell } from '@/cell'; -import { - BACK_GROUND_GROUP_CONTAINER_Z_INDEX, - FRONT_GROUND_GROUP_CONTAINER_Z_INDEX, - KEY_GROUP_BACK_GROUND, - KEY_GROUP_FORE_GROUND, - KEY_GROUP_PANEL_FROZEN_BOTTOM, - KEY_GROUP_PANEL_FROZEN_COL, - KEY_GROUP_PANEL_FROZEN_ROW, - KEY_GROUP_PANEL_FROZEN_TOP, - KEY_GROUP_PANEL_FROZEN_TRAILING_COL, - KEY_GROUP_PANEL_FROZEN_TRAILING_ROW, - KEY_GROUP_PANEL_GROUND, - KEY_GROUP_PANEL_SCROLL, - PANEL_GROUP_FROZEN_GROUP_Z_INDEX, - PANEL_GROUP_GROUP_CONTAINER_Z_INDEX, - PANEL_GROUP_SCROLL_GROUP_Z_INDEX, - S2Event, -} from '@/common/constant'; -import { DebuggerUtil } from '@/common/debug'; -import { i18n } from '@/common/i18n'; -import { - OffsetConfig, - Pagination, - S2CellType, - S2DataConfig, - S2MountContainer, - S2Options, - safetyDataConfig, - safetyOptions, - SpreadSheetFacetCfg, - ThemeCfg, - TooltipData, - TooltipOptions, - TooltipShowOptions, - Total, - Totals, - ViewMeta, -} from '@/common/interface'; -import { - EmitterType, - RowCellCollapseTreeRowsType, -} from '@/common/interface/emitter'; -import { Store } from '@/common/store'; -import { BaseDataSet, PivotDataSet, TableDataSet } from '@/data-set'; -import { CustomTreePivotDataSet } from '@/data-set/custom-tree-pivot-data-set'; -import { BaseFacet, PivotFacet, TableFacet } from '@/facet'; -import { Node, SpreadSheetTheme } from '@/index'; -import { RootInteraction } from '@/interaction/root'; -import { getTheme } from '@/theme'; -import { HdAdapter } from '@/ui/hd-adapter'; -import { BaseTooltip } from '@/ui/tooltip'; -import { clearValueRangeState } from '@/utils/condition/state-controller'; -import { customMerge } from '@/utils/merge'; -import { getTooltipData } from '@/utils/tooltip'; +import { PivotSheet } from './pivot-sheet'; +import { TableSheet } from './table-sheet'; +import { SpreadSheet } from './spread-sheet'; -export class SpreadSheet extends EE { - // dom id - public dom: S2MountContainer; - - // theme config - public theme: SpreadSheetTheme; - - // store some temporary data - public store = new Store(); - - // the original data config - public dataCfg: S2DataConfig; - - // Spreadsheet's configurations - public options: S2Options; - - /** - * processed data structure, include {@link Fields}, {@link Meta} - * {@link Data}, {@link SortParams} - */ - public dataSet: BaseDataSet; - - /** - * Facet: determine how to render headers/cell - */ - public facet: BaseFacet; - - public tooltip: BaseTooltip; - - // the base container, contains all groups - public container: Canvas; - - public maskContainer: Canvas; - - // the background group, render bgColor... - public backgroundGroup: IGroup; - - // facet cell area group, it contains all cross-tab's cell - public panelGroup: IGroup; - - public maskGroup: IGroup; - - public panelScrollGroup: IGroup; - - public frozenRowGroup: IGroup; - - public frozenColGroup: IGroup; - - public frozenTrailingRowGroup: IGroup; - - public frozenTrailingColGroup: IGroup; - - public frozenTopGroup: IGroup; - - public frozenBottomGroup: IGroup; - - // contains rowHeader,cornerHeader,colHeader, scroll bars - public foregroundGroup: IGroup; - - public interaction: RootInteraction; - - public hdAdapter: HdAdapter; - - private untypedOn = this.on; - - private untypedEmit = this.emit; - - public on = ( - event: K, - listener: EmitterType[K], - ): this => this.untypedOn(event, listener); - - public emit = ( - event: K, - ...args: Parameters - ): boolean => this.untypedEmit(event, ...args); - - public constructor( - dom: S2MountContainer, - dataCfg: S2DataConfig, - options: S2Options, - ) { - super(); - this.dom = this.getMountContainer(dom); - this.dataCfg = safetyDataConfig(dataCfg); - this.options = safetyOptions(options); - this.dataSet = this.getDataSet(this.options); - - this.initTooltip(); - this.initGroups(this.dom, this.options); - this.bindEvents(); - this.initInteraction(); - this.initTheme(); - this.initHdAdapter(); - - DebuggerUtil.getInstance().setDebug(options?.debug); - } - - get isShowTooltip() { - return this.options?.tooltip?.showTooltip ?? true; - } - - private initTheme() { - // When calling spreadsheet directly, there is no theme and initialization is required - this.setThemeCfg({ - name: 'default', - }); - } - - private getMountContainer(dom: S2MountContainer) { - const mountContainer = isString(dom) - ? document.getElementById(dom) - : (dom as HTMLElement); - - if (!mountContainer) { - throw new Error('Target mount container is not a DOM element'); - } - - return mountContainer; - } - - private initHdAdapter() { - if (this.options.hdAdapter) { - this.hdAdapter = new HdAdapter(this); - this.hdAdapter.init(); - } - } - - private initInteraction() { - this.interaction = new RootInteraction(this); - } - - private initTooltip() { - this.tooltip = this.renderTooltip(); - if (!(this.tooltip instanceof BaseTooltip)) { - // eslint-disable-next-line no-console - console.warn( - `[Custom Tooltip]: ${( - this.tooltip as unknown - )?.constructor?.toString()} should be extends from BaseTooltip`, - ); - } - } - - private renderTooltip(): BaseTooltip { - return ( - this.options?.tooltip?.renderTooltip?.(this) || new BaseTooltip(this) - ); - } - - public showTooltip(showOptions: TooltipShowOptions) { - if (this.isShowTooltip) { - this.tooltip.show?.(showOptions); - } - } - - public showTooltipWithInfo( - event: CanvasEvent | MouseEvent, - data: TooltipData[], - options?: TooltipOptions, - ) { - if (!this.isShowTooltip) { - return; - } - const tooltipData = getTooltipData({ - spreadsheet: this, - cellInfos: data, - options, - }); - this.showTooltip({ - data: tooltipData, - position: { - x: event.clientX, - y: event.clientY, - }, - options: { - enterable: true, - ...options, - }, - }); - } - - public hideTooltip() { - if (this.isShowTooltip) { - this.tooltip.hide?.(); - } - } - - public destroyTooltip() { - if (this.isShowTooltip) { - this.tooltip.destroy?.(); - } - } - - private getDataSet = (options: S2Options): BaseDataSet => { - const { mode, dataSet, hierarchyType } = options; - if (dataSet) { - return dataSet(this); - } - - const realDataSet = - hierarchyType === 'customTree' - ? new CustomTreePivotDataSet(this) - : new PivotDataSet(this); - - return mode === 'table' ? new TableDataSet(this) : realDataSet; - }; - - public clearDrillDownData(rowNodeId?: string) { - if (this.dataSet instanceof PivotDataSet) { - this.dataSet.clearDrillDownData(rowNodeId); - this.render(false); - } - } - - /** - * Update data config and keep pre-sort operations - * Group sort params kept in {@see store} and - * Priority: group sort > advanced sort - * @param dataCfg - */ - public setDataCfg(dataCfg: S2DataConfig) { - const newDataCfg = clone(dataCfg); - const lastSortParam = this.store.get('sortParam'); - const { sortParams } = newDataCfg; - newDataCfg.sortParams = [].concat(lastSortParam || [], sortParams || []); - this.dataCfg = safetyDataConfig(newDataCfg); - // clear value ranger after each updated data cfg - clearValueRangeState(this); - } - - public setOptions(options: Partial) { - this.hideTooltip(); - this.options = customMerge(this.options, options); - } - - public render(reloadData = true) { - if (reloadData) { - this.dataSet.setDataCfg(this.dataCfg); - } - this.buildFacet(); - } - - public destroy() { - this.facet.destroy(); - this.hdAdapter?.destroy(); - this.interaction.destroy(); - this.destroyTooltip(); - } - - /** - * Update theme config, if the {@param type} is exists, re-use it, - * otherwise create new one {@see theme} - * @param type string - * @param theme - */ - public setThemeCfg(themeCfg: ThemeCfg) { - const theme = themeCfg?.theme || {}; - this.theme = merge({}, getTheme({ ...themeCfg, spreadsheet: this }), theme); - } - - /** - * Update pagination config which store in {@see options} - * @param pagination - */ - public updatePagination(pagination: Pagination) { - this.options = merge({}, this.options, { - pagination, - }); - - // 清空滚动进度 - this.store.set('scrollX', 0); - this.store.set('scrollY', 0); - } - - /** - * 获取当前表格实际内容高度 - */ - public getContentHeight(): number { - return this.facet.getContentHeight(); - } - - /** - * 修改交叉表画布大小,不用重新加载数据 - * @param width - * @param height - */ - public changeSize(width: number, height: number) { - this.options = merge({}, this.options, { width, height }); - // resize the canvas - this.container.changeSize(width, height); - } - - /** - * tree type must be in strategy mode - */ - public isHierarchyTreeType(): boolean { - const type = this.options.hierarchyType; - // custom tree and tree!!! - return type === 'tree' || type === 'customTree'; - } - - public isColAdaptive(): boolean { - return this.options.style.colCfg?.colWidthType === 'adaptive'; - } - - /** - * Check if is pivot mode - */ - public isPivotMode(): boolean { - return this.options?.mode === 'pivot'; - } - - /** - * Check if is pivot mode - */ - public isTableMode(): boolean { - return this.options?.mode === 'table'; - } - - /** - * Check whether scroll contains row header - * For now contains row header in ListSheet mode by default - */ - public isScrollContainsRowHeader(): boolean { - return !this.freezeRowHeader() || !this.isPivotMode(); - } - - /** - * Scroll Freeze Row Header - */ - public freezeRowHeader(): boolean { - return this.options?.freezeRowHeader; - } - - public getRowNodes(level = -1): Node[] { - if (level === -1) { - return this.facet.layoutResult.rowNodes; - } - return this.facet.layoutResult.rowNodes.filter( - (value) => value.level === level, - ); - } - - public getRealColumnSize(): number { - return size(this.dataCfg.fields?.columns || []) + 1; - } - - /** - * get columnNode in levels, - * @param level -1 = get all - */ - public getColumnNodes(level = -1): Node[] { - if (level === -1) { - return this.facet?.layoutResult.colNodes; - } - return this.facet?.layoutResult.colNodes.filter( - (value) => value.level === level, - ); - } - - /** - * Update scroll's offset, the value can be undefined, - * indicate not update current value - * @param offsetConfig - * default offsetX(horizontal scroll need animation) - * but offsetY(vertical scroll don't need animation) - */ - public updateScrollOffset(offsetConfig: OffsetConfig): void { - this.facet.updateScrollOffset( - merge( - {}, - { - offsetX: { - value: undefined, - animate: false, - }, - offsetY: { - value: undefined, - animate: false, - }, - }, - offsetConfig, - ) as OffsetConfig, - ); - } - - public isValueInCols(): boolean { - return this.dataSet.fields.valueInCols; - } - - public getTooltipDataItemMappingCallback() { - return this.options?.mappingDisplayDataItem; - } - - // 获取当前cell实例 - public getCell( - target: CanvasEvent['target'], - ): T { - let parent = target; - // 一直索引到g顶层的canvas来检查是否在指定的cell中 - while (parent && !(parent instanceof Canvas)) { - if (parent instanceof BaseCell) { - // 在单元格中,返回true - return parent as T; - } - parent = parent.get('parent'); - } - return null; - } - - // 获取当前cell类型 - public getCellType(target: CanvasEvent['target']) { - const cell = this.getCell(target); - return cell?.cellType; - } - - /** - * get total's config by dimension id - * @param dimension unique dimension id - */ - public getTotalsConfig(dimension: string): Partial { - const { totals } = this.options; - const { rows } = this.dataCfg.fields; - const totalConfig = get( - totals, - includes(rows, dimension) ? 'row' : 'col', - {}, - ) as Total; - const showSubTotals = totalConfig.showSubTotals - ? includes(totalConfig.subTotalsDimensions, dimension) - : false; - return { - showSubTotals, - showGrandTotals: totalConfig.showGrandTotals, - reverseLayout: totalConfig.reverseLayout, - reverseSubLayout: totalConfig.reverseSubLayout, - label: totalConfig.label || i18n('总计'), - subLabel: totalConfig.subLabel || i18n('小计'), - }; - } - - /** - * Create all related groups, contains: - * 1. container -- base canvas group - * 2. backgroundGroup - * 3. panelGroup -- main facet group belongs to - * 4. foregroundGroup - * @param dom - * @param options - * @private - */ - protected initGroups(dom: HTMLElement, options: S2Options) { - const { width, height } = options; - // base canvas group - this.container = new Canvas({ - container: dom, - width, - height, - localRefresh: false, - }); - - // the main three layer groups - this.backgroundGroup = this.container.addGroup({ - name: KEY_GROUP_BACK_GROUND, - zIndex: BACK_GROUND_GROUP_CONTAINER_Z_INDEX, - }); - this.panelGroup = this.container.addGroup({ - name: KEY_GROUP_PANEL_GROUND, - zIndex: PANEL_GROUP_GROUP_CONTAINER_Z_INDEX, - }); - this.foregroundGroup = this.container.addGroup({ - name: KEY_GROUP_FORE_GROUND, - zIndex: FRONT_GROUND_GROUP_CONTAINER_Z_INDEX, - }); - this.initPanelGroupChildren(); - } - - protected initPanelGroupChildren(): void { - this.panelScrollGroup = this.panelGroup.addGroup({ - name: KEY_GROUP_PANEL_SCROLL, - zIndex: PANEL_GROUP_SCROLL_GROUP_Z_INDEX, - }); - this.frozenRowGroup = this.panelGroup.addGroup({ - name: KEY_GROUP_PANEL_FROZEN_ROW, - zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, - }); - this.frozenColGroup = this.panelGroup.addGroup({ - name: KEY_GROUP_PANEL_FROZEN_COL, - zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, - }); - this.frozenTrailingRowGroup = this.panelGroup.addGroup({ - name: KEY_GROUP_PANEL_FROZEN_TRAILING_ROW, - zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, - }); - this.frozenTrailingColGroup = this.panelGroup.addGroup({ - name: KEY_GROUP_PANEL_FROZEN_TRAILING_COL, - zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, - }); - this.frozenTopGroup = this.panelGroup.addGroup({ - name: KEY_GROUP_PANEL_FROZEN_TOP, - zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, - }); - this.frozenBottomGroup = this.panelGroup.addGroup({ - name: KEY_GROUP_PANEL_FROZEN_BOTTOM, - zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, - }); - } - - /** - * 避免每次新增、变更dataSet和options时,生成SpreadSheetFacetCfg - * 要多出定义匹配的问题,直接按需&部分拆分options/dataSet合并为facetCfg - */ - protected getFacetCfgFromDataSetAndOptions = (): SpreadSheetFacetCfg => { - const { fields, meta } = this.dataSet; - const { style, dataCell } = this.options; - // 默认单元格实现 - const defaultCell = (facet: ViewMeta) => { - if (this.isTableMode()) { - if (this.options.showSeriesNumber && facet.colIndex === 0) { - return new TableRowCell(facet, this); - } - return new TableDataCell(facet, this); - } - return new DataCell(facet, this); - }; - return { - ...fields, - ...style, - ...this.options, - meta, - spreadsheet: this, - dataSet: this.dataSet, - dataCell: dataCell ?? defaultCell, - }; - }; - - protected buildFacet = () => { - const facetCfg = this.getFacetCfgFromDataSetAndOptions(); - this.facet?.destroy(); - this.facet = this.isPivotMode() - ? new PivotFacet(facetCfg) - : new TableFacet(facetCfg); - - this.facet.render(); - }; - - protected bindEvents() { - this.off(S2Event.ROW_CELL_COLLAPSE_TREE_ROWS); - this.off(S2Event.LAYOUT_TREE_ROWS_COLLAPSE_ALL); - // collapse rows in tree mode of SpreadSheet - this.on( - S2Event.ROW_CELL_COLLAPSE_TREE_ROWS, - this.handleRowCellCollapseTreeRows, - ); - // 收起、展开按钮 - this.on( - S2Event.LAYOUT_TREE_ROWS_COLLAPSE_ALL, - this.handleTreeRowsCollapseAll, - ); - } - - protected handleRowCellCollapseTreeRows(data: RowCellCollapseTreeRowsType) { - const { id, isCollapsed } = data; - const options: Partial = { - style: { - collapsedRows: { - [id]: isCollapsed, - }, - }, - }; - // post to x-report to store state - this.emit(S2Event.LAYOUT_COLLAPSE_ROWS, { - collapsedRows: options.style.collapsedRows, - }); - this.setOptions(options); - this.render(false); - this.emit(S2Event.LAYOUT_AFTER_COLLAPSE_ROWS, { - collapsedRows: options.style.collapsedRows, - }); - } - - protected handleTreeRowsCollapseAll(isCollapsed: boolean) { - const options: Partial = { - hierarchyCollapse: !isCollapsed, - style: { - collapsedRows: {}, // 清空用户操作的缓存 - }, - }; - this.setOptions(options); - this.render(false); - } -} +export { PivotSheet, TableSheet, SpreadSheet }; diff --git a/packages/s2-core/src/sheet-type/pivot-sheet.ts b/packages/s2-core/src/sheet-type/pivot-sheet.ts new file mode 100644 index 0000000000..7b6863a546 --- /dev/null +++ b/packages/s2-core/src/sheet-type/pivot-sheet.ts @@ -0,0 +1,145 @@ +import { SpreadSheet } from './spread-sheet'; +import { DataCell } from '@/cell'; +import { S2Event } from '@/common/constant'; +import { S2Options, SpreadSheetFacetCfg, ViewMeta } from '@/common/interface'; +import { RowCellCollapseTreeRowsType } from '@/common/interface/emitter'; +import { PivotDataSet } from '@/data-set'; +import { CustomTreePivotDataSet } from '@/data-set/custom-tree-pivot-data-set'; +import { PivotFacet } from '@/facet'; + +export class PivotSheet extends SpreadSheet { + public getDataSet(options: S2Options) { + const { dataSet, hierarchyType } = options; + if (dataSet) { + return dataSet(this); + } + + const realDataSet = + hierarchyType === 'customTree' + ? new CustomTreePivotDataSet(this) + : new PivotDataSet(this); + return realDataSet; + } + + /** + * Check if is pivot mode + */ + public isPivotMode(): boolean { + return true; + } + + /** + * Check if is pivot mode + */ + public isTableMode(): boolean { + return false; + } + + /** + * tree type must be in strategy mode + */ + public isHierarchyTreeType(): boolean { + const type = this.options.hierarchyType; + // custom tree and tree!!! + return type === 'tree' || type === 'customTree'; + } + + /** + * Check whether scroll contains row header + * For now contains row header in ListSheet mode by default + */ + public isScrollContainsRowHeader(): boolean { + return !this.freezeRowHeader(); + } + + /** + * Scroll Freeze Row Header + */ + public freezeRowHeader(): boolean { + return this.options?.freezeRowHeader; + } + + /** + * Check if the value is in the columns + */ + public isValueInCols(): boolean { + return this.dataSet.fields.valueInCols; + } + + public clearDrillDownData(rowNodeId?: string) { + if (this.dataSet instanceof PivotDataSet) { + this.dataSet.clearDrillDownData(rowNodeId); + this.render(false); + } + } + + protected getFacetCfgFromDataSetAndOptions(): SpreadSheetFacetCfg { + const { fields, meta } = this.dataSet; + const { style, dataCell } = this.options; + // 默认单元格实现 + const defaultCell = (facet: ViewMeta) => new DataCell(facet, this); + + return { + ...fields, + ...style, + ...this.options, + meta, + spreadsheet: this, + dataSet: this.dataSet, + dataCell: dataCell ?? defaultCell, + }; + } + + protected buildFacet() { + const facetCfg = this.getFacetCfgFromDataSetAndOptions(); + this.facet?.destroy(); + this.facet = new PivotFacet(facetCfg); + this.facet.render(); + } + + protected bindEvents() { + this.off(S2Event.ROW_CELL_COLLAPSE_TREE_ROWS); + this.off(S2Event.LAYOUT_TREE_ROWS_COLLAPSE_ALL); + // collapse rows in tree mode of SpreadSheet + this.on( + S2Event.ROW_CELL_COLLAPSE_TREE_ROWS, + this.handleRowCellCollapseTreeRows, + ); + // 收起、展开按钮 + this.on( + S2Event.LAYOUT_TREE_ROWS_COLLAPSE_ALL, + this.handleTreeRowsCollapseAll, + ); + } + + protected handleRowCellCollapseTreeRows(data: RowCellCollapseTreeRowsType) { + const { id, isCollapsed } = data; + const options: Partial = { + style: { + collapsedRows: { + [id]: isCollapsed, + }, + }, + }; + // post to x-report to store state + this.emit(S2Event.LAYOUT_COLLAPSE_ROWS, { + collapsedRows: options.style.collapsedRows, + }); + this.setOptions(options); + this.render(false); + this.emit(S2Event.LAYOUT_AFTER_COLLAPSE_ROWS, { + collapsedRows: options.style.collapsedRows, + }); + } + + protected handleTreeRowsCollapseAll(isCollapsed: boolean) { + const options: Partial = { + hierarchyCollapse: !isCollapsed, + style: { + collapsedRows: {}, // 清空用户操作的缓存 + }, + }; + this.setOptions(options); + this.render(false); + } +} diff --git a/packages/s2-core/src/sheet-type/spread-sheet.ts b/packages/s2-core/src/sheet-type/spread-sheet.ts new file mode 100644 index 0000000000..ddbb1987b9 --- /dev/null +++ b/packages/s2-core/src/sheet-type/spread-sheet.ts @@ -0,0 +1,514 @@ +import EE from '@antv/event-emitter'; +import { Canvas, Event as CanvasEvent, IGroup } from '@antv/g-canvas'; +import { clone, get, includes, isString, merge, size } from 'lodash'; +import { BaseCell } from '@/cell'; +import { + BACK_GROUND_GROUP_CONTAINER_Z_INDEX, + FRONT_GROUND_GROUP_CONTAINER_Z_INDEX, + KEY_GROUP_BACK_GROUND, + KEY_GROUP_FORE_GROUND, + KEY_GROUP_PANEL_GROUND, + KEY_GROUP_PANEL_SCROLL, + PANEL_GROUP_GROUP_CONTAINER_Z_INDEX, + PANEL_GROUP_SCROLL_GROUP_Z_INDEX, +} from '@/common/constant'; +import { DebuggerUtil } from '@/common/debug'; +import { i18n } from '@/common/i18n'; +import { + OffsetConfig, + Pagination, + S2CellType, + S2DataConfig, + S2MountContainer, + S2Options, + safetyDataConfig, + safetyOptions, + SpreadSheetFacetCfg, + ThemeCfg, + TooltipData, + TooltipOptions, + TooltipShowOptions, + Total, + Totals, +} from '@/common/interface'; +import { EmitterType } from '@/common/interface/emitter'; +import { Store } from '@/common/store'; +import { BaseDataSet } from '@/data-set'; + +import { BaseFacet } from '@/facet'; +import { Node, SpreadSheetTheme } from '@/index'; +import { RootInteraction } from '@/interaction/root'; +import { getTheme } from '@/theme'; +import { HdAdapter } from '@/ui/hd-adapter'; +import { BaseTooltip } from '@/ui/tooltip'; +import { clearValueRangeState } from '@/utils/condition/state-controller'; +import { customMerge } from '@/utils/merge'; +import { getTooltipData } from '@/utils/tooltip'; + +export abstract class SpreadSheet extends EE { + // dom id + public dom: S2MountContainer; + + // theme config + public theme: SpreadSheetTheme; + + // store some temporary data + public store = new Store(); + + // the original data config + public dataCfg: S2DataConfig; + + // Spreadsheet's configurations + public options: S2Options; + + /** + * processed data structure, include {@link Fields}, {@link Meta} + * {@link Data}, {@link SortParams} + */ + public dataSet: BaseDataSet; + + /** + * Facet: determine how to render headers/cell + */ + public facet: BaseFacet; + + public tooltip: BaseTooltip; + + // the base container, contains all groups + public container: Canvas; + + public maskContainer: Canvas; + + // the background group, render bgColor... + public backgroundGroup: IGroup; + + // facet cell area group, it contains all cross-tab's cell + public panelGroup: IGroup; + + public maskGroup: IGroup; + + public panelScrollGroup: IGroup; + + public frozenRowGroup: IGroup; + + public frozenColGroup: IGroup; + + public frozenTrailingRowGroup: IGroup; + + public frozenTrailingColGroup: IGroup; + + public frozenTopGroup: IGroup; + + public frozenBottomGroup: IGroup; + + // contains rowHeader,cornerHeader,colHeader, scroll bars + public foregroundGroup: IGroup; + + public interaction: RootInteraction; + + public hdAdapter: HdAdapter; + + private untypedOn = this.on; + + private untypedEmit = this.emit; + + public on = ( + event: K, + listener: EmitterType[K], + ): this => this.untypedOn(event, listener); + + public emit = ( + event: K, + ...args: Parameters + ): boolean => this.untypedEmit(event, ...args); + + public constructor( + dom: S2MountContainer, + dataCfg: S2DataConfig, + options: S2Options, + ) { + super(); + this.dom = this.getMountContainer(dom); + this.dataCfg = safetyDataConfig(dataCfg); + this.options = safetyOptions(options); + this.dataSet = this.getDataSet(this.options); + + this.initTooltip(); + this.initGroups(this.dom, this.options); + this.bindEvents(); + this.initInteraction(); + this.initTheme(); + this.initHdAdapter(); + + DebuggerUtil.getInstance().setDebug(options?.debug); + } + + get isShowTooltip() { + return this.options?.tooltip?.showTooltip ?? true; + } + + private initTheme() { + // When calling spreadsheet directly, there is no theme and initialization is required + this.setThemeCfg({ + name: 'default', + }); + } + + private getMountContainer(dom: S2MountContainer) { + const mountContainer = isString(dom) + ? document.getElementById(dom) + : (dom as HTMLElement); + + if (!mountContainer) { + throw new Error('Target mount container is not a DOM element'); + } + + return mountContainer; + } + + private initHdAdapter() { + if (this.options.hdAdapter) { + this.hdAdapter = new HdAdapter(this); + this.hdAdapter.init(); + } + } + + private initInteraction() { + this.interaction = new RootInteraction(this); + } + + private initTooltip() { + this.tooltip = this.renderTooltip(); + if (!(this.tooltip instanceof BaseTooltip)) { + // eslint-disable-next-line no-console + console.warn( + `[Custom Tooltip]: ${( + this.tooltip as unknown + )?.constructor?.toString()} should be extends from BaseTooltip`, + ); + } + } + + private renderTooltip(): BaseTooltip { + return ( + this.options?.tooltip?.renderTooltip?.(this) || new BaseTooltip(this) + ); + } + + protected abstract bindEvents(); + + public abstract getDataSet(options: S2Options): BaseDataSet; + + /** + * Check if is pivot mode + */ + public abstract isPivotMode(): boolean; + + /** + * tree type must be in strategy mode + */ + public abstract isHierarchyTreeType(): boolean; + + /** + * Check whether scroll contains row header + * For now contains row header in ListSheet mode by default + */ + public abstract isScrollContainsRowHeader(): boolean; + + /** + * Scroll Freeze Row Header + */ + public abstract freezeRowHeader(): boolean; + + /** + * Check if is pivot mode + */ + public abstract isTableMode(): boolean; + + /** + * Check if the value is in the columns + */ + public abstract isValueInCols(): boolean; + + /** + * 避免每次新增、变更dataSet和options时,生成SpreadSheetFacetCfg + * 要多出定义匹配的问题,直接按需&部分拆分options/dataSet合并为facetCfg + */ + protected abstract getFacetCfgFromDataSetAndOptions(): SpreadSheetFacetCfg; + + protected abstract buildFacet(): void; + + public abstract clearDrillDownData(owNodeId?: string): void; + + public showTooltip(showOptions: TooltipShowOptions) { + if (this.isShowTooltip) { + this.tooltip.show?.(showOptions); + } + } + + public showTooltipWithInfo( + event: CanvasEvent | MouseEvent, + data: TooltipData[], + options?: TooltipOptions, + ) { + if (!this.isShowTooltip) { + return; + } + const tooltipData = getTooltipData({ + spreadsheet: this, + cellInfos: data, + options, + }); + this.showTooltip({ + data: tooltipData, + position: { + x: event.clientX, + y: event.clientY, + }, + options: { + enterable: true, + ...options, + }, + }); + } + + public hideTooltip() { + if (this.isShowTooltip) { + this.tooltip.hide?.(); + } + } + + public destroyTooltip() { + if (this.isShowTooltip) { + this.tooltip.destroy?.(); + } + } + + /** + * Update data config and keep pre-sort operations + * Group sort params kept in {@see store} and + * Priority: group sort > advanced sort + * @param dataCfg + */ + public setDataCfg(dataCfg: S2DataConfig) { + const newDataCfg = clone(dataCfg); + const lastSortParam = this.store.get('sortParam'); + const { sortParams } = newDataCfg; + newDataCfg.sortParams = [].concat(lastSortParam || [], sortParams || []); + this.dataCfg = safetyDataConfig(newDataCfg); + // clear value ranger after each updated data cfg + clearValueRangeState(this); + } + + public setOptions(options: Partial) { + this.hideTooltip(); + this.options = customMerge(this.options, options); + } + + public render(reloadData = true) { + if (reloadData) { + this.dataSet.setDataCfg(this.dataCfg); + } + this.buildFacet(); + } + + public destroy() { + this.facet.destroy(); + this.hdAdapter?.destroy(); + this.interaction.destroy(); + this.destroyTooltip(); + } + + /** + * Update theme config, if the {@param type} is exists, re-use it, + * otherwise create new one {@see theme} + * @param type string + * @param theme + */ + public setThemeCfg(themeCfg: ThemeCfg) { + const theme = themeCfg?.theme || {}; + this.theme = merge({}, getTheme({ ...themeCfg, spreadsheet: this }), theme); + } + + /** + * Update pagination config which store in {@see options} + * @param pagination + */ + public updatePagination(pagination: Pagination) { + this.options = merge({}, this.options, { + pagination, + }); + + // 清空滚动进度 + this.store.set('scrollX', 0); + this.store.set('scrollY', 0); + } + + /** + * 获取当前表格实际内容高度 + */ + public getContentHeight(): number { + return this.facet.getContentHeight(); + } + + /** + * 修改交叉表画布大小,不用重新加载数据 + * @param width + * @param height + */ + public changeSize(width: number, height: number) { + this.options = merge({}, this.options, { width, height }); + // resize the canvas + this.container.changeSize(width, height); + } + + public isColAdaptive(): boolean { + return this.options.style.colCfg?.colWidthType === 'adaptive'; + } + + public getRowNodes(level = -1): Node[] { + if (level === -1) { + return this.facet.layoutResult.rowNodes; + } + return this.facet.layoutResult.rowNodes.filter( + (value) => value.level === level, + ); + } + + public getRealColumnSize(): number { + return size(this.dataCfg.fields?.columns || []) + 1; + } + + /** + * get columnNode in levels, + * @param level -1 = get all + */ + public getColumnNodes(level = -1): Node[] { + if (level === -1) { + return this.facet?.layoutResult.colNodes; + } + return this.facet?.layoutResult.colNodes.filter( + (value) => value.level === level, + ); + } + + /** + * Update scroll's offset, the value can be undefined, + * indicate not update current value + * @param offsetConfig + * default offsetX(horizontal scroll need animation) + * but offsetY(vertical scroll don't need animation) + */ + public updateScrollOffset(offsetConfig: OffsetConfig): void { + this.facet.updateScrollOffset( + merge( + {}, + { + offsetX: { + value: undefined, + animate: false, + }, + offsetY: { + value: undefined, + animate: false, + }, + }, + offsetConfig, + ) as OffsetConfig, + ); + } + + public getTooltipDataItemMappingCallback() { + return this.options?.mappingDisplayDataItem; + } + + // 获取当前cell实例 + public getCell( + target: CanvasEvent['target'], + ): T { + let parent = target; + // 一直索引到g顶层的canvas来检查是否在指定的cell中 + while (parent && !(parent instanceof Canvas)) { + if (parent instanceof BaseCell) { + // 在单元格中,返回true + return parent as T; + } + parent = parent.get('parent'); + } + return null; + } + + // 获取当前cell类型 + public getCellType(target: CanvasEvent['target']) { + const cell = this.getCell(target); + return cell?.cellType; + } + + /** + * get total's config by dimension id + * @param dimension unique dimension id + */ + public getTotalsConfig(dimension: string): Partial { + const { totals } = this.options; + const { rows } = this.dataCfg.fields; + const totalConfig = get( + totals, + includes(rows, dimension) ? 'row' : 'col', + {}, + ) as Total; + const showSubTotals = totalConfig.showSubTotals + ? includes(totalConfig.subTotalsDimensions, dimension) + : false; + return { + showSubTotals, + showGrandTotals: totalConfig.showGrandTotals, + reverseLayout: totalConfig.reverseLayout, + reverseSubLayout: totalConfig.reverseSubLayout, + label: totalConfig.label || i18n('总计'), + subLabel: totalConfig.subLabel || i18n('小计'), + }; + } + + /** + * Create all related groups, contains: + * 1. container -- base canvas group + * 2. backgroundGroup + * 3. panelGroup -- main facet group belongs to + * 4. foregroundGroup + * @param dom + * @param options + * @private + */ + protected initGroups(dom: HTMLElement, options: S2Options) { + const { width, height } = options; + // base canvas group + this.container = new Canvas({ + container: dom, + width, + height, + localRefresh: false, + }); + + // the main three layer groups + this.backgroundGroup = this.container.addGroup({ + name: KEY_GROUP_BACK_GROUND, + zIndex: BACK_GROUND_GROUP_CONTAINER_Z_INDEX, + }); + this.panelGroup = this.container.addGroup({ + name: KEY_GROUP_PANEL_GROUND, + zIndex: PANEL_GROUP_GROUP_CONTAINER_Z_INDEX, + }); + this.foregroundGroup = this.container.addGroup({ + name: KEY_GROUP_FORE_GROUND, + zIndex: FRONT_GROUND_GROUP_CONTAINER_Z_INDEX, + }); + this.initPanelGroupChildren(); + } + + protected initPanelGroupChildren(): void { + this.panelScrollGroup = this.panelGroup.addGroup({ + name: KEY_GROUP_PANEL_SCROLL, + zIndex: PANEL_GROUP_SCROLL_GROUP_Z_INDEX, + }); + } +} diff --git a/packages/s2-core/src/sheet-type/table-sheet.ts b/packages/s2-core/src/sheet-type/table-sheet.ts new file mode 100644 index 0000000000..7c6fd5996c --- /dev/null +++ b/packages/s2-core/src/sheet-type/table-sheet.ts @@ -0,0 +1,127 @@ +import { SpreadSheet } from './spread-sheet'; +import { TableDataCell, TableRowCell } from '@/cell'; +import { + KEY_GROUP_PANEL_FROZEN_BOTTOM, + KEY_GROUP_PANEL_FROZEN_COL, + KEY_GROUP_PANEL_FROZEN_ROW, + KEY_GROUP_PANEL_FROZEN_TOP, + KEY_GROUP_PANEL_FROZEN_TRAILING_COL, + KEY_GROUP_PANEL_FROZEN_TRAILING_ROW, + PANEL_GROUP_FROZEN_GROUP_Z_INDEX, +} from '@/common/constant'; +import { S2Options, SpreadSheetFacetCfg, ViewMeta } from '@/common/interface'; +import { TableDataSet } from '@/data-set'; +import { TableFacet } from '@/facet'; +export class TableSheet extends SpreadSheet { + public getDataSet(options: S2Options) { + const { dataSet } = options; + if (dataSet) { + return dataSet(this); + } + + return new TableDataSet(this); + } + + /** + * Check if is pivot mode + */ + public isPivotMode(): boolean { + return false; + } + + /** + * Check if is pivot mode + */ + public isTableMode(): boolean { + return true; + } + + /** + * tree type must be in strategy mode + */ + public isHierarchyTreeType(): boolean { + return false; + } + + /** + * Check whether scroll contains row header + * For now contains row header in ListSheet mode by default + */ + public isScrollContainsRowHeader(): boolean { + return false; + } + + /** + * Scroll Freeze Row Header + */ + public freezeRowHeader(): boolean { + return false; + } + + public clearDrillDownData(): void {} + + /** + * Check if the value is in the columns + */ + public isValueInCols(): boolean { + return false; + } + + protected bindEvents() {} + + protected initPanelGroupChildren(): void { + super.initPanelGroupChildren(); + this.frozenRowGroup = this.panelGroup.addGroup({ + name: KEY_GROUP_PANEL_FROZEN_ROW, + zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, + }); + this.frozenColGroup = this.panelGroup.addGroup({ + name: KEY_GROUP_PANEL_FROZEN_COL, + zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, + }); + this.frozenTrailingRowGroup = this.panelGroup.addGroup({ + name: KEY_GROUP_PANEL_FROZEN_TRAILING_ROW, + zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, + }); + this.frozenTrailingColGroup = this.panelGroup.addGroup({ + name: KEY_GROUP_PANEL_FROZEN_TRAILING_COL, + zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, + }); + this.frozenTopGroup = this.panelGroup.addGroup({ + name: KEY_GROUP_PANEL_FROZEN_TOP, + zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, + }); + this.frozenBottomGroup = this.panelGroup.addGroup({ + name: KEY_GROUP_PANEL_FROZEN_BOTTOM, + zIndex: PANEL_GROUP_FROZEN_GROUP_Z_INDEX, + }); + } + + protected getFacetCfgFromDataSetAndOptions(): SpreadSheetFacetCfg { + const { fields, meta } = this.dataSet; + const { style, dataCell } = this.options; + // 默认单元格实现 + const defaultCell = (facet: ViewMeta) => { + if (this.options.showSeriesNumber && facet.colIndex === 0) { + return new TableRowCell(facet, this); + } + return new TableDataCell(facet, this); + }; + return { + ...fields, + ...style, + ...this.options, + meta, + spreadsheet: this, + dataSet: this.dataSet, + dataCell: dataCell ?? defaultCell, + }; + } + + protected buildFacet() { + const facetCfg = this.getFacetCfgFromDataSetAndOptions(); + this.facet?.destroy(); + this.facet = new TableFacet(facetCfg); + this.facet.render(); + } +} diff --git a/s2-site/examples/basic/pivot/demo/grid.ts b/s2-site/examples/basic/pivot/demo/grid.ts index 1d30be34e6..20bde7ba39 100644 --- a/s2-site/examples/basic/pivot/demo/grid.ts +++ b/s2-site/examples/basic/pivot/demo/grid.ts @@ -1,4 +1,4 @@ -import { SpreadSheet } from '@antv/s2'; +import { PivotSheet } from '@antv/s2'; import '@antv/s2/dist/s2.min.css'; fetch('../data/basic.json') @@ -18,7 +18,7 @@ fetch('../data/basic.json') width: 600, height: 600, }; - const s2 = new SpreadSheet(container, s2DataConfig, s2options); + const s2 = new PivotSheet(container, s2DataConfig, s2options); s2.render(); }); diff --git a/s2-site/examples/basic/pivot/demo/tree.ts b/s2-site/examples/basic/pivot/demo/tree.ts index 05b3e7725d..a9bf9fb4be 100644 --- a/s2-site/examples/basic/pivot/demo/tree.ts +++ b/s2-site/examples/basic/pivot/demo/tree.ts @@ -1,4 +1,4 @@ -import { SpreadSheet } from '@antv/s2'; +import { PivotSheet } from '@antv/s2'; import '@antv/s2/dist/s2.min.css'; fetch('../data/basic.json') @@ -19,7 +19,7 @@ fetch('../data/basic.json') height: 600, hierarchyType: 'tree', }; - const s2 = new SpreadSheet(container, s2DataConfig, s2options); + const s2 = new PivotSheet(container, s2DataConfig, s2options); s2.render(); }); diff --git a/yarn.lock b/yarn.lock index 3f1c1cc796..7fe57c8941 100644 --- a/yarn.lock +++ b/yarn.lock @@ -382,7 +382,7 @@ core-js-pure "^3.16.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== @@ -1926,6 +1926,14 @@ dependencies: "@types/node" "*" +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" @@ -2023,6 +2031,13 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== +"@types/react-beautiful-dnd@^13.1.2": + version "13.1.2" + resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.2.tgz#510405abb09f493afdfd898bf83995dc6385c130" + integrity sha512-+OvPkB8CdE/bGdXKyIhc/Lm2U7UAYCCJgsqmopFmh9gbAudmslkI8eOrPDjg4JhwSE6wytz4a3/wRjKtovHVJg== + dependencies: + "@types/react" "*" + "@types/react-dom@17.0.9", "@types/react-dom@>=16.9.0": version "17.0.9" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.9.tgz#441a981da9d7be117042e1a6fd3dac4b30f55add" @@ -2030,6 +2045,16 @@ dependencies: "@types/react" "*" +"@types/react-redux@^7.1.16": + version "7.1.18" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.18.tgz#2bf8fd56ebaae679a90ebffe48ff73717c438e04" + integrity sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react-test-renderer@>=16.9.0": version "17.0.1" resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3120f7d1c157fba9df0118dae20cb0297ee0e06b" @@ -3848,6 +3873,13 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +css-box-model@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" + integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== + dependencies: + tiny-invariant "^1.0.6" + css-color-names@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-1.0.1.tgz#6ff7ee81a823ad46e020fa2fd6ab40a887e2ba67" @@ -5802,6 +5834,13 @@ highlight.js@^10.7.1: resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -8151,6 +8190,11 @@ mdn-data@2.0.14: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== +memoize-one@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" @@ -10067,6 +10111,11 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +raf-schd@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" + integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== + randomatic@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" @@ -10437,6 +10486,19 @@ rc@^1.2.1, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-beautiful-dnd@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz#ec97c81093593526454b0de69852ae433783844d" + integrity sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA== + dependencies: + "@babel/runtime" "^7.9.2" + css-box-model "^1.2.0" + memoize-one "^5.1.1" + raf-schd "^4.0.2" + react-redux "^7.2.0" + redux "^4.0.4" + use-memo-one "^1.1.1" + react-dom@^16.14.0: version "16.14.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" @@ -10454,7 +10516,7 @@ react-error-boundary@^3.1.0: dependencies: "@babel/runtime" "^7.12.5" -react-is@^16.12.0, react-is@^16.8.1, react-is@^16.8.4: +react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -10464,6 +10526,18 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-redux@^7.2.0: + version "7.2.5" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.5.tgz#213c1b05aa1187d9c940ddfc0b29450957f6a3b8" + integrity sha512-Dt29bNyBsbQaysp6s/dN0gUodcq+dVKKER8Qv82UrpeygwYeX1raTtil7O/fftw/rFqzaf6gJhDZRkkZnn6bjg== + dependencies: + "@babel/runtime" "^7.12.1" + "@types/react-redux" "^7.1.16" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.13.1" + react@^16.14.0: version "16.14.0" resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" @@ -10667,6 +10741,13 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redux@^4.0.0, redux@^4.0.4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.1.tgz#76f1c439bb42043f985fbd9bf21990e60bd67f47" + integrity sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw== + dependencies: + "@babel/runtime" "^7.9.2" + regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -12093,6 +12174,11 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-invariant@^1.0.6: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" + integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -12458,6 +12544,11 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +use-memo-one@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.2.tgz#0c8203a329f76e040047a35a1197defe342fab20" + integrity sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ== + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"