UNPKG

@antv/s2

Version:

effective spreadsheet render core lib

357 lines 18.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processSelectedPivotByDataCell = exports.asyncProcessSelectedAllPivot = exports.processSelectedAllPivot = exports.processSelectedPivotByHeader = exports.PivotDataCellCopy = void 0; const tslib_1 = require("tslib"); const lodash_1 = require("lodash"); const common_1 = require("../../../common"); const pivot_data_set_1 = require("../../dataset/pivot-data-set"); const method_1 = require("../method"); const base_data_cell_copy_1 = require("./base-data-cell-copy"); const common_2 = require("./common"); class PivotDataCellCopy extends base_data_cell_copy_1.BaseDataCellCopy { constructor(params) { super(params); this.leafRowNodes = []; this.leafColNodes = []; /** * 兼容 hideMeasureColumn 方案:hideMeasureColumn 的隐藏实现是通过截取掉度量(measure)数据,但是又只截取了 Node 中的,像 pivotMeta 中的又是完整的。导致复制时,无法通过 Node 找出正确路径。 * https://github.com/antvis/S2/issues/1955 */ this.compatibleHideMeasureColumn = () => { var _a, _b, _c, _d; const isHideValue = ((_c = (_b = (_a = this.spreadsheet.options) === null || _a === void 0 ? void 0 : _a.style) === null || _b === void 0 ? void 0 : _b.colCell) === null || _c === void 0 ? void 0 : _c.hideValue) && this.spreadsheet.isValueInCols(); // 被 hideMeasureColumn 隐藏的 度量(measure) 值,手动添加上。 return isHideValue ? { [common_1.EXTRA_FIELD]: (_d = this.spreadsheet.dataCfg.fields.values) === null || _d === void 0 ? void 0 : _d[0], } : {}; }; this.getDataMatrixByHeaderNode = () => { const measureQuery = this.compatibleHideMeasureColumn(); return (0, lodash_1.map)(this.leafRowNodes, (rowNode) => this.leafColNodes.map((colNode) => { return this.getDataCellValue({ rowNode, colNode, config: { measureQuery, }, }); })); }; this.getDataMatrixByHeaderNodeRIC = () => { const matrix = []; let rowIndex = 0; const measureQuery = this.compatibleHideMeasureColumn(); // 在所有单元格数据获取成功后 resolve return new Promise((resolve, reject) => { try { // 因为每次 requestIdleCallback 执行的时间不一样,所以需要记录下当前执行到的 this.leafRowNodes 和 this.leafColNodes const dataMatrixIdleCallback = (deadline) => { const rowLength = this.leafRowNodes.length; // requestIdleCallback 浏览器空闲时会多次执行, 只有一行数据时执行一次即可, 避免生成重复数据 this.initIdleCallbackCount(rowLength); while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && rowIndex <= rowLength - 1 && this.idleCallbackCount > 0) { for (let j = rowIndex; j < rowLength && this.idleCallbackCount > 0; j++) { const row = []; const rowNode = this.leafRowNodes[j]; for (let i = 0; i < this.leafColNodes.length; i++) { const colNode = this.leafColNodes[i]; const dataItem = this.getDataCellValue({ rowNode, colNode, config: { measureQuery, }, }); row.push(dataItem); } rowIndex++; matrix.push(row); this.idleCallbackCount--; } } if (rowIndex === rowLength) { resolve(matrix); } else { // 重置 idleCallbackCount,避免下次 requestIdleCallback 时 idleCallbackCount 为 0 this.initIdleCallbackCount(rowLength); requestIdleCallback(dataMatrixIdleCallback, common_2.ricOptions); } }; requestIdleCallback(dataMatrixIdleCallback, common_2.ricOptions); } catch (e) { reject(e); } }); }; this.getDataCellValue = ({ rowNode, colNode, config, }) => { var _a; const { measureQuery } = config; const query = Object.assign(Object.assign(Object.assign({}, rowNode.query), colNode.query), measureQuery); const isTotals = rowNode.isTotals || rowNode.isTotalMeasure || colNode.isTotals || colNode.isTotalMeasure; const cellData = this.spreadsheet.dataSet.getCellData({ query, rowNode, isTotals, totalStatus: (0, pivot_data_set_1.getHeaderTotalStatus)(rowNode, colNode), }); const formatNode = this.spreadsheet.isValueInCols() ? colNode : rowNode; let field = (_a = (0, method_1.getColNodeFieldFromNode)(this.spreadsheet.isPivotMode, formatNode)) !== null && _a !== void 0 ? _a : ''; // 主要解决只有一个度量时,总计小计对应的值无法格式化的问题 const { values } = this.spreadsheet.dataCfg.fields; field = (values === null || values === void 0 ? void 0 : values.includes(field)) ? field : values === null || values === void 0 ? void 0 : values[0]; const formatter = this.getFormatter({ field: field !== null && field !== void 0 ? field : colNode.field, rowIndex: rowNode.rowIndex, colIndex: colNode.colIndex, }); const fieldValue = cellData === null || cellData === void 0 ? void 0 : cellData[common_1.VALUE_FIELD]; const isChartData = (0, lodash_1.isPlainObject)(fieldValue === null || fieldValue === void 0 ? void 0 : fieldValue.values); const value = isChartData ? '' : fieldValue; return formatter(value !== null && value !== void 0 ? value : ''); }; this.getCustomRowCornerMatrix = (rowMatrix) => { const maxRowLen = (0, common_2.getMaxRowLen)(rowMatrix !== null && rowMatrix !== void 0 ? rowMatrix : []); const cornerNodes = this.spreadsheet.facet.getCornerNodes(); // 对 cornerNodes 进行排序, cornerType === CornerNodeType.Col 的放在前面 const sortedCornerNodes = (0, lodash_1.sortBy)(cornerNodes, (node) => { return node.cornerType === common_1.CornerNodeType.Col ? 0 : 1; }); // 树状模式 if (this.spreadsheet.isHierarchyTreeType()) { // 角头需要根据行头的最大长度进行填充,最后一列的值为角头的值 return (0, lodash_1.map)(sortedCornerNodes, (node) => { const result = new Array(maxRowLen).fill(''); result[maxRowLen - 1] = node.value; return result; }); } // 平铺模式 return Object.values((0, lodash_1.groupBy)(sortedCornerNodes, 'y')).map((nodes) => { const placeholder = new Array(maxRowLen - nodes.length).fill(''); const result = nodes.map((node) => node.value); return [...placeholder, ...result]; }); }; this.getFieldName = (field) => { return this.config.formatHeader ? this.spreadsheet.dataSet.getFieldName(field) : this.spreadsheet.dataSet.getField(field); }; this.getCornerMatrix = (rowMatrix) => { if (this.spreadsheet.isCustomRowFields()) { return this.getCustomRowCornerMatrix(rowMatrix); } const { colsHierarchy } = this.spreadsheet.facet.getLayoutResult(); const { fields } = this.spreadsheet.dataCfg; const { columns = [], rows = [] } = fields; // 为了对齐数值, 增加 "" 占位 // 自定义列头不需要占位, 但是为树状结构, 需要根据采样节点解析: https://github.com/antvis/S2/issues/2844) const customColumns = this.spreadsheet.isCustomColumnFields() ? colsHierarchy .getNodes() .slice(0, colsHierarchy.sampleNodesForAllLevels.length) .map((node) => node.field) : [...columns, '']; const maxRowLen = this.spreadsheet.isHierarchyTreeType() ? (0, common_2.getMaxRowLen)(rowMatrix !== null && rowMatrix !== void 0 ? rowMatrix : []) : rows.length; const customRows = (0, lodash_1.slice)(rows, 0, maxRowLen); /** * cornerMatrix 形成的矩阵为 rows.length(宽) * columns.length(高) */ return (0, lodash_1.map)(customColumns, (colField, colIndex) => (0, lodash_1.map)(customRows, (rowField, rowIndex) => { // 角头的最后一行,为行头 if (colIndex === customColumns.length - 1) { return this.getFieldName(rowField); } // 角头的最后一列,为列头 if (rowIndex === maxRowLen - 1) { return this.getFieldName(colField); } return ''; })); }; this.getDataMatrixByDataCell = (cellMetaMatrix) => { const { copy } = this.spreadsheet.options.interaction; const measureQuery = this.compatibleHideMeasureColumn(); const dataMatrix = (0, lodash_1.map)(cellMetaMatrix, (cellsMeta) => (0, lodash_1.map)(cellsMeta, (meta) => { const [rowNode, colNode] = (0, common_2.getHeaderNodeFromMeta)(meta, this.spreadsheet); const dataItem = this.getDataCellValue({ rowNode: rowNode, colNode: colNode, config: { measureQuery, }, }); return dataItem; })); // 不带表头复制 if (!(copy === null || copy === void 0 ? void 0 : copy.withHeader)) { return this.matrixTransformer(dataMatrix, this.config.separator); } // 带表头复制 const rowMatrix = this.getRowMatrix(); const colMatrix = this.getColMatrix(); return this.matrixTransformer((0, common_2.assembleMatrix)({ rowMatrix, colMatrix, dataMatrix }), this.config.separator); }; this.getAsyncAllPivotCopyData = () => tslib_1.__awaiter(this, void 0, void 0, function* () { const rowMatrix = this.getRowMatrix(); const colMatrix = this.getColMatrix(); const cornerMatrix = this.getCornerMatrix(rowMatrix); let dataMatrix = []; // 把两类导出都封装成异步的,保证导出类型的一致 if (this.isEnableASync()) { dataMatrix = (yield this.getDataMatrixByHeaderNodeRIC()); } else { dataMatrix = (yield Promise.resolve(this.getDataMatrixByHeaderNode())); } const resultMatrix = this.matrixTransformer((0, common_2.assembleMatrix)({ rowMatrix, colMatrix, dataMatrix, cornerMatrix }), this.config.separator); return resultMatrix; }); this.getPivotAllCopyData = () => { const rowMatrix = this.getRowMatrix(); const colMatrix = this.getColMatrix(); const cornerMatrix = this.getCornerMatrix(rowMatrix); const dataMatrix = this.getDataMatrixByHeaderNode(); const resultMatrix = this.matrixTransformer((0, common_2.assembleMatrix)({ rowMatrix, colMatrix, dataMatrix, cornerMatrix }), this.config.separator); return resultMatrix; }; this.leafRowNodes = this.getLeafRowNodes(); this.leafColNodes = this.getLeafColNodes(); } getHeaderNodeMatrix(node) { // 透视表的表头也是可以格式化的 (虚拟数值列 (EXTRA_FIELD)除外) if (this.config.formatHeader) { return (0, common_2.getNodeFormatData)(node); } return super.getHeaderNodeMatrix(node); } getLeafRowNodes() { const rowLeafNodes = this.spreadsheet.facet.getRowLeafNodes(); const selectedRowsMeta = (0, method_1.getSelectedRows)(this.config.selectedCells); const isTreeData = this.spreadsheet.isHierarchyTreeType(); if ((0, lodash_1.isEmpty)(selectedRowsMeta)) { return rowLeafNodes; } // selectedRowMeta 选中了指定的行头,则只展示对应行头对应的数据 return this.getSelectedNode(selectedRowsMeta, rowLeafNodes, isTreeData); } getLeafColNodes() { const colLeafNodes = this.spreadsheet.facet.getColLeafNodes(); const selectedColsMeta = (0, method_1.getSelectedCols)(this.config.selectedCells); if ((0, lodash_1.isEmpty)(selectedColsMeta)) { return colLeafNodes; } // selectedColNodes 选中了指定的列头,则只展示对应列头对应的数据 return this.getSelectedNode(selectedColsMeta, colLeafNodes); } getSelectedNode(selectedMeta, allRowOrColLeafNodes, isTreeData = false) { if (isTreeData) { const selectedIds = new Set(selectedMeta.map((meta) => meta.id)); return allRowOrColLeafNodes.filter((node) => selectedIds.has(node.id)); } return selectedMeta.reduce((nodes, cellMeta) => { const parentId = cellMeta.id; const filterNodes = allRowOrColLeafNodes.filter((node) => { // 核心修复逻辑: // 1. node.id === parentId -> 完全匹配,例如 "root[&]四川省" 匹配 "root[&]四川省" // 2. node.id.startsWith(parentId + delimiter) -> 匹配子孙,例如 "root[&]四川省[&]成都市" return (node.id === parentId || node.id.startsWith(parentId + common_1.NODE_ID_SEPARATOR)); }); nodes.push(...filterNodes); return nodes; }, []); } getColMatrix() { return (0, lodash_1.zip)(...(0, lodash_1.map)(this.leafColNodes, (node) => this.getHeaderNodeMatrix(node))); } getRowMatrix() { const rowMatrix = (0, lodash_1.map)(this.leafRowNodes, (node) => this.getHeaderNodeMatrix(node)); return (0, common_2.completeMatrix)(rowMatrix); } getPivotCopyData() { const { copy } = this.spreadsheet.options.interaction; const dataMatrix = this.getDataMatrixByHeaderNode(); // 不带表头复制 if (!(copy === null || copy === void 0 ? void 0 : copy.withHeader)) { return this.matrixTransformer(dataMatrix, this.config.separator); } // 带表头复制 const rowMatrix = this.getRowMatrix(); const colMatrix = this.getColMatrix(); return this.matrixTransformer((0, common_2.assembleMatrix)({ rowMatrix, colMatrix, dataMatrix }), this.config.separator); } } exports.PivotDataCellCopy = PivotDataCellCopy; function processSelectedPivotByHeader(spreadsheet, selectedCells) { const pivotDataCellCopy = new PivotDataCellCopy({ spreadsheet, config: { selectedCells, }, }); return pivotDataCellCopy.getPivotCopyData(); } exports.processSelectedPivotByHeader = processSelectedPivotByHeader; // 全量导出使用 const processSelectedAllPivot = (params) => { const { sheetInstance, split, formatOptions, customTransformer } = params; const pivotDataCellCopy = new PivotDataCellCopy({ spreadsheet: sheetInstance, isExport: true, config: { separator: split, formatOptions, customTransformer, }, }); return pivotDataCellCopy.getPivotAllCopyData(); }; exports.processSelectedAllPivot = processSelectedAllPivot; const asyncProcessSelectedAllPivot = (params) => { const { sheetInstance, split, formatOptions, customTransformer, async } = params; const pivotDataCellCopy = new PivotDataCellCopy({ spreadsheet: sheetInstance, isExport: true, config: { separator: split, formatOptions, customTransformer, async: async !== null && async !== void 0 ? async : true, }, }); return pivotDataCellCopy.getAsyncAllPivotCopyData(); }; exports.asyncProcessSelectedAllPivot = asyncProcessSelectedAllPivot; /** * 刷选单元格数据时使用此方法 * @param {SpreadSheet} spreadsheet * @param {CellMeta[][]} selectedCells * @param {CellMeta[]} headerSelectedCells * @return {CopyableList} */ const processSelectedPivotByDataCell = ({ spreadsheet, selectedCells, headerSelectedCells, }) => { const pivotDataCellCopy = new PivotDataCellCopy({ spreadsheet, config: { selectedCells: headerSelectedCells, formatOptions: true, }, }); return pivotDataCellCopy.getDataMatrixByDataCell(selectedCells); }; exports.processSelectedPivotByDataCell = processSelectedPivotByDataCell; //# sourceMappingURL=pivot-data-cell-copy.js.map