diff --git a/packages/s2-core/__tests__/unit/facet/pivot-facet-spec.ts b/packages/s2-core/__tests__/unit/facet/pivot-facet-spec.ts index 2f252f516b..aec63f6c98 100644 --- a/packages/s2-core/__tests__/unit/facet/pivot-facet-spec.ts +++ b/packages/s2-core/__tests__/unit/facet/pivot-facet-spec.ts @@ -95,6 +95,9 @@ jest.mock('@/data-set/pivot-data-set', () => { indexesData, sortedDimensionValues, moreThanOneValue: jest.fn(), + transformIndexesData: actualPivotDataSet.prototype.transformIndexesData, + getExistValuesByDataItem: + actualPivotDataSet.prototype.getExistValuesByDataItem, getFieldFormatter: actualDataSet.prototype.getFieldFormatter, getFieldMeta: (field: string, meta: ViewMeta) => find(meta, { field }), getFieldName: actualPivotDataSet.prototype.getFieldName, diff --git a/packages/s2-core/__tests__/unit/facet/util.ts b/packages/s2-core/__tests__/unit/facet/util.ts index 49b4ae4878..997c6681f2 100644 --- a/packages/s2-core/__tests__/unit/facet/util.ts +++ b/packages/s2-core/__tests__/unit/facet/util.ts @@ -1,5 +1,8 @@ import { assembleDataCfg } from 'tests/util'; -import { transformIndexesData } from '@/utils/dataset/pivot-data-set'; +import { + getExistValues, + transformIndexesData, +} from '@/utils/dataset/pivot-data-set'; /** * 获取 Mock 数据 @@ -20,5 +23,6 @@ export function getMockPivotMeta() { rowPivotMeta: rawRowPivotMeta, colPivotMeta: rawColPivotMeta, valueInCols: true, + getExistValuesByDataItem: getExistValues, }); } diff --git a/packages/s2-core/src/data-set/pivot-data-set.ts b/packages/s2-core/src/data-set/pivot-data-set.ts index 99dd3975c6..508130970a 100644 --- a/packages/s2-core/src/data-set/pivot-data-set.ts +++ b/packages/s2-core/src/data-set/pivot-data-set.ts @@ -44,11 +44,13 @@ import { flattenIndexesData, getDataPath, getDataPathPrefix, + getExistValues, getFlattenDimensionValues, getSatisfiedPivotMetaValues, isMultiValue, transformDimensionsValues, transformIndexesData, + type TransformResult, } from '../utils/dataset/pivot-data-set'; import { DataHandler } from '../utils/dataset/proxy-handler'; import { calcActionByType } from '../utils/number-calculate'; @@ -75,6 +77,10 @@ export class PivotDataSet extends BaseDataSet { // sorted dimension values public sortedDimensionValues: SortedDimensionValues; + getExistValuesByDataItem(data: DataType, values: string[]) { + return getExistValues(data, values); + } + /** * When data related config changed, we need * 1、re-process config @@ -84,26 +90,41 @@ export class PivotDataSet extends BaseDataSet { */ public setDataCfg(dataCfg: S2DataConfig) { super.setDataCfg(dataCfg); + const { rows } = this.fields; this.sortedDimensionValues = {}; this.rowPivotMeta = new Map(); this.colPivotMeta = new Map(); + this.transformIndexesData(this.originData.concat(this.totalData), rows); + this.handleDimensionValuesSort(); + } + + public transformIndexesData( + data: DataType[], + rows: string[], + ): TransformResult { + const { columns, values, valueInCols } = this.fields; + + let result: TransformResult; DebuggerUtil.getInstance().debugCallback(DEBUG_TRANSFORM_DATA, () => { - const { rows, columns, values, valueInCols } = this.fields; - const { indexesData } = transformIndexesData({ + result = transformIndexesData({ rows, columns: columns as string[], values, valueInCols, - data: this.originData.concat(this.totalData), + data, indexesData: this.indexesData, sortedDimensionValues: this.sortedDimensionValues, rowPivotMeta: this.rowPivotMeta, colPivotMeta: this.colPivotMeta, + getExistValuesByDataItem: this.getExistValuesByDataItem, }); - this.indexesData = indexesData; + this.indexesData = result.indexesData; + this.rowPivotMeta = result.rowPivotMeta; + this.colPivotMeta = result.colPivotMeta; + this.sortedDimensionValues = result.sortedDimensionValues; }); - this.handleDimensionValuesSort(); + return result; } /** @@ -117,7 +138,6 @@ export class PivotDataSet extends BaseDataSet { drillDownData: DataType[], rowNode: Node, ) { - const { columns, values, valueInCols } = this.fields; const currentRowFields = Node.getFieldPath(rowNode, true); const nextRowFields = [...currentRowFields, extraRowField]; const store = this.spreadsheet.store; @@ -134,27 +154,10 @@ export class PivotDataSet extends BaseDataSet { } // 3、转换数据 - const { - paths: drillDownDataPaths, - indexesData, - rowPivotMeta, - colPivotMeta, - sortedDimensionValues, - } = transformIndexesData({ - rows: nextRowFields, - columns: columns as string[], - values, - valueInCols, - data: drillDownData, - indexesData: this.indexesData, - sortedDimensionValues: this.sortedDimensionValues, - rowPivotMeta: this.rowPivotMeta, - colPivotMeta: this.colPivotMeta, - }); - this.indexesData = indexesData; - this.rowPivotMeta = rowPivotMeta; - this.colPivotMeta = colPivotMeta; - this.sortedDimensionValues = sortedDimensionValues; + const { paths: drillDownDataPaths } = this.transformIndexesData( + drillDownData, + nextRowFields, + ); // 4、record data paths by nodeId // set new drill-down data path diff --git a/packages/s2-core/src/utils/data-set-operate.ts b/packages/s2-core/src/utils/data-set-operate.ts index d0f6b74d65..498509291e 100644 --- a/packages/s2-core/src/utils/data-set-operate.ts +++ b/packages/s2-core/src/utils/data-set-operate.ts @@ -36,7 +36,6 @@ export const filterOutDetail = (values: string[] = []) => { (v) => v !== TOTAL_VALUE && v !== EMPTY_EXTRA_FIELD_PLACEHOLDER, ); }; - export const customFlattenDeep = ( data: Record[] | Record, ) => { diff --git a/packages/s2-core/src/utils/dataset/pivot-data-set.ts b/packages/s2-core/src/utils/dataset/pivot-data-set.ts index 810bbd46ce..a8782caad4 100644 --- a/packages/s2-core/src/utils/dataset/pivot-data-set.ts +++ b/packages/s2-core/src/utils/dataset/pivot-data-set.ts @@ -57,7 +57,7 @@ export function isMultiValue(pathValue: string | number) { export function transformDimensionsValues( record: DataType = {}, dimensions: string[] = [], - placeholder: string = TOTAL_VALUE, + placeholder = TOTAL_VALUE, ): string[] { return dimensions.reduce((res: string[], dimension: string) => { const value = record[dimension]; @@ -70,10 +70,19 @@ export function transformDimensionsValues( }, []); } +export function getExistValues(data: DataType, values: string[]) { + const result = values.filter((v) => v in data); + if (isEmpty(result)) { + result.push(EMPTY_EXTRA_FIELD_PLACEHOLDER); + } + + return result; +} + export function transformDimensionsValuesWithExtraFields( record: DataType = {}, dimensions: string[] = [], - values: string[] = [], + values?: string[], ) { const result = []; @@ -93,25 +102,13 @@ export function transformDimensionsValuesWithExtraFields( }, []); } - if (isEmpty(values)) { - result.push(transform(record, dimensions)); - } else { + if (values) { values.forEach((value) => { - if (value in record) { - result.push(transform(record, dimensions, value)); - } + result.push(transform(record, dimensions, value)); }); + } else { + result.push(transform(record, dimensions)); } - - /** - * result 为空时,就是命中了数组置于当前维度,但是当前的数据中并没有包含任何 values 配置,给一个默认维度用于占位 - * 主要用于处理趋势分析表中只存在日期列头,不存在任何值的情况: - * ref: @see packages/s2-react/__tests__/unit/components/sheets/strategy-sheet/index-spec.tsx - */ - if (isEmpty(result)) { - result.push(transform(record, dimensions, EMPTY_EXTRA_FIELD_PLACEHOLDER)); - } - return result; } @@ -277,12 +274,21 @@ interface Param { sortedDimensionValues: SortedDimensionValues; rowPivotMeta?: PivotMeta; colPivotMeta?: PivotMeta; + getExistValuesByDataItem?: (data: DataType, values: string[]) => string[]; +} + +export interface TransformResult { + paths: (string | number)[]; + indexesData: Record; + rowPivotMeta: PivotMeta; + colPivotMeta: PivotMeta; + sortedDimensionValues: SortedDimensionValues; } /** * 转换原始数据为二维数组数据 */ -export function transformIndexesData(params: Param) { +export function transformIndexesData(params: Param): TransformResult { const { rows, columns, @@ -293,6 +299,7 @@ export function transformIndexesData(params: Param) { sortedDimensionValues, rowPivotMeta, colPivotMeta, + getExistValuesByDataItem, } = params; const paths = []; @@ -319,21 +326,25 @@ export function transformIndexesData(params: Param) { const prefix = getDataPathPrefix(rows, columns as string[]); - data.forEach((item) => { + data.forEach((item: DataType) => { // 空数据没有意义,直接跳过 if (!item || isEmpty(item)) { return; } + const existValues = getExistValuesByDataItem + ? getExistValuesByDataItem(item, values) + : getExistValues(item, values); + const multiRowDimensionValues = transformDimensionsValuesWithExtraFields( item, rows, - valueInCols ? undefined : values, + valueInCols ? null : existValues, ); const multiColDimensionValues = transformDimensionsValuesWithExtraFields( item, columns, - valueInCols ? values : undefined, + valueInCols ? existValues : null, ); for (const rowDimensionValues of multiRowDimensionValues) { diff --git a/packages/s2-react/src/components/sheets/strategy-sheet/custom-data-set.ts b/packages/s2-react/src/components/sheets/strategy-sheet/custom-data-set.ts index 05a6729212..c62fc33710 100644 --- a/packages/s2-react/src/components/sheets/strategy-sheet/custom-data-set.ts +++ b/packages/s2-react/src/components/sheets/strategy-sheet/custom-data-set.ts @@ -1,11 +1,24 @@ import { CustomTreePivotDataSet, + EMPTY_EXTRA_FIELD_PLACEHOLDER, i18n, + type DataType, type Meta, type S2DataConfig, } from '@antv/s2'; +import { isEmpty, isObject, keys } from 'lodash'; export class StrategyDataSet extends CustomTreePivotDataSet { + getExistValuesByDataItem(data: DataType, values: string[]) { + const result = keys(data).filter((key) => isObject(data[key])); + + if (isEmpty(result)) { + result.push(EMPTY_EXTRA_FIELD_PLACEHOLDER); + } + + return result; + } + processDataCfg(dataCfg: S2DataConfig): S2DataConfig { const { meta } = dataCfg; const updatedDataCfg = super.processDataCfg(dataCfg);