@antv/s2
Version:
effective spreadsheet render core lib
462 lines • 22 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PivotChartFacet = void 0;
const s2_1 = require("@antv/s2");
const lodash_1 = require("lodash");
const constant_1 = require("../constant");
const axis_col_1 = require("../header/axis-col");
const axis_corner_1 = require("../header/axis-corner");
const axis_row_1 = require("../header/axis-row");
const corner_1 = require("../header/corner");
const axis_col_cell_1 = require("../cell/axis-col-cell");
const axis_corner_cell_1 = require("../cell/axis-corner-cell");
const axis_row_cell_1 = require("../cell/axis-row-cell");
const cell_type_1 = require("../cell/cell-type");
const separate_axis_1 = require("../utils/separate-axis");
const corner_bbox_1 = require("./corner-bbox");
const frame_1 = require("./frame");
const panel_bbox_1 = require("./panel-bbox");
class PivotChartFacet extends s2_1.PivotFacet {
constructor() {
super(...arguments);
/**
* 获取单元格的所有子节点 (含非可视区域)
* @example
* const rowCell = facet.getRowCells()[0]
* facet.getCellChildrenNodes(rowCell)
*/
this.getCellChildrenNodes = (cell) => {
var _a;
const selectNode = (_a = cell === null || cell === void 0 ? void 0 : cell.getMeta) === null || _a === void 0 ? void 0 : _a.call(cell);
return s2_1.Node.getAllChildrenNodes(selectNode, (node) => {
// 行列头区域,也把对应的 axis 区域 node 返回
return node.relatedNode ? [node, node.relatedNode] : [node];
});
};
}
doLayout() {
let layoutResult = this.buildAllHeaderHierarchy();
layoutResult = (0, separate_axis_1.separateRowColLeafNodes)(layoutResult, this.spreadsheet);
this.calculateHeaderNodesCoordinate(layoutResult);
this.calculateAxisHierarchyCoordinate(layoutResult);
const { rowsHierarchy, colsHierarchy, axisRowsHierarchy, axisColsHierarchy, } = layoutResult;
return {
axisRowsHierarchy,
axisColsHierarchy,
rowsHierarchy,
rowNodes: rowsHierarchy.getNodes(),
rowLeafNodes: rowsHierarchy.getLeaves(),
colsHierarchy,
colNodes: colsHierarchy.getNodes(),
colLeafNodes: colsHierarchy.getLeaves(),
};
}
getColLeafNodeRelatedCount(colNode) {
const isValueInCols = this.spreadsheet.isValueInCols();
const isPolar = this.spreadsheet.isPolarCoordinate();
const size = !isValueInCols && !isPolar
? (0, lodash_1.get)(colNode.relatedNode, 'children', []).length
: 1;
return size;
}
getRowLeafNodeRelatedCount(rowNode) {
const isValueInCols = this.spreadsheet.isValueInCols();
const isPolar = this.spreadsheet.isPolarCoordinate();
const size = isValueInCols && !isPolar
? (0, lodash_1.get)(rowNode.relatedNode, 'children', []).length
: 1;
return size;
}
getRowAxisWidth() {
var _a, _b;
const { rowCell } = this.spreadsheet.options.style;
const { rows = [] } = this.spreadsheet.dataSet.fields;
const lastRow = (0, lodash_1.last)(rows);
return (0, s2_1.round)((_b = (_a = rowCell === null || rowCell === void 0 ? void 0 : rowCell.widthByField) === null || _a === void 0 ? void 0 : _a[lastRow]) !== null && _b !== void 0 ? _b : 0);
}
getColAxisHeight() {
var _a, _b;
const { colCell } = this.spreadsheet.options.style;
const { columns = [] } = this.spreadsheet.dataSet.fields;
const lastCol = (0, lodash_1.last)(columns);
return (0, s2_1.round)((_b = (_a = colCell === null || colCell === void 0 ? void 0 : colCell.heightByField) === null || _a === void 0 ? void 0 : _a[lastCol]) !== null && _b !== void 0 ? _b : 0);
}
getCompactGridColNodeWidth(colNode) {
const { dataCell } = this.spreadsheet.options.style;
const dataCellWidth = (0, s2_1.getCellWidth)(dataCell, this.getColLeafNodeRelatedCount(colNode));
return (0, s2_1.round)(dataCellWidth);
}
getAdaptGridColWidth(colLeafNodes, colNode, rowHeaderWidth) {
const { rows = [] } = this.spreadsheet.dataSet.fields;
const { dataCell } = this.spreadsheet.options.style;
const rowHeaderColSize = Math.max(0, rows.length - 1);
const colHeaderColSize = (0, lodash_1.sum)(colLeafNodes.map((node) => this.getColLeafNodeRelatedCount(node)));
const { width } = this.getCanvasSize();
const availableWidth = width -
this.getSeriesNumberWidth() -
this.getRowAxisWidth() -
frame_1.Frame.getVerticalBorderWidth(this.spreadsheet);
const colSize = Math.max(1, rowHeaderColSize + colHeaderColSize);
const currentSize = colNode ? this.getColLeafNodeRelatedCount(colNode) : 1;
if (!rowHeaderWidth) {
return (0, s2_1.round)(currentSize *
Math.max((0, s2_1.getCellWidth)(dataCell), (0, lodash_1.floor)(availableWidth / colSize)));
}
return (0, s2_1.round)(currentSize *
Math.max((0, s2_1.getCellWidth)(dataCell), (0, lodash_1.floor)((availableWidth - rowHeaderWidth) / colHeaderColSize)));
}
getRowLeafNodeHeight(rowLeafNode) {
var _a;
const customHeight = this.getCustomRowCellHeight(rowLeafNode);
// 1. 拖拽后的宽度优先级最高
if ((0, lodash_1.isNumber)(customHeight)) {
return (0, s2_1.round)(customHeight);
}
const { dataCell } = this.spreadsheet.options.style;
const dataCellHeight = (0, s2_1.round)((_a = dataCell === null || dataCell === void 0 ? void 0 : dataCell.height) !== null && _a !== void 0 ? _a : 0);
return this.getRowLeafNodeRelatedCount(rowLeafNode) * dataCellHeight;
}
calculateAxisHierarchyCoordinate(layoutResult) {
this.adjustTotalNodesCoordinateAfterSeparateAxisHierarchy(layoutResult);
this.calculateAxisRowsHierarchyCoordinate(layoutResult);
this.calculateAxisColsHierarchyCoordinate(layoutResult);
}
adjustTotalNodesCoordinateAfterSeparateAxisHierarchy(layoutResult) {
// 最后一个维度分离出去后,再存在总计、小计分组时,会存在总计、小计格子出现空缺,因为 pivot-facet 层是按照未拆分的逻辑做的补全。
// 拆分后需要再处理一下,而且只需要针对维度拆分的部分做处理即可,指标拆分正常显示
var _a, _b;
const { rowsHierarchy, colsHierarchy } = layoutResult;
if (!(0, lodash_1.isEmpty)((_a = this.spreadsheet.options.totals) === null || _a === void 0 ? void 0 : _a.row) &&
this.spreadsheet.isValueInCols()) {
const sampleNodeForLastLevel = rowsHierarchy.sampleNodeForLastLevel;
const maxX = sampleNodeForLastLevel.x + sampleNodeForLastLevel.width;
rowsHierarchy.getLeaves().forEach((leaf) => {
const rightX = leaf.x + leaf.width;
if (maxX > rightX) {
leaf.width += maxX - rightX;
}
});
}
if (!(0, lodash_1.isEmpty)((_b = this.spreadsheet.options.totals) === null || _b === void 0 ? void 0 : _b.col) &&
!this.spreadsheet.isValueInCols()) {
const sampleNodeForLastLevel = colsHierarchy.sampleNodeForLastLevel;
const maxY = sampleNodeForLastLevel.y + sampleNodeForLastLevel.height;
colsHierarchy.getLeaves().forEach((leaf) => {
const bottomY = leaf.y + leaf.height;
if (maxY > bottomY) {
leaf.height += maxY - bottomY;
}
});
}
}
calculateAxisRowsHierarchyCoordinate(layoutResult) {
const { rowsHierarchy, axisRowsHierarchy } = layoutResult;
if (!axisRowsHierarchy) {
return;
}
const isValueInCols = this.spreadsheet.isValueInCols();
const isPolar = this.spreadsheet.isPolarCoordinate();
rowsHierarchy.width =
rowsHierarchy.isPlaceholder && isValueInCols && !isPolar
? 0
: rowsHierarchy.width;
const rowAxisWidth = this.getRowAxisWidth();
rowsHierarchy.getLeaves().forEach((leaf) => {
const relatedNode = leaf.relatedNode;
if (!relatedNode) {
return;
}
relatedNode.y = leaf.y;
relatedNode.width = rowAxisWidth;
relatedNode.height = leaf.height;
});
if (isValueInCols && isPolar) {
axisRowsHierarchy.width = 0;
axisRowsHierarchy.getNodes().forEach((node) => {
node.width = 0;
});
}
else {
axisRowsHierarchy.width = rowAxisWidth;
}
axisRowsHierarchy.height = rowsHierarchy.height;
}
calculateAxisColsHierarchyCoordinate(layoutResult) {
const { colsHierarchy, axisColsHierarchy } = layoutResult;
if (!axisColsHierarchy) {
return;
}
const isValueInCols = this.spreadsheet.isValueInCols();
const isPolar = this.spreadsheet.isPolarCoordinate();
const colAxisHeight = this.getColAxisHeight();
colsHierarchy.getLeaves().forEach((leaf) => {
const relatedNode = leaf.relatedNode;
if (!relatedNode) {
return;
}
relatedNode.x = leaf.x;
relatedNode.width = leaf.width;
relatedNode.height = colAxisHeight;
});
axisColsHierarchy.width = colsHierarchy.width;
if (!isValueInCols && isPolar) {
axisColsHierarchy.height = 0;
axisColsHierarchy.getNodes().forEach((node) => {
node.height = 0;
});
}
else {
axisColsHierarchy.height = colAxisHeight;
}
}
calculateCornerBBox() {
this.cornerBBox = new corner_bbox_1.CornerBBox(this, true);
}
calculatePanelBBox() {
this.panelBBox = new panel_bbox_1.PanelBBox(this, true);
}
getCenterFrame() {
var _a;
if (!this.centerFrame) {
const { viewportWidth, viewportHeight } = this.panelBBox;
const cornerWidth = this.cornerBBox.width;
const cornerHeight = this.cornerBBox.height;
const frame = (_a = this.spreadsheet.options) === null || _a === void 0 ? void 0 : _a.frame;
const frameCfg = {
position: {
x: this.cornerBBox.x,
y: this.cornerBBox.y,
},
cornerWidth,
cornerHeight,
viewportWidth,
viewportHeight,
showViewportLeftShadow: false,
showViewportRightShadow: false,
spreadsheet: this.spreadsheet,
};
return frame ? frame(frameCfg) : new frame_1.Frame(frameCfg);
}
return this.centerFrame;
}
renderHeaders() {
super.renderHeaders();
this.axisRowHeader = this.getAxisRowHeader();
if (this.axisRowHeader) {
this.foregroundGroup.appendChild(this.axisRowHeader);
}
this.axisColumnHeader = this.getAxisColHeader();
if (this.axisColumnHeader) {
this.foregroundGroup.appendChild(this.axisColumnHeader);
}
this.axisCornerHeader = this.getAxisCornerHeader();
if (this.axisCornerHeader) {
this.foregroundGroup.appendChild(this.axisCornerHeader);
}
}
getCornerHeader() {
return (this.cornerHeader ||
corner_1.CornerHeader.getCornerHeader({
panelBBox: this.panelBBox,
cornerBBox: this.cornerBBox,
seriesNumberWidth: this.getSeriesNumberWidth(),
layoutResult: this.layoutResult,
spreadsheet: this.spreadsheet,
}));
}
getAxisRowHeader() {
var _a;
if (this.axisRowHeader) {
return this.axisRowHeader;
}
const { y, viewportHeight, viewportWidth, height } = this.panelBBox;
const { rowsHierarchy, axisRowsHierarchy } = this.layoutResult;
const seriesNumberWidth = this.getSeriesNumberWidth();
return new axis_row_1.AxisRowHeader({
width: this.cornerBBox.width,
height,
viewportWidth,
viewportHeight,
position: { x: seriesNumberWidth + rowsHierarchy.width, y },
nodes: (_a = axisRowsHierarchy === null || axisRowsHierarchy === void 0 ? void 0 : axisRowsHierarchy.getNodes()) !== null && _a !== void 0 ? _a : [],
spreadsheet: this.spreadsheet,
});
}
getAxisColHeader() {
var _a, _b;
if (this.axisColumnHeader) {
return this.axisColumnHeader;
}
const { x, width, viewportWidth, y, viewportHeight } = this.panelBBox;
const { axisColsHierarchy } = this.layoutResult;
return new axis_col_1.AxisColHeader({
width,
cornerWidth: this.cornerBBox.width,
height: (_a = axisColsHierarchy === null || axisColsHierarchy === void 0 ? void 0 : axisColsHierarchy.height) !== null && _a !== void 0 ? _a : 0,
viewportWidth,
viewportHeight,
position: { x, y: y + viewportHeight },
nodes: (_b = axisColsHierarchy === null || axisColsHierarchy === void 0 ? void 0 : axisColsHierarchy.getNodes()) !== null && _b !== void 0 ? _b : [],
spreadsheet: this.spreadsheet,
});
}
getAxisCornerHeader() {
return (this.axisCornerHeader ||
axis_corner_1.AxisCornerHeader.getCornerHeader({
panelBBox: this.panelBBox,
cornerBBox: this.cornerBBox,
seriesNumberWidth: this.getSeriesNumberWidth(),
layoutResult: this.layoutResult,
spreadsheet: this.spreadsheet,
}));
}
translateRelatedGroups(scrollX, scrollY, hRowScroll) {
var _a, _b, _c;
super.translateRelatedGroups(scrollX, scrollY, hRowScroll);
(_a = this.axisRowHeader) === null || _a === void 0 ? void 0 : _a.onScrollXY(this.getRealScrollX(scrollX, hRowScroll), scrollY, constant_1.KEY_GROUP_ROW_AXIS_RESIZE_AREA);
(_b = this.axisColumnHeader) === null || _b === void 0 ? void 0 : _b.onColScroll(scrollX, constant_1.KEY_GROUP_COL_AXIS_RESIZE_AREA);
(_c = this.axisCornerHeader) === null || _c === void 0 ? void 0 : _c.onCorScroll(this.getRealScrollX(scrollX, hRowScroll));
}
renderRowScrollBar(rowHeaderScrollX) {
super.renderRowScrollBar(rowHeaderScrollX);
if (this.hRowScrollBar) {
const maxOffset = this.cornerBBox.originalWidth - this.cornerBBox.width;
this.hRowScrollBar.addEventListener(s2_1.ScrollType.ScrollChange, ({ offset }) => {
var _a, _b;
const newOffset = this.getValidScrollBarOffset(offset, maxOffset);
const newRowHeaderScrollX = (0, lodash_1.floor)(newOffset);
this.setScrollOffset({ rowHeaderScrollX: newRowHeaderScrollX });
(_a = this.axisRowHeader) === null || _a === void 0 ? void 0 : _a.onRowScrollX(newRowHeaderScrollX, constant_1.KEY_GROUP_ROW_AXIS_RESIZE_AREA);
(_b = this.axisCornerHeader) === null || _b === void 0 ? void 0 : _b.onRowScrollX(newRowHeaderScrollX);
});
}
}
/**
* 根据行列索引获取单元格元数据
*/
getCellMeta(rowIndex = 0, colIndex = 0) {
var _a, _b, _c, _d;
const { options, dataSet } = this.spreadsheet;
const { axisRowsHierarchy, axisColsHierarchy } = this.getLayoutResult();
const rowAxisLeafNodes = (_a = axisRowsHierarchy === null || axisRowsHierarchy === void 0 ? void 0 : axisRowsHierarchy.getLeaves()) !== null && _a !== void 0 ? _a : [];
const colAxisLeafNodes = (_b = axisColsHierarchy === null || axisColsHierarchy === void 0 ? void 0 : axisColsHierarchy.getLeaves()) !== null && _b !== void 0 ? _b : [];
const rowAxis = rowAxisLeafNodes[rowIndex];
const colAxis = colAxisLeafNodes[colIndex];
if (!rowAxis || !colAxis) {
return null;
}
const data = [];
const xField = rowAxis.field === s2_1.EXTRA_FIELD ? colAxis.field : rowAxis.field;
const yField = rowAxis.field === s2_1.EXTRA_FIELD ? rowAxis.value : colAxis.value;
for (const rowChild of rowAxis.children) {
for (const colChild of colAxis.children) {
const rowQuery = rowChild.query;
const colQuery = colChild.query;
const isTotals = rowChild.isTotals ||
rowChild.isTotalMeasure ||
colChild.isTotals ||
colChild.isTotalMeasure;
const totalStatus = (0, s2_1.getHeaderTotalStatus)(rowChild, colChild);
const dataQuery = (0, lodash_1.merge)({}, rowQuery, colQuery);
const current = dataSet.getCellData({
query: dataQuery,
isTotals,
totalStatus,
});
let xValue;
let xValueShouldFormatter = true;
if (rowChild.field === s2_1.EXTRA_FIELD) {
xValue = colChild.value;
xValueShouldFormatter = !colChild.isTotalRoot;
}
else {
xValue = rowChild.value;
xValueShouldFormatter = !rowChild.isTotalRoot;
}
const origin = Object.assign({ [xField]: xValue, [constant_1.X_FIELD_FORMATTER]: xValueShouldFormatter }, current === null || current === void 0 ? void 0 : current[s2_1.ORIGIN_FIELD]);
data.push(origin);
}
}
const cellMeta = {
spreadsheet: this.spreadsheet,
x: colAxis.x,
y: rowAxis.y,
width: colAxis.width,
height: rowAxis.height,
data,
rowIndex,
colIndex,
rowId: rowAxis.id,
colId: colAxis.id,
fieldValue: data,
valueField: yField,
xField,
yField,
id: (0, s2_1.getDataCellId)(rowAxis.id, colAxis.id),
};
return (_d = (_c = options.layoutCellMeta) === null || _c === void 0 ? void 0 : _c.call(options, cellMeta)) !== null && _d !== void 0 ? _d : cellMeta;
}
getFrozenColSplitLineSize() {
var _a;
const { viewportHeight, y: panelBBoxStartY } = this.panelBBox;
const { axisColsHierarchy } = this.layoutResult;
const height = viewportHeight + panelBBoxStartY + ((_a = axisColsHierarchy === null || axisColsHierarchy === void 0 ? void 0 : axisColsHierarchy.height) !== null && _a !== void 0 ? _a : 0);
return {
y: 0,
height,
};
}
getAxisCornerCells() {
var _a;
const headerChildren = (((_a = this.getAxisCornerHeader()) === null || _a === void 0 ? void 0 : _a.children) ||
[]);
return (0, s2_1.getAllChildCells)(headerChildren, axis_corner_cell_1.AxisCornerCell).filter((cell) => cell.cellType === cell_type_1.AxisCellType.AXIS_CORNER_CELL);
}
getAxisRowCells() {
var _a;
const headerChildren = (((_a = this.getAxisRowHeader()) === null || _a === void 0 ? void 0 : _a.children) ||
[]);
return (0, s2_1.getAllChildCells)(headerChildren, axis_row_cell_1.AxisRowCell).filter((cell) => cell.cellType === cell_type_1.AxisCellType.AXIS_ROW_CELL);
}
getAxisColCells() {
var _a;
const headerChildren = (((_a = this.getAxisColHeader()) === null || _a === void 0 ? void 0 : _a.children) ||
[]);
return (0, s2_1.getAllChildCells)(headerChildren, axis_col_cell_1.AxisColCell).filter((cell) => cell.cellType === cell_type_1.AxisCellType.AXIS_COL_CELL);
}
/**
* 获取表头单元格 (序号,角头,行头,列头) (不含可视区域)
* @example 获取全部: facet.getHeaderCells()
* @example 获取一组 facet.getHeaderCells(['root[&]浙江省[&]宁波市', 'root[&]浙江省[&]杭州市'])
*/
getHeaderCells(cellIds) {
const headerCells = (0, lodash_1.concat)(this.getCornerCells(), this.getSeriesNumberCells(), this.getRowCells(), this.getColCells(), this.getAxisCornerCells(), this.getAxisRowCells(), this.getAxisColCells());
return this.filterCells(headerCells, cellIds);
}
getAxisCornerNodes() {
var _a;
return ((_a = this.axisCornerHeader) === null || _a === void 0 ? void 0 : _a.getNodes()) || [];
}
getAxisRowNodes() {
var _a;
return ((_a = this.axisRowHeader) === null || _a === void 0 ? void 0 : _a.getNodes()) || [];
}
getAxisColNodes() {
var _a;
return ((_a = this.axisColumnHeader) === null || _a === void 0 ? void 0 : _a.getNodes()) || [];
}
/**
* 获取表头节点 (角头,序号,行头,列头) (含可视区域)
* @example 获取全部: facet.getHeaderNodes()
* @example 获取一组 facet.getHeaderNodes(['root[&]浙江省[&]宁波市', 'root[&]浙江省[&]杭州市'])
*/
getHeaderNodes(nodeIds) {
const headerNodes = (0, lodash_1.concat)(this.getCornerNodes(), this.getSeriesNumberNodes(), this.getRowNodes(), this.getColNodes(), this.getAxisCornerNodes(), this.getAxisRowNodes(), this.getAxisColNodes());
if (!nodeIds) {
return headerNodes;
}
return headerNodes.filter((node) => nodeIds.includes(node.id));
}
}
exports.PivotChartFacet = PivotChartFacet;
//# sourceMappingURL=pivot-chart-facet.js.map