@antv/s2
Version:
effective spreadsheet render core lib
357 lines • 18.2 kB
JavaScript
"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