UNPKG

@antv/s2

Version:

effective spreadsheet render core lib

463 lines 22.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PivotDataSet = void 0; const lodash_1 = require("lodash"); const common_1 = require("../common"); const constant_1 = require("../common/constant"); const debug_1 = require("../common/debug"); const i18n_1 = require("../common/i18n"); const node_1 = require("../facet/layout/node"); const utils_1 = require("../utils"); const data_set_operate_1 = require("../utils/data-set-operate"); const pivot_data_set_1 = require("../utils/dataset/pivot-data-set"); const number_calculate_1 = require("../utils/number-calculate"); const sort_action_1 = require("../utils/sort-action"); const base_data_set_1 = require("./base-data-set"); const cell_data_1 = require("./cell-data"); class PivotDataSet extends base_data_set_1.BaseDataSet { constructor() { super(...arguments); /** * 排序优先级: * 1、sortParams里的条件优先级高于原始数据 * 2、sortParams多个item:按照顺序优先级,排在后面的优先级高 * 3、item中多个条件:sortByField > sortFunc > sortBy > sortMethod */ this.handleDimensionValuesSort = () => { (0, lodash_1.each)(this.sortParams, (item) => { const { sortFieldId, sortByMeasure } = item; // 万物排序的前提 if (!sortFieldId) { return; } const originValues = [...(this.sortedDimensionValues[sortFieldId] || [])]; const result = (0, sort_action_1.handleSortAction)({ dataSet: this, sortParam: item, originValues, isSortByMeasure: !(0, lodash_1.isEmpty)(sortByMeasure), }); this.sortedDimensionValues[sortFieldId] = result; this.handlePivotMetaSort(sortFieldId, result); }); }; this.getTotalStatus = (query) => { const { columns, rows } = this.fields; const isTotals = (dimensions, isSubTotal) => { if (isSubTotal) { const firstDimension = (0, lodash_1.find)(dimensions, (item) => !(0, lodash_1.has)(query, item)); return !!(firstDimension && firstDimension !== (0, lodash_1.first)(dimensions)); } return (0, lodash_1.every)(dimensions, (item) => !(0, lodash_1.has)(query, item)); }; return { isRowGrandTotal: isTotals((0, pivot_data_set_1.filterExtraDimension)(rows)), isRowSubTotal: isTotals(rows, true), isColGrandTotal: isTotals((0, pivot_data_set_1.filterExtraDimension)(columns)), isColSubTotal: isTotals(columns, true), }; }; } getExistValuesByDataItem(data, values) { return (0, pivot_data_set_1.getExistValues)(data, values); } /** * When data related config changed, we need * 1、re-process config * 2、re-transform origin data * 3、sort and other things * @param dataCfg */ setDataCfg(dataCfg) { super.setDataCfg(dataCfg); const { rows } = this.fields; this.sortedDimensionValues = {}; this.rowPivotMeta = new Map(); this.colPivotMeta = new Map(); this.dimensionValuesCache = new Map(); this.transformIndexesData(this.originData, rows); this.handleDimensionValuesSort(); } transformIndexesData(data, rows) { const { columns, values, valueInCols } = this.fields; let result; debug_1.DebuggerUtil.getInstance().debugCallback(debug_1.DEBUG_TRANSFORM_DATA, () => { result = (0, pivot_data_set_1.transformIndexesData)({ rows: (0, pivot_data_set_1.getIndexFields)(rows), columns: (0, pivot_data_set_1.getIndexFields)(columns), values: values, valueInCols: valueInCols, data, indexesData: this.indexesData, sortedDimensionValues: this.sortedDimensionValues, rowPivotMeta: this.rowPivotMeta, colPivotMeta: this.colPivotMeta, getExistValuesByDataItem: this.getExistValuesByDataItem, }); this.indexesData = result.indexesData; this.rowPivotMeta = result.rowPivotMeta; this.colPivotMeta = result.colPivotMeta; this.sortedDimensionValues = result.sortedDimensionValues; }); return result; } /** * Provide a way to append some drill-down data in indexesData * @param extraRowField * @param drillDownData * @param rowNode */ transformDrillDownData(extraRowField, drillDownData, rowNode) { var _a; const currentRowFields = node_1.Node.getFieldPath(rowNode, true); const nextRowFields = [...currentRowFields, extraRowField]; const store = this.spreadsheet.store; // 2. 检查该节点是否已经存在下钻维度 const rowNodeId = rowNode === null || rowNode === void 0 ? void 0 : rowNode.id; const idPathMap = (_a = store.get('drillDownIdPathMap')) !== null && _a !== void 0 ? _a : new Map(); if (idPathMap.has(rowNodeId)) { // the current node has a drill-down field, clean it (0, lodash_1.forEach)(idPathMap.get(rowNodeId), (path) => { (0, lodash_1.unset)(this.indexesData, path); }); (0, pivot_data_set_1.deleteMetaById)(this.rowPivotMeta, rowNodeId); } // 3、转换数据 const { paths: drillDownDataPaths } = this.transformIndexesData(drillDownData, nextRowFields); /* * 4、record data paths by nodeId * set new drill-down data path */ idPathMap.set(rowNodeId, drillDownDataPaths); store.set('drillDownIdPathMap', idPathMap); } /** * Clear drill down data by rowNodeId * rowNodeId is undefined => clear all * @param rowNodeId */ clearDrillDownData(rowNodeId) { const store = this.spreadsheet.store; const idPathMap = store.get('drillDownIdPathMap'); if (!idPathMap) { return false; } const drillDownDataCache = store.get('drillDownDataCache', []); if (rowNodeId) { // 1. 删除 indexesData 当前下钻层级对应数据 const currentIdPathMap = idPathMap.get(rowNodeId); if (currentIdPathMap) { (0, lodash_1.forEach)(currentIdPathMap, (path) => { (0, lodash_1.unset)(this.indexesData, path); }); } // 2. 删除 rowPivotMeta 当前下钻层级对应 meta 信息 (0, pivot_data_set_1.deleteMetaById)(this.rowPivotMeta, rowNodeId); // 3. 删除下钻缓存路径 idPathMap.delete(rowNodeId); // 4. 过滤清除的下钻缓存 const restDataCache = (0, lodash_1.filter)(drillDownDataCache, (cache) => idPathMap.has(cache === null || cache === void 0 ? void 0 : cache.rowId)); store.set('drillDownDataCache', restDataCache); // 5. 过滤清除的下钻层级 const restDrillLevels = restDataCache.map((cache) => cache === null || cache === void 0 ? void 0 : cache.drillLevel); const drillDownFieldInLevel = store.get('drillDownFieldInLevel', []); const restFieldInLevel = drillDownFieldInLevel.filter((filed) => (0, lodash_1.includes)(restDrillLevels, filed === null || filed === void 0 ? void 0 : filed.drillLevel)); store.set('drillDownFieldInLevel', restFieldInLevel); } else { idPathMap.clear(); /* * 需要对应清空所有下钻后的dataCfg信息 * 因此如果缓存有下钻前原始dataCfg,需要清空所有的下钻数据 */ const originalDataCfg = this.spreadsheet.store.get('originalDataCfg'); if (!(0, lodash_1.isEmpty)(originalDataCfg)) { this.spreadsheet.setDataCfg(originalDataCfg); } // 清空所有的下钻信息 this.spreadsheet.store.set('drillItemsNum', -1); this.spreadsheet.store.set('drillDownDataCache', []); this.spreadsheet.store.set('drillDownFieldInLevel', []); } store.set('drillDownIdPathMap', idPathMap); return true; } handlePivotMetaSort(sortFieldId, sortedDimensionValues) { const { rows, columns } = this.fields; if ((0, lodash_1.includes)(rows, sortFieldId)) { this.rowPivotMeta = (0, sort_action_1.getSortedPivotMeta)({ pivotMeta: this.rowPivotMeta, dimensions: rows, sortFieldId, sortedDimensionValues, }); } else if ((0, lodash_1.includes)(columns, sortFieldId)) { this.colPivotMeta = (0, sort_action_1.getSortedPivotMeta)({ pivotMeta: this.colPivotMeta, dimensions: columns, sortFieldId, sortedDimensionValues, }); } } processDataCfg(dataCfg) { const { data, meta = [], fields, sortParams = [] } = dataCfg; const { columns = [], rows = [], values, valueInCols, customValueOrder, } = fields; let newColumns = columns; let newRows = rows; if (valueInCols) { newColumns = this.isCustomMeasuresPosition(customValueOrder) ? this.handleCustomMeasuresOrder(customValueOrder, newColumns) : (0, lodash_1.uniq)([...columns, constant_1.EXTRA_FIELD]); } else { newRows = this.isCustomMeasuresPosition(customValueOrder) ? this.handleCustomMeasuresOrder(customValueOrder, newRows) : (0, lodash_1.uniq)([...rows, constant_1.EXTRA_FIELD]); } const newMeta = this.processMeta(meta, (0, i18n_1.i18n)('数值')); return { data, meta: newMeta, fields: Object.assign(Object.assign({}, fields), { rows: newRows, columns: newColumns, values }), sortParams, }; } getFieldsAndPivotMetaByField(field) { const { rows = [], columns = [] } = this.fields || {}; if (rows.includes(field)) { return { dimensions: (0, pivot_data_set_1.getIndexFields)(rows), pivotMeta: this.rowPivotMeta, }; } if (columns.includes(field)) { return { dimensions: (0, pivot_data_set_1.getIndexFields)(columns), pivotMeta: this.colPivotMeta, }; } return {}; } getDimensionValues(field, query = {}) { var _a; const { pivotMeta, dimensions } = this.getFieldsAndPivotMetaByField(field); if (!pivotMeta || !dimensions) { return []; } const isGetAllDimensionValues = (0, lodash_1.isEmpty)(query); // 暂时先对获取某一个维度所有的 labels 这样的场景做缓存处理,因为内部 flatten 逻辑比较耗时 if (this.dimensionValuesCache.has(field) && isGetAllDimensionValues) { return (_a = this.dimensionValuesCache.get(field)) !== null && _a !== void 0 ? _a : []; } const dimensionValues = (0, pivot_data_set_1.transformDimensionsValues)(query, dimensions, common_1.MULTI_VALUE); const metaValues = (0, pivot_data_set_1.getSatisfiedPivotMetaValues)({ pivotMeta, dimensionValues, fields: dimensions, fieldIdx: (0, lodash_1.indexOf)(dimensions, field), queryType: common_1.QueryDataType.DetailOnly, sortedDimensionValues: this.sortedDimensionValues, }); const result = (0, lodash_1.uniq)(metaValues.map((meta) => (0, utils_1.resolveNillString)(meta.value))); if (isGetAllDimensionValues) { this.dimensionValuesCache.set(field, result); } return result; } getTotalValue(query, totalStatus) { const { options } = this.spreadsheet; const effectiveStatus = (0, lodash_1.some)(totalStatus); const status = effectiveStatus ? totalStatus : this.getTotalStatus(query); const { aggregation, calcFunc } = (0, data_set_operate_1.getAggregationAndCalcFuncByQuery)(status, options === null || options === void 0 ? void 0 : options.totals) || {}; // 聚合方式从用户配置的 s2Options.totals 取, 在触发前端兜底计算汇总逻辑时, 如果没有汇总的配置, 默认按 [求和] 计算,避免排序失效. // tree 和 grid-tree 模式下,如果用户没有配置 totals,不应该自动聚合 const defaultAggregation = (0, lodash_1.isEmpty)(options === null || options === void 0 ? void 0 : options.totals) && !this.spreadsheet.isHierarchyTreeType() && !this.spreadsheet.isHierarchyGridTreeType() ? common_1.Aggregation.SUM : ''; const calcAction = number_calculate_1.calcActionByType[aggregation || defaultAggregation]; // 前端计算汇总值 if (calcAction || calcFunc) { const data = this.getCellMultiData({ query, queryType: common_1.QueryDataType.DetailOnly, }); let totalValue = null; if (calcFunc) { totalValue = calcFunc(query, data, this.spreadsheet); } else if (calcAction) { totalValue = calcAction(data, constant_1.VALUE_FIELD); } return cell_data_1.CellData.getCellData(Object.assign(Object.assign({}, (0, lodash_1.omit)(query, [constant_1.EXTRA_FIELD])), { [query[constant_1.EXTRA_FIELD]]: totalValue }), query[constant_1.EXTRA_FIELD]); } } getCellData(params) { var _a, _b, _c, _d; const { query = {}, rowNode, isTotals = false, totalStatus } = params || {}; const { rows: originRows, columns } = this.fields; let rows = originRows; const drillDownIdPathMap = (_a = this.spreadsheet) === null || _a === void 0 ? void 0 : _a.store.get('drillDownIdPathMap'); /* * 判断当前是否为下钻节点 * 需检查 rowNode.id 是否属于下钻根节点(drillDownIdPathMap.keys)的下属节点 */ const isDrillDown = Array.from((_b = drillDownIdPathMap === null || drillDownIdPathMap === void 0 ? void 0 : drillDownIdPathMap.keys()) !== null && _b !== void 0 ? _b : []).some((parentPath) => rowNode === null || rowNode === void 0 ? void 0 : rowNode.id.startsWith(parentPath)); // 如果是下钻结点,行维度在 originRows 中并不存在 if (rowNode && isDrillDown) { rows = (_c = node_1.Node.getFieldPath(rowNode, isDrillDown)) !== null && _c !== void 0 ? _c : originRows; } const indexRows = (0, pivot_data_set_1.getIndexFields)(rows); const indexColumns = (0, pivot_data_set_1.getIndexFields)(columns); const rowDimensionValues = (0, pivot_data_set_1.transformDimensionsValues)(query, indexRows); const colDimensionValues = (0, pivot_data_set_1.transformDimensionsValues)(query, indexColumns); const path = (0, pivot_data_set_1.getDataPath)({ rowDimensionValues, colDimensionValues, rowPivotMeta: this.rowPivotMeta, colPivotMeta: this.colPivotMeta, rowFields: indexRows, colFields: indexColumns, prefix: (0, pivot_data_set_1.getDataPathPrefix)(indexRows, indexColumns), }); const rawData = (0, lodash_1.get)(this.indexesData, path); if (rawData) { // 如果已经有数据则取已有数据 return cell_data_1.CellData.getCellData(rawData, query[constant_1.EXTRA_FIELD]); } if (isTotals) { return this.getTotalValue(query, totalStatus); } // grid-tree 模式下折叠的节点,使用小计聚合逻辑计算数据 // 折叠节点没有原始数据,需要聚合其子节点的数据 const isGridTree = (_d = this.spreadsheet) === null || _d === void 0 ? void 0 : _d.isHierarchyGridTreeType(); if (isGridTree && (rowNode === null || rowNode === void 0 ? void 0 : rowNode.isCollapsed)) { return this.getTotalValue(query, totalStatus); } } getQueryExtraFields(query) { const { values = [] } = this.fields; const extra = query[constant_1.EXTRA_FIELD]; if (extra) { return (0, lodash_1.includes)(values, extra) ? [extra] : []; } return values; } getCellMultiData(params) { const { query = {}, queryType = common_1.QueryDataType.All, drillDownFields = [], } = params || {}; if ((0, lodash_1.isEmpty)(query)) { // 如果查询的 query 为空,这样的场景其实没有意义,如果用户想获取全量数据,可以直接从 data 中获取 // eslint-disable-next-line no-console console.warn(`query: ${query} shouldn't be empty, you can get all data from dataCfg if you're intended.\n you should use { EXTRA_FIELD: xxx} as least if you want query all specific value data`); } const { rows, columns } = this.fields; const totalRows = !(0, lodash_1.isEmpty)(drillDownFields) ? rows.concat(drillDownFields) : rows; const indexRows = (0, pivot_data_set_1.getIndexFields)(totalRows); const indexColumns = (0, pivot_data_set_1.getIndexFields)(columns); const rowDimensionValues = (0, pivot_data_set_1.transformDimensionsValues)(query, indexRows, common_1.MULTI_VALUE); const colDimensionValues = (0, pivot_data_set_1.transformDimensionsValues)(query, indexColumns, common_1.MULTI_VALUE); const { rowQueries, colQueries } = (0, pivot_data_set_1.getFlattenDimensionValues)({ rowDimensionValues, colDimensionValues, rowPivotMeta: this.rowPivotMeta, colPivotMeta: this.colPivotMeta, rowFields: indexRows, colFields: indexColumns, sortedDimensionValues: this.sortedDimensionValues, queryType, }); const prefix = (0, pivot_data_set_1.getDataPathPrefix)(indexRows, indexColumns); const all = []; for (const rowQuery of rowQueries) { for (const colQuery of colQueries) { const path = (0, pivot_data_set_1.getDataPath)({ rowDimensionValues: rowQuery, colDimensionValues: colQuery, rowPivotMeta: this.rowPivotMeta, colPivotMeta: this.colPivotMeta, rowFields: indexRows, colFields: indexColumns, prefix, }); let hadMultiField = false; let result = this.indexesData; for (let i = 0; i < path.length; i++) { const current = path[i]; if (hadMultiField) { if ((0, pivot_data_set_1.isMultiValue)(current)) { result = (0, pivot_data_set_1.flattenIndexesData)(result, queryType); } else { result = (0, lodash_1.compact)((0, lodash_1.map)(result, (item) => item === null || item === void 0 ? void 0 : item[current])); } } else if ((0, pivot_data_set_1.isMultiValue)(current)) { hadMultiField = true; result = (0, lodash_1.compact)([result]); i--; } else { result = result === null || result === void 0 ? void 0 : result[current]; } } // 如果每一个维度都是被指定好的,那么最终获取的数据就是单个的 if ((0, lodash_1.isArray)(result)) { all.push(...result); } else if (result) { all.push(result); } } } const extraFields = this.getQueryExtraFields(query); // 多个 extra field 有时对应的同一个对象,需要进行去重 return (0, lodash_1.flatMap)((0, lodash_1.uniq)(all), (item) => { return item ? cell_data_1.CellData.getCellDataList(item, extraFields) : []; }); } getFieldFormatter(field, cellMeta) { // 兼容总计小计场景 if (field === constant_1.TOTAL_VALUE) { return this.getFieldFormatterForTotalValue(cellMeta); } return super.getFieldFormatter(field); } getFieldFormatterForTotalValue(cellMeta) { let valueField = ''; // 当数据置于行头时,小计总计列尝试去找对应的指标 if (!this.spreadsheet.isValueInCols() && cellMeta) { valueField = (0, lodash_1.get)(cellMeta.rowQuery, constant_1.EXTRA_FIELD); } // 如果没有找到对应指标,则默认取第一个维度 valueField = valueField !== null && valueField !== void 0 ? valueField : (0, lodash_1.get)(this.fields.values, 0); return super.getFieldFormatter(valueField); } /** * 自定义度量组位置值 * @param customValueOrder 用户配置度量组位置,从 0 开始 * @param fields Rows || Columns */ handleCustomMeasuresOrder(customValueOrder, fields) { const newFields = (0, lodash_1.uniq)([...fields]); if (fields.length >= customValueOrder) { newFields.splice(customValueOrder, 0, constant_1.EXTRA_FIELD); return newFields; } // 当用户配置的度量组位置大于等于度量组数量时,默认放在最后 return [...newFields, constant_1.EXTRA_FIELD]; } // 是否开启自定义度量组位置值 isCustomMeasuresPosition(customValueOrder) { return (0, lodash_1.isNumber)(customValueOrder); } getRowData(cellMeta) { return this.getCellMultiData({ query: cellMeta.rowQuery }); } } exports.PivotDataSet = PivotDataSet; //# sourceMappingURL=pivot-data-set.js.map