diff --git a/packages/s2-core/__tests__/spreadsheet/__snapshots__/theme-spec.ts.snap b/packages/s2-core/__tests__/spreadsheet/__snapshots__/theme-spec.ts.snap index 7e8b2d3100..806d4e2c9a 100644 --- a/packages/s2-core/__tests__/spreadsheet/__snapshots__/theme-spec.ts.snap +++ b/packages/s2-core/__tests__/spreadsheet/__snapshots__/theme-spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`SpreadSheet Theme Tests Theme Default Value Tests should get default theme 1`] = ` +exports[`SpreadSheet Theme Tests Theme Default Value Tests should get pivot sheet default theme 1`] = ` Object { "background": Object { "color": "#FFFFFF", @@ -533,3 +533,537 @@ Object { }, } `; + +exports[`SpreadSheet Theme Tests Theme Default Value Tests should get table sheet theme 1`] = ` +Object { + "background": Object { + "color": "#FFFFFF", + "opacity": 1, + }, + "colCell": Object { + "bolderText": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": 700, + "opacity": 1, + "textAlign": "center", + "textBaseline": "middle", + }, + "cell": Object { + "backgroundColor": "#E0E9FD", + "backgroundColorOpacity": 1, + "borderDash": Array [], + "horizontalBorderColor": "#CCDBFC", + "horizontalBorderColorOpacity": 1, + "horizontalBorderWidth": 1, + "interactionState": Object { + "highlight": Object { + "backgroundColor": "#87B5FF", + "backgroundOpacity": 1, + }, + "hover": Object { + "backgroundColor": "#CCDBFC", + "backgroundOpacity": 0.6, + }, + "prepareSelect": Object { + "borderColor": "#000000", + "borderOpacity": 1, + "borderWidth": 1, + }, + "searchResult": Object { + "backgroundColor": "#F0F7FF", + "backgroundOpacity": 1, + }, + "selected": Object { + "backgroundColor": "#CCDBFC", + "backgroundOpacity": 0.6, + }, + "unselected": Object { + "backgroundOpacity": 0.3, + "opacity": 0.3, + "textOpacity": 0.3, + }, + }, + "padding": Object { + "bottom": 0, + "left": 8, + "right": 8, + "top": 0, + }, + "verticalBorderColor": "#CCDBFC", + "verticalBorderColorOpacity": 1, + "verticalBorderWidth": 1, + }, + "icon": Object { + "fill": "#000000", + "margin": Object { + "bottom": 6, + "left": 4, + "right": 4, + "top": 6, + }, + "size": 10, + }, + "measureText": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "opacity": 1, + "textAlign": "right", + "textBaseline": "middle", + }, + "text": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "opacity": 1, + "textAlign": "center", + "textBaseline": "middle", + }, + }, + "cornerCell": Object { + "bolderText": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": 700, + "opacity": 1, + "textAlign": "center", + "textBaseline": "middle", + }, + "cell": Object { + "backgroundColor": "#E0E9FD", + "backgroundColorOpacity": 1, + "borderDash": Array [], + "horizontalBorderColor": "#CCDBFC", + "horizontalBorderColorOpacity": 1, + "horizontalBorderWidth": 1, + "padding": Object { + "bottom": 0, + "left": 8, + "right": 8, + "top": 0, + }, + "verticalBorderColor": "#CCDBFC", + "verticalBorderColorOpacity": 1, + "verticalBorderWidth": 1, + }, + "icon": Object { + "fill": "#000000", + "margin": Object { + "left": 4, + "right": 4, + }, + "size": 10, + }, + "text": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": 700, + "opacity": 1, + "textAlign": "right", + "textBaseline": "middle", + }, + }, + "dataCell": Object { + "bolderText": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": 700, + "linkTextFill": "#326EF4", + "opacity": 1, + "textAlign": "right", + "textBaseline": "middle", + }, + "cell": Object { + "backgroundColor": "#FFFFFF", + "backgroundColorOpacity": 1, + "borderDash": Array [], + "crossBackgroundColor": "#F5F8FE", + "horizontalBorderColor": "#E0E9FD", + "horizontalBorderColorOpacity": 1, + "horizontalBorderWidth": 1, + "interactionState": Object { + "highlight": Object { + "backgroundColor": "#87B5FF", + "backgroundOpacity": 1, + }, + "hover": Object { + "backgroundColor": "#E0E9FD", + "backgroundOpacity": 0.6, + }, + "hoverFocus": Object { + "backgroundColor": "#E0E9FD", + "backgroundOpacity": 0.6, + "borderColor": "#000000", + "borderOpacity": 1, + "borderWidth": 1, + }, + "prepareSelect": Object { + "borderColor": "#000000", + "borderOpacity": 1, + "borderWidth": 1, + }, + "searchResult": Object { + "backgroundColor": "#F0F7FF", + "backgroundOpacity": 1, + }, + "selected": Object { + "backgroundColor": "#E0E9FD", + "backgroundOpacity": 0.6, + }, + "unselected": Object { + "backgroundOpacity": 0.3, + "opacity": 0.3, + "textOpacity": 0.3, + }, + }, + "padding": Object { + "bottom": 8, + "left": 8, + "right": 8, + "top": 8, + }, + "verticalBorderColor": "#E0E9FD", + "verticalBorderColorOpacity": 1, + "verticalBorderWidth": 1, + }, + "icon": Object { + "downIconColor": "#FF4D4F", + "fill": "#000000", + "margin": Object { + "left": 4, + "right": 4, + }, + "size": 10, + "upIconColor": "#29A294", + }, + "miniChart": Object { + "bar": Object { + "fill": "#326EF4", + "intervalPadding": 4, + "opacity": 1, + }, + "bullet": Object { + "backgroundColor": "#E9E9E9", + "comparativeMeasure": Object { + "fill": "#000000", + "height": 12, + "opacity": 0.25, + "width": 1, + }, + "progressBar": Object { + "height": 10, + "innerHeight": 6, + "widthPercent": 0.6, + }, + "rangeColors": Object { + "bad": "#FF4D4F", + "good": "#29A294", + "satisfactory": "#FAAD14", + }, + }, + "interval": Object { + "fill": "#326EF4", + "height": 12, + }, + "line": Object { + "linkLine": Object { + "fill": "#326EF4", + "opacity": 0.6, + "size": 1.5, + }, + "point": Object { + "fill": "#326EF4", + "opacity": 1, + "size": 2.2, + }, + }, + }, + "text": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "linkTextFill": "#326EF4", + "opacity": 1, + "textAlign": "right", + "textBaseline": "middle", + }, + }, + "mergedCell": Object { + "bolderText": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": 700, + "linkTextFill": "#326EF4", + "opacity": 1, + "textAlign": "right", + "textBaseline": "middle", + }, + "cell": Object { + "backgroundColor": "#FFFFFF", + "backgroundColorOpacity": 1, + "borderDash": Array [], + "crossBackgroundColor": "#F5F8FE", + "horizontalBorderColor": "#E0E9FD", + "horizontalBorderColorOpacity": 1, + "horizontalBorderWidth": 1, + "interactionState": Object { + "highlight": Object { + "backgroundColor": "#87B5FF", + "backgroundOpacity": 1, + }, + "hover": Object { + "backgroundColor": "#E0E9FD", + "backgroundOpacity": 0.6, + }, + "hoverFocus": Object { + "backgroundColor": "#E0E9FD", + "backgroundOpacity": 0.6, + "borderColor": "#000000", + "borderOpacity": 1, + "borderWidth": 1, + }, + "prepareSelect": Object { + "borderColor": "#000000", + "borderOpacity": 1, + "borderWidth": 1, + }, + "searchResult": Object { + "backgroundColor": "#F0F7FF", + "backgroundOpacity": 1, + }, + "selected": Object { + "backgroundColor": "#E0E9FD", + "backgroundOpacity": 0.6, + }, + "unselected": Object { + "backgroundOpacity": 0.3, + "opacity": 0.3, + "textOpacity": 0.3, + }, + }, + "padding": Object { + "bottom": 8, + "left": 8, + "right": 8, + "top": 8, + }, + "verticalBorderColor": "#E0E9FD", + "verticalBorderColorOpacity": 1, + "verticalBorderWidth": 1, + }, + "icon": Object { + "downIconColor": "#FF4D4F", + "fill": "#000000", + "margin": Object { + "left": 4, + "right": 4, + }, + "size": 10, + "upIconColor": "#29A294", + }, + "miniChart": Object { + "bar": Object { + "fill": "#326EF4", + "intervalPadding": 4, + "opacity": 1, + }, + "bullet": Object { + "backgroundColor": "#E9E9E9", + "comparativeMeasure": Object { + "fill": "#000000", + "height": 12, + "opacity": 0.25, + "width": 1, + }, + "progressBar": Object { + "height": 10, + "innerHeight": 6, + "widthPercent": 0.6, + }, + "rangeColors": Object { + "bad": "#FF4D4F", + "good": "#29A294", + "satisfactory": "#FAAD14", + }, + }, + "interval": Object { + "fill": "#326EF4", + "height": 12, + }, + "line": Object { + "linkLine": Object { + "fill": "#326EF4", + "opacity": 0.6, + "size": 1.5, + }, + "point": Object { + "fill": "#326EF4", + "opacity": 1, + "size": 2.2, + }, + }, + }, + "text": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "linkTextFill": "#326EF4", + "opacity": 1, + "textAlign": "right", + "textBaseline": "middle", + }, + }, + "prepareSelectMask": Object { + "backgroundColor": "#234DAB", + "backgroundOpacity": 0.3, + }, + "resizeArea": Object { + "background": "#326EF4", + "backgroundOpacity": 0, + "guideLineColor": "#326EF4", + "guideLineDash": Array [ + 3, + 3, + ], + "guideLineDisableColor": "rgba(0,0,0,0.25)", + "interactionState": Object { + "hover": Object { + "backgroundColor": "#326EF4", + "backgroundOpacity": 1, + }, + }, + "size": 3, + }, + "rowCell": Object { + "bolderText": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": 700, + "linkTextFill": "#326EF4", + "opacity": 1, + "textAlign": "center", + "textBaseline": "top", + }, + "cell": Object { + "backgroundColor": "#F5F8FE", + "backgroundColorOpacity": 1, + "borderDash": Array [], + "horizontalBorderColor": "#E0E9FD", + "horizontalBorderColorOpacity": 1, + "horizontalBorderWidth": 1, + "interactionState": Object { + "highlight": Object { + "backgroundColor": "#87B5FF", + "backgroundOpacity": 1, + }, + "hover": Object { + "backgroundColor": "#E0E9FD", + "backgroundOpacity": 0.6, + }, + "prepareSelect": Object { + "borderColor": "#000000", + "borderOpacity": 1, + "borderWidth": 1, + }, + "searchResult": Object { + "backgroundColor": "#F0F7FF", + "backgroundOpacity": 1, + }, + "selected": Object { + "backgroundColor": "#E0E9FD", + "backgroundOpacity": 0.6, + }, + "unselected": Object { + "backgroundOpacity": 0.3, + "opacity": 0.3, + "textOpacity": 0.3, + }, + }, + "padding": Object { + "bottom": 0, + "left": 8, + "right": 8, + "top": 0, + }, + "verticalBorderColor": "#E0E9FD", + "verticalBorderColorOpacity": 1, + "verticalBorderWidth": 1, + }, + "icon": Object { + "fill": "#000000", + "margin": Object { + "left": 4, + "right": 4, + }, + "size": 10, + }, + "measureText": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "linkTextFill": "#326EF4", + "opacity": 1, + "textAlign": "center", + "textBaseline": "top", + }, + "seriesNumberWidth": 80, + "seriesText": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "linkTextFill": "#326EF4", + "opacity": 1, + "textAlign": "center", + "textBaseline": "middle", + }, + "text": Object { + "fill": "#000000", + "fontFamily": "Roboto, PingFangSC, BlinkMacSystemFont, Microsoft YaHei, Arial, sans-serif", + "fontSize": 12, + "fontWeight": "normal", + "linkTextFill": "#326EF4", + "opacity": 1, + "textAlign": "center", + "textBaseline": "top", + }, + }, + "scrollBar": Object { + "hoverSize": 8, + "lineCap": "round", + "size": 6, + "thumbColor": "rgba(0,0,0,0.15)", + "thumbHorizontalMinSize": 32, + "thumbHoverColor": "rgba(0,0,0,0.25)", + "thumbVerticalMinSize": 32, + "trackColor": "rgba(0,0,0,0.01)", + }, + "splitLine": Object { + "borderDash": Array [], + "horizontalBorderColor": "#326EF4", + "horizontalBorderColorOpacity": 0.2, + "horizontalBorderWidth": 2, + "shadowColors": Object { + "left": "rgba(0,0,0,0.1)", + "right": "rgba(0,0,0,0)", + }, + "shadowWidth": 8, + "showShadow": true, + "verticalBorderColor": "#326EF4", + "verticalBorderColorOpacity": 0.25, + "verticalBorderWidth": 2, + }, +} +`; diff --git a/packages/s2-core/__tests__/spreadsheet/theme-spec.ts b/packages/s2-core/__tests__/spreadsheet/theme-spec.ts index 0856ed10c5..5b044223e0 100644 --- a/packages/s2-core/__tests__/spreadsheet/theme-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/theme-spec.ts @@ -1,5 +1,5 @@ /* eslint-disable jest/expect-expect */ -import { createPivotSheet } from 'tests/util/helpers'; +import { createPivotSheet, createTableSheet } from 'tests/util/helpers'; import type { Group, IGroup, ShapeAttrs } from '@antv/g-canvas'; import { get } from 'lodash'; import type { @@ -52,10 +52,16 @@ describe('SpreadSheet Theme Tests', () => { CellTypes.MERGED_CELL, ]; - test('should get default theme', () => { + test('should get pivot sheet default theme', () => { expect(s2.theme).toMatchSnapshot(); }); + test('should get table sheet theme', () => { + const tableSheet = createTableSheet(null); + + expect(tableSheet.theme).toMatchSnapshot(); + }); + test.each(CELL_TYPES)( "should assign the same color for %s's text and icon", (cellType: CellTypes) => { diff --git a/packages/s2-core/__tests__/unit/data-set/table-data-set-spec.ts b/packages/s2-core/__tests__/unit/data-set/table-data-set-spec.ts index 8e990596c3..d7731c4239 100644 --- a/packages/s2-core/__tests__/unit/data-set/table-data-set-spec.ts +++ b/packages/s2-core/__tests__/unit/data-set/table-data-set-spec.ts @@ -3,7 +3,7 @@ */ import { assembleDataCfg } from 'tests/util'; import type { S2DataConfig } from '@/common/interface'; -import { TableSheet } from '@/sheet-type'; +import { SpreadSheet, TableSheet } from '@/sheet-type'; import { TableDataSet } from '@/data-set/table-data-set'; jest.mock('@/sheet-type'); @@ -11,7 +11,9 @@ jest.mock('@/facet/layout/node'); const MockTableSheet = TableSheet as any as jest.Mock; describe('Table Mode Dataset Test', () => { + let s2: SpreadSheet; let dataSet: TableDataSet; + const mockNumberFormatter = jest.fn().mockReturnValue('number'); const mockSubTypeFormatter = jest.fn().mockReturnValue('sub_type'); const mockTypeFormatter = jest.fn().mockReturnValue('type'); @@ -56,9 +58,12 @@ describe('Table Mode Dataset Test', () => { }, ], }; + beforeEach(() => { MockTableSheet.mockClear(); - dataSet = new TableDataSet(new MockTableSheet()); + + s2 = new MockTableSheet(); + dataSet = new TableDataSet(s2); dataSet.setDataCfg(dataCfg); }); diff --git a/packages/s2-core/__tests__/unit/dataset/__snapshots__/table-dataset-spec.ts.snap b/packages/s2-core/__tests__/unit/dataset/__snapshots__/table-dataset-spec.ts.snap new file mode 100644 index 0000000000..b37ddaca28 --- /dev/null +++ b/packages/s2-core/__tests__/unit/dataset/__snapshots__/table-dataset-spec.ts.snap @@ -0,0 +1,459 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Table Mode Dataset Test test for sort and filter should asc sort by number field 1`] = ` +Array [ + Object { + "city": "绵阳市", + "number": 245, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "乐山市", + "number": 352, + "province": "四川省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "绍兴市", + "number": 632, + "province": "浙江省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "舟山市", + "number": 834, + "province": "浙江省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "杭州市", + "number": 945, + "province": "浙江省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "宁波市", + "number": 1145, + "province": "浙江省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "绍兴市", + "number": 1304, + "province": "浙江省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "杭州市", + "number": 1343, + "province": "浙江省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "绍兴市", + "number": 1354, + "province": "浙江省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "舟山市", + "number": 1432, + "province": "浙江省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "宁波市", + "number": 1523, + "province": "浙江省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "舟山市", + "number": 1634, + "province": "浙江省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "成都市", + "number": 1723, + "province": "四川省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "绵阳市", + "number": 1822, + "province": "四川省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "南充市", + "number": 1943, + "province": "四川省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "绵阳市", + "number": 2244, + "province": "四川省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "乐山市", + "number": 2330, + "province": "四川省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "南充市", + "number": 2333, + "province": "四川省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "成都市", + "number": 2335, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "绍兴市", + "number": 2367, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "乐山市", + "number": 2445, + "province": "四川省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "成都市", + "number": 2451, + "province": "四川省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "南充市", + "number": 2457, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "乐山市", + "number": 2458, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "绵阳市", + "number": 3077, + "province": "四川省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "南充市", + "number": 3551, + "province": "四川省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "宁波市", + "number": 3877, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "成都市", + "number": 4004, + "province": "四川省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "舟山市", + "number": 4342, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "杭州市", + "number": 5343, + "province": "浙江省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "宁波市", + "number": 7234, + "province": "浙江省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "杭州市", + "number": 7789, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + }, +] +`; + +exports[`Table Mode Dataset Test test for sort and filter should desc sort by number field 1`] = ` +Array [ + Object { + "city": "杭州市", + "number": 7789, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "宁波市", + "number": 7234, + "province": "浙江省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "杭州市", + "number": 5343, + "province": "浙江省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "舟山市", + "number": 4342, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "成都市", + "number": 4004, + "province": "四川省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "宁波市", + "number": 3877, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "南充市", + "number": 3551, + "province": "四川省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "绵阳市", + "number": 3077, + "province": "四川省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "乐山市", + "number": 2458, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "南充市", + "number": 2457, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "成都市", + "number": 2451, + "province": "四川省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "乐山市", + "number": 2445, + "province": "四川省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "绍兴市", + "number": 2367, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "成都市", + "number": 2335, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "南充市", + "number": 2333, + "province": "四川省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "乐山市", + "number": 2330, + "province": "四川省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "绵阳市", + "number": 2244, + "province": "四川省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "南充市", + "number": 1943, + "province": "四川省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "绵阳市", + "number": 1822, + "province": "四川省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "成都市", + "number": 1723, + "province": "四川省", + "sub_type": "桌子", + "type": "家具", + }, + Object { + "city": "舟山市", + "number": 1634, + "province": "浙江省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "宁波市", + "number": 1523, + "province": "浙江省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "舟山市", + "number": 1432, + "province": "浙江省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "绍兴市", + "number": 1354, + "province": "浙江省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "杭州市", + "number": 1343, + "province": "浙江省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "绍兴市", + "number": 1304, + "province": "浙江省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "宁波市", + "number": 1145, + "province": "浙江省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "杭州市", + "number": 945, + "province": "浙江省", + "sub_type": "笔", + "type": "办公用品", + }, + Object { + "city": "舟山市", + "number": 834, + "province": "浙江省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "绍兴市", + "number": 632, + "province": "浙江省", + "sub_type": "沙发", + "type": "家具", + }, + Object { + "city": "乐山市", + "number": 352, + "province": "四川省", + "sub_type": "纸张", + "type": "办公用品", + }, + Object { + "city": "绵阳市", + "number": 245, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + }, +] +`; 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 153910e67c..e05168e5fa 100644 --- a/packages/s2-core/__tests__/unit/dataset/table-dataset-spec.ts +++ b/packages/s2-core/__tests__/unit/dataset/table-dataset-spec.ts @@ -1,18 +1,20 @@ /** * table mode data-set test. */ -import { orderBy, uniq } from 'lodash'; +import { first, last, orderBy, uniq } from 'lodash'; import { assembleDataCfg } from '../../util'; import type { S2DataConfig } from '@/common/interface'; -import { TableSheet } from '@/sheet-type'; import { TableDataSet } from '@/data-set/table-data-set'; +import { TableSheet } from '@/sheet-type'; jest.mock('@/sheet-type'); jest.mock('@/facet/layout/node'); + const MockTableSheet = TableSheet as any as jest.Mock; describe('Table Mode Dataset Test', () => { let dataSet: TableDataSet; + const dataCfg: S2DataConfig = { ...assembleDataCfg({}), meta: [], @@ -20,13 +22,17 @@ describe('Table Mode Dataset Test', () => { columns: ['province', 'city', 'type', 'sub_type', 'number'], }, }; + beforeEach(() => { - MockTableSheet.mockClear(); dataSet = new TableDataSet(new MockTableSheet()); dataSet.setDataCfg(dataCfg); }); + afterEach(() => { + MockTableSheet.mockClear(); + }); + describe('test base dataset structure', () => { test('should get correct field data', () => { expect(dataSet.fields.rows).toEqual(undefined); @@ -115,6 +121,7 @@ describe('Table Mode Dataset Test', () => { }), ).toEqual('成都市'); }); + it('should getCellData with customFilter', () => { dataSet.setDataCfg({ ...dataCfg, @@ -280,5 +287,118 @@ describe('Table Mode Dataset Test', () => { dataSet.handleDimensionValuesSort(); expect([...result, ...rest]).toStrictEqual(dataSet.getDisplayDataSet()); }); + + it('should asc sort by number field', () => { + const sortFieldId = 'number'; + + dataSet.sortParams = [ + { + sortFieldId, + sortMethod: 'asc', + }, + ]; + + dataSet.handleDimensionValuesSort(); + + expect(dataSet.getDisplayDataSet()).toHaveLength(32); + expect(dataSet.getDisplayDataSet()).toMatchSnapshot(); + }); + + it('should desc sort by number field', () => { + const sortFieldId = 'number'; + + dataSet.sortParams = [ + { + sortFieldId, + sortMethod: 'desc', + }, + ]; + + dataSet.handleDimensionValuesSort(); + + expect(dataSet.getDisplayDataSet()).toHaveLength(32); + expect(dataSet.getDisplayDataSet()).toMatchSnapshot(); + }); + + // https://github.com/antvis/S2/issues/2388 + it('should frozen correctly desc sorted data', () => { + const sortFieldId = 'number'; + + Object.defineProperty(dataSet.spreadsheet, 'options', { + value: { + frozenRowCount: 1, + frozenTrailingRowCount: 1, + }, + }); + + dataSet.sortParams = [ + { + sortFieldId, + sortMethod: 'desc', + }, + ]; + + dataSet.handleDimensionValuesSort(); + + expect(dataSet.getDisplayDataSet()).toHaveLength(32); + expect(first(dataSet.getDisplayDataSet())).toMatchInlineSnapshot(` + Object { + "city": "杭州市", + "number": 7789, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + } + `); + expect(last(dataSet.getDisplayDataSet())).toMatchInlineSnapshot(` + Object { + "city": "绵阳市", + "number": 245, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + } + `); + }); + + it('should frozen correctly asc sorted data', () => { + const sortFieldId = 'number'; + + Object.defineProperty(dataSet.spreadsheet, 'options', { + value: { + frozenRowCount: 1, + frozenTrailingRowCount: 1, + }, + }); + + dataSet.sortParams = [ + { + sortFieldId, + sortMethod: 'asc', + }, + ]; + + dataSet.handleDimensionValuesSort(); + + expect(dataSet.getDisplayDataSet()).toHaveLength(32); + expect(first(dataSet.getDisplayDataSet())).toMatchInlineSnapshot(` + Object { + "city": "绵阳市", + "number": 245, + "province": "四川省", + "sub_type": "笔", + "type": "办公用品", + } + `); + expect(last(dataSet.getDisplayDataSet())).toMatchInlineSnapshot(` + Object { + "city": "杭州市", + "number": 7789, + "province": "浙江省", + "sub_type": "桌子", + "type": "家具", + } + `); + }); }); }); diff --git a/packages/s2-core/__tests__/util/index.ts b/packages/s2-core/__tests__/util/index.ts index e29855f1b9..9218271816 100644 --- a/packages/s2-core/__tests__/util/index.ts +++ b/packages/s2-core/__tests__/util/index.ts @@ -31,7 +31,7 @@ export const assembleDataCfg = (...dataCfg: Partial[]) => ...dataCfg, ); -export const TOTALS_OPTIONS = { +export const TOTALS_OPTIONS: S2Options['totals'] = { row: { showGrandTotals: true, showSubTotals: true, diff --git a/packages/s2-core/src/data-set/base-data-set.ts b/packages/s2-core/src/data-set/base-data-set.ts index 87fc283f2c..1bb7929d41 100644 --- a/packages/s2-core/src/data-set/base-data-set.ts +++ b/packages/s2-core/src/data-set/base-data-set.ts @@ -51,7 +51,7 @@ export abstract class BaseDataSet { public filterParams: FilterParam[]; // 透视表入口对象实例 - protected spreadsheet: SpreadSheet; + public spreadsheet: SpreadSheet; public constructor(spreadsheet: SpreadSheet) { this.spreadsheet = spreadsheet; diff --git a/packages/s2-core/src/data-set/table-data-set.ts b/packages/s2-core/src/data-set/table-data-set.ts index 619d04456a..8915a27944 100644 --- a/packages/s2-core/src/data-set/table-data-set.ts +++ b/packages/s2-core/src/data-set/table-data-set.ts @@ -1,10 +1,10 @@ -import { each, orderBy, filter, includes, isFunction, isObject } from 'lodash'; +import { each, filter, isFunction, isObject, orderBy } from 'lodash'; import { isAscSort, isDescSort } from '..'; -import type { S2DataConfig } from '../common/interface'; import type { CellMeta } from '../common'; +import type { S2DataConfig } from '../common/interface'; import type { RowData } from '../common/interface/basic'; -import type { CellDataParams, DataType } from './interface'; import { BaseDataSet } from './base-data-set'; +import type { CellDataParams, DataType } from './interface'; export class TableDataSet extends BaseDataSet { // data that goes into canvas (aka sorted & filtered) @@ -24,12 +24,12 @@ export class TableDataSet extends BaseDataSet { * 返回顶部冻结行 * @returns */ - protected getStartRows() { + protected getStartFrozenRows(displayData: DataType[]): DataType[] { const { frozenRowCount } = this.spreadsheet.options || {}; if (!frozenRowCount) { return []; } - const { displayData } = this; + return displayData.slice(0, frozenRowCount); } @@ -37,29 +37,25 @@ export class TableDataSet extends BaseDataSet { * 返回底部冻结行 * @returns */ - protected getEndRows() { + protected getEndFrozenRows(displayData: DataType[]): DataType[] { const { frozenTrailingRowCount } = this.spreadsheet.options || {}; - // 没有冻结行时返回空数组 if (!frozenTrailingRowCount) { return []; } - const { displayData } = this; return displayData.slice(-frozenTrailingRowCount); } - /** - * 返回可移动的非冻结行 - * @returns - */ - protected getMovableRows(): DataType[] { - const { displayData } = this; - const { frozenTrailingRowCount, frozenRowCount } = - this.spreadsheet.options || {}; - return displayData.slice( - frozenRowCount || 0, - -frozenTrailingRowCount || undefined, + protected getDisplayData(displayData: DataType[]): DataType[] { + const startFrozenRows = this.getStartFrozenRows(displayData); + const endFrozenRows = this.getEndFrozenRows(displayData); + + const data = displayData.slice( + startFrozenRows.length || 0, + -endFrozenRows.length || undefined, ); + + return [...startFrozenRows, ...data, ...endFrozenRows]; } handleDimensionValueFilter = () => { @@ -67,16 +63,15 @@ export class TableDataSet extends BaseDataSet { const filteredValuesSet = new Set(filteredValues); const defaultFilterFunc = (row: DataType) => !filteredValuesSet.has(row[filterKey]); - this.displayData = [ - ...this.getStartRows(), - ...filter(this.getMovableRows(), (row) => { - if (customFilter) { - return customFilter(row) && defaultFilterFunc(row); - } - return defaultFilterFunc(row); - }), - ...this.getEndRows(), - ]; + + const filteredData = filter(this.displayData, (row) => { + if (customFilter) { + return customFilter(row) && defaultFilterFunc(row); + } + return defaultFilterFunc(row); + }); + + this.displayData = this.getDisplayData(filteredData); }); }; @@ -89,7 +84,7 @@ export class TableDataSet extends BaseDataSet { return; } - let data = this.getMovableRows(); + let data = this.displayData; const restData = []; if (query) { @@ -142,11 +137,7 @@ export class TableDataSet extends BaseDataSet { } // For frozen options - this.displayData = [ - ...this.getStartRows(), - ...sortedData, - ...this.getEndRows(), - ]; + this.displayData = this.getDisplayData(sortedData); }); }; diff --git a/packages/s2-core/src/theme/index.ts b/packages/s2-core/src/theme/index.ts index 9270cc979b..4bc69b2209 100644 --- a/packages/s2-core/src/theme/index.ts +++ b/packages/s2-core/src/theme/index.ts @@ -227,7 +227,7 @@ export const getTheme = ( fill: basicColors[14], linkTextFill: basicColors[6], opacity: 1, - textBaseline: 'top', + textBaseline: isTable ? 'middle' : 'top', textAlign: 'center', }, measureText: { diff --git a/packages/s2-core/src/utils/merge.ts b/packages/s2-core/src/utils/merge.ts index 67c17d29aa..edb63f7f95 100644 --- a/packages/s2-core/src/utils/merge.ts +++ b/packages/s2-core/src/utils/merge.ts @@ -1,7 +1,7 @@ -import { isArray, isEmpty, mergeWith, uniq, isEqual, forEach } from 'lodash'; +import { isArray, isEmpty, isEqual, mergeWith, uniq } from 'lodash'; import { DEFAULT_DATA_CONFIG } from '../common/constant/dataConfig'; import { DEFAULT_OPTIONS } from '../common/constant/options'; -import type { S2DataConfig, S2Options, Fields } from '../common/interface'; +import type { Fields, S2DataConfig, S2Options } from '../common/interface'; export const customMerge = (...objects: unknown[]) => { const customize = (origin: unknown, updated: unknown) => { diff --git a/packages/s2-react/__tests__/spreadsheet/filter-sheet-spec.tsx b/packages/s2-react/__tests__/spreadsheet/filter-sheet-spec.tsx index 45946c2d21..df476620ab 100644 --- a/packages/s2-react/__tests__/spreadsheet/filter-sheet-spec.tsx +++ b/packages/s2-react/__tests__/spreadsheet/filter-sheet-spec.tsx @@ -1,34 +1,24 @@ /* eslint-disable no-console */ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { act } from 'react-dom/test-utils'; -import { Button, Space } from 'antd'; import { - type S2DataConfig, S2Event, - type S2Options, SpreadSheet, - TableSheet, + type S2DataConfig, + type S2Options, } from '@antv/s2'; -import { getContainer, getMockData } from '../util/helpers'; +import { Button, Space } from 'antd'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { act } from 'react-dom/test-utils'; +import { getContainer, getMockData, sleep } from '../util/helpers'; import { SheetComponent } from '@/components'; import 'antd/dist/antd.min.css'; -const data = getMockData('../data/tableau-supermarket.csv'); -let spreadSheet: SpreadSheet; - -const onMounted = - (ref: React.MutableRefObject) => - (dom: string | HTMLElement, dataCfg: S2DataConfig, options: S2Options) => { - const s2 = new TableSheet(dom, dataCfg, options); - ref.current = s2; - spreadSheet = s2; +const data = getMockData('../data/tableau-supermarket.csv'); - return s2; - }; +let s2: SpreadSheet; -const columns = [ +const columns: string[] = [ 'order_id', 'order_date', 'ship_date', @@ -46,7 +36,7 @@ const columns = [ 'count', 'discount', 'profit', -] as const; +]; const meta = [ { @@ -66,7 +56,7 @@ function MainLayout() { }, meta, data, - } as unknown as S2DataConfig; + }; const options: S2Options = { width: 800, @@ -74,6 +64,7 @@ function MainLayout() { showSeriesNumber: true, interaction: { enableCopy: true, + linkFields: ['order_id', 'customer_name'], }, style: { cellCfg: { @@ -81,19 +72,14 @@ function MainLayout() { }, device: 'pc', }, - frozenRowCount: 2, frozenColCount: 1, frozenTrailingColCount: 1, frozenTrailingRowCount: 1, - linkFieldIds: ['order_id', 'customer_name'], tooltip: { showTooltip: true, - operation: { - filter: true, - }, }, - } as S2Options; + }; const s2Ref = React.useRef(null); @@ -101,7 +87,7 @@ function MainLayout() { - { + s2 = spreadsheet; + }} /> ); } describe('table sheet filter spec', () => { - act(() => { - ReactDOM.render(, getContainer()); + let container: HTMLDivElement; + const filterKey = 'customer_type'; + const filteredValue = '消费者'; + + beforeEach(() => { + container = getContainer(); + + act(() => { + ReactDOM.render(, container); + }); }); - test('filter customer_type values', () => { - spreadSheet.emit(S2Event.RANGE_FILTER, { - filterKey: 'customer_type', - filteredValues: ['消费者'], + afterEach(() => { + container?.remove(); + }); + + test('filter customer_type values', async () => { + await sleep(1000); + + s2.emit(S2Event.RANGE_FILTER, { + filterKey, + filteredValues: [filteredValue], }); - expect(spreadSheet.facet.getCellRange()).toStrictEqual({ - end: 467, + expect(s2.facet.getCellRange()).toStrictEqual({ + end: 465, start: 0, }); + expect(s2.dataSet.getDisplayDataSet()).toHaveLength(466); + expect( + s2.dataSet + .getDisplayDataSet() + .some((item) => item.customer_type === filteredValue), + ).toBeFalsy(); }); - test('reset filter params on customer_type', () => { - spreadSheet.emit(S2Event.RANGE_FILTER, { - filterKey: 'customer_type', - filteredValues: ['消费者'], + test('reset filter params on customer_type', async () => { + await sleep(1000); + + s2.emit(S2Event.RANGE_FILTER, { + filterKey, + filteredValues: [filteredValue], }); - spreadSheet.emit(S2Event.RANGE_FILTER, { - filterKey: 'customer_type', + s2.emit(S2Event.RANGE_FILTER, { + filterKey, filteredValues: [], }); - expect(spreadSheet.facet.getCellRange()).toStrictEqual({ + expect(s2.facet.getCellRange()).toStrictEqual({ end: 999, start: 0, }); + expect(s2.dataSet.getDisplayDataSet()).toHaveLength(1000); }); - test('filtered event fired with new data', () => { - spreadSheet.on(S2Event.RANGE_FILTERED, (data) => { - expect(data.length).toStrictEqual(468); + test('filtered event fired with new data', async () => { + await sleep(1000); + + s2.on(S2Event.RANGE_FILTERED, (data) => { + expect(data.length).toStrictEqual(466); + expect(s2.dataSet.getDisplayDataSet()).toHaveLength(466); + expect( + s2.dataSet + .getDisplayDataSet() + .some((item) => item.customer_type === filteredValue), + ).toBeFalsy(); }); - spreadSheet.emit(S2Event.RANGE_FILTER, { - filterKey: 'customer_type', - filteredValues: ['消费者'], + s2.emit(S2Event.RANGE_FILTER, { + filterKey, + filteredValues: [filteredValue], }); }); - test('falsy/nullish data should not be filtered with irrelavent filter params', () => { - spreadSheet.on(S2Event.RANGE_FILTERED, (data) => { - expect(data.length).toStrictEqual(468); + test('falsy/nullish data should not be filtered with irrelevant filter params', async () => { + await sleep(1000); + + s2.on(S2Event.RANGE_FILTERED, (data) => { + expect(data.length).toStrictEqual(1000); + expect(s2.dataSet.getDisplayDataSet()).toHaveLength(1000); }); - spreadSheet.emit(S2Event.RANGE_FILTER, { + s2.emit(S2Event.RANGE_FILTER, { filterKey: 'express_type', filteredValues: ['消费者'], }); diff --git a/packages/s2-react/playground/config.ts b/packages/s2-react/playground/config.ts index 4b89787962..709eb6ca4e 100644 --- a/packages/s2-react/playground/config.ts +++ b/packages/s2-react/playground/config.ts @@ -77,7 +77,7 @@ export const pivotSheetDataCfgForCompactMode = customMerge(pivotSheetDataCfg, { }); export const s2Options: SheetComponentOptions = { - debug: true, + debug: false, width: 600, height: 400, frozenFirstRow: false, @@ -143,7 +143,7 @@ export const s2Options: SheetComponentOptions = { }, cellCfg: { height: 50, - width: 200, + width: 100, }, }, }; diff --git a/s2-site/examples/interaction/basic/demo/state-theme.ts b/s2-site/examples/interaction/basic/demo/state-theme.ts index 241dadc80c..3d43c15ac0 100644 --- a/s2-site/examples/interaction/basic/demo/state-theme.ts +++ b/s2-site/examples/interaction/basic/demo/state-theme.ts @@ -14,17 +14,60 @@ fetch( hoverHighlight: true, selectedCellHighlight: true, selectedCellsSpotlight: true, + multiSelection: true, + selectedCellMove: true, + rangeSelection: true, + brushSelection: { + row: true, + col: true, + data: true, + }, }, tooltip: { showTooltip: true, }, + style: { + rowCfg: { + width: 100, + }, + cellCfg: { + width: 120, + }, + }, }; + const s2 = new PivotSheet(container, dataCfg, s2Options); s2.setTheme({ + // 刷选 (预选中遮罩框) prepareSelectMask: { backgroundColor: '#ccc', }, + // 宽高调整 (热区, 参考线) + resizeArea: { + // 热区大小, 背景色 + size: 4, + background: 'rgba(0,0,0, 0.5)', + backgroundOpacity: 0, + + // 参考线 + guideLineColor: 'pink', + guideLineDisableColor: 'yellow', + guideLineDash: [4, 4], + }, + // 滚动条 + scrollBar: { + trackColor: 'rgba(0,0,0,0.01)', + thumbHoverColor: 'rgba(0,0,0,0.25)', + thumbColor: 'rgba(0,0,0,0.15)', + // 滑块最小宽度 + thumbHorizontalMinSize: 32, + thumbVerticalMinSize: 32, + size: 6, + hoverSize: 10, + lineCap: 'round', + }, + // 数值单元格 (其他单元格同理) dataCell: { cell: { interactionState: { @@ -35,23 +78,36 @@ fetch( // 或者边框透明度设置为 0 // borderOpacity: 0 }, - // 悬停 + // 十字悬停 hover: { backgroundOpacity: 0.2, + borderColor: 'transparent', + borderOpacity: 1, }, // 选中背景色/边框 selected: { backgroundColor: 'pink', borderWidth: 3, + borderColor: '#dcdcdc', + borderOpacity: 1, + }, + // 未选中背景色/边框 + unselected: { + backgroundOpacity: 0.5, + textOpacity: 0.1, + opacity: 0.1, }, // 高亮效果 highlight: { textOpacity: 0.2, backgroundColor: '#f63', + borderColor: '#f63', + borderOpacity: 1, }, // 预选 (刷选) prepareSelect: { borderColor: '#396', + borderOpacity: 1, }, }, },