@antv/s2
Version:
effective spreadsheet render core lib
508 lines • 24.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FrozenFacet = void 0;
const g_1 = require("@antv/g");
const lodash_1 = require("lodash");
const constant_1 = require("../common/constant");
const frozen_group_1 = require("../group/frozen-group");
const utils_1 = require("../utils");
const grid_1 = require("../utils/grid");
const math_1 = require("../utils/math");
const base_facet_1 = require("./base-facet");
const util_1 = require("./header/util");
const utils_2 = require("./utils");
/**
* Defines the row freeze abstract standard interface
*/
class FrozenFacet extends base_facet_1.BaseFacet {
constructor() {
super(...arguments);
this.frozenGroupAreas = {
[constant_1.FrozenGroupArea.Col]: {
width: 0,
x: 0,
range: [],
},
[constant_1.FrozenGroupArea.TrailingCol]: {
width: 0,
x: 0,
range: [],
},
[constant_1.FrozenGroupArea.Row]: {
height: 0,
y: 0,
range: [],
},
[constant_1.FrozenGroupArea.TrailingRow]: {
height: 0,
y: 0,
range: [],
},
};
this.panelScrollGroupIndexes = [0, 0, 0, 0];
this.addDataCell = (cell) => {
const colLeafLength = this.getColLeafNodes().length;
const cellRange = this.getCellRange();
const frozenGroupType = (0, utils_2.getFrozenGroupTypeByCell)(cell.getMeta(), this.getFrozenOptions(), colLeafLength, cellRange);
if (frozenGroupType === constant_1.FrozenGroupType.Scroll) {
this.panelScrollGroup.appendChild(cell);
}
else {
this.frozenGroups[frozenGroupType].appendChild(cell);
}
(0, utils_1.waitForCellMounted)(() => {
this.spreadsheet.emit(constant_1.S2Event.DATA_CELL_RENDER, cell);
this.spreadsheet.emit(constant_1.S2Event.LAYOUT_CELL_RENDER, cell);
});
};
this.addFrozenCell = (colIndex, rowIndex, group) => {
const viewMeta = this.getCellMeta(rowIndex, colIndex);
if (viewMeta) {
viewMeta['isFrozenCorner'] = true;
const cell = this.createDataCell(viewMeta);
group.appendChild(cell);
}
};
this.translateFrozenGroups = () => {
const { scrollY, scrollX } = this.getScrollOffset();
const paginationScrollY = this.getPaginationScrollY();
const { x, y, viewportWidth, viewportHeight } = this.panelBBox;
const colOffset = (0, util_1.getFrozenColOffset)(this, this.cornerBBox.width, scrollX);
const trailingColOffset = (0, util_1.getFrozenTrailingColOffset)(this, viewportWidth);
const trailingRowOffset = (0, util_1.getFrozenTrailingRowOffset)(this, viewportHeight, paginationScrollY);
(0, utils_2.translateGroup)(this.frozenGroups[constant_1.FrozenGroupType.TopLeft], x - colOffset, y - paginationScrollY);
(0, utils_2.translateGroup)(this.frozenGroups[constant_1.FrozenGroupType.TopRight], x - trailingColOffset, y - paginationScrollY);
(0, utils_2.translateGroup)(this.frozenGroups[constant_1.FrozenGroupType.BottomLeft], x - colOffset, y - trailingRowOffset);
(0, utils_2.translateGroup)(this.frozenGroups[constant_1.FrozenGroupType.BottomRight], x - trailingColOffset, y - trailingRowOffset);
(0, utils_2.translateGroup)(this.frozenGroups[constant_1.FrozenGroupType.Row], x - scrollX, y - paginationScrollY);
(0, utils_2.translateGroup)(this.frozenGroups[constant_1.FrozenGroupType.TrailingRow], x - scrollX, y - trailingRowOffset);
(0, utils_2.translateGroup)(this.frozenGroups[constant_1.FrozenGroupType.Col], x - colOffset, y - scrollY - paginationScrollY);
(0, utils_2.translateGroup)(this.frozenGroups[constant_1.FrozenGroupType.TrailingCol], x - trailingColOffset, y - scrollY - paginationScrollY);
};
// eslint-disable-next-line max-lines-per-function
this.renderFrozenGroupSplitLine = (scrollX, scrollY) => {
var _a;
// 在分页条件下需要额外处理 Y 轴滚动值
const relativeScrollY = Math.floor(scrollY - this.getPaginationScrollY());
// remove previous split line group
(_a = this.foregroundGroup.getElementById(constant_1.KEY_GROUP_FROZEN_SPLIT_LINE)) === null || _a === void 0 ? void 0 : _a.remove();
const { splitLine } = this.spreadsheet.theme;
const splitLineGroup = this.foregroundGroup.appendChild(new g_1.Group({
id: constant_1.KEY_GROUP_FROZEN_SPLIT_LINE,
style: {
zIndex: constant_1.FRONT_GROUND_GROUP_FROZEN_Z_INDEX,
},
}));
const verticalBorderStyle = {
lineWidth: constant_1.SPLIT_LINE_WIDTH,
stroke: splitLine === null || splitLine === void 0 ? void 0 : splitLine.verticalBorderColor,
opacity: splitLine === null || splitLine === void 0 ? void 0 : splitLine.verticalBorderColorOpacity,
};
const horizontalBorderStyle = {
lineWidth: constant_1.SPLIT_LINE_WIDTH,
stroke: splitLine === null || splitLine === void 0 ? void 0 : splitLine.horizontalBorderColor,
opacity: splitLine === null || splitLine === void 0 ? void 0 : splitLine.horizontalBorderColorOpacity,
};
this.renderFrozenColSplitLine(splitLineGroup, splitLine, verticalBorderStyle, scrollX);
this.renderFrozenTrailingColSplitLine(splitLineGroup, splitLine, verticalBorderStyle, scrollX);
this.renderFrozenRowSplitLine(splitLineGroup, splitLine, horizontalBorderStyle, relativeScrollY);
this.renderFrozenTrailingRowSplitLine(splitLineGroup, splitLine, horizontalBorderStyle, relativeScrollY);
};
this.renderFrozenPanelCornerGroup = () => {
const cellRange = this.getCellRange();
const result = (0, utils_2.calculateFrozenCornerCells)(this.getFrozenOptions(), this.getColLeafNodes().length, cellRange);
Object.keys(result || {}).forEach((key) => {
const cells = result[key];
const group = this.frozenGroups[key];
if (group) {
cells.forEach((cell) => {
this.addFrozenCell(cell.x, cell.y, group);
});
}
});
};
this.getTotalHeightForRange = (start, end) => {
if (start < 0 || end < 0) {
return 0;
}
if (this.rowOffsets) {
return this.rowOffsets[end + 1] - this.rowOffsets[start];
}
let totalHeight = 0;
for (let index = start; index < end + 1; index++) {
const height = this.getDefaultCellHeight();
totalHeight += height;
}
return totalHeight;
};
this.getShadowFill = (angle) => {
var _a, _b;
const { splitLine } = this.spreadsheet.theme;
return `l (${angle}) 0:${(_a = splitLine === null || splitLine === void 0 ? void 0 : splitLine.shadowColors) === null || _a === void 0 ? void 0 : _a.left} 1:${(_b = splitLine === null || splitLine === void 0 ? void 0 : splitLine.shadowColors) === null || _b === void 0 ? void 0 : _b.right}`;
};
}
initPanelGroups() {
super.initPanelGroups();
/* init frozen groups */
this.frozenGroups = [
constant_1.FrozenGroupType.Row,
constant_1.FrozenGroupType.Col,
constant_1.FrozenGroupType.TrailingRow,
constant_1.FrozenGroupType.TrailingCol,
constant_1.FrozenGroupType.TopLeft,
constant_1.FrozenGroupType.TopRight,
constant_1.FrozenGroupType.BottomLeft,
constant_1.FrozenGroupType.BottomRight,
].reduce((acc, name) => {
const frozenGroup = new frozen_group_1.FrozenGroup({
name,
zIndex: constant_1.PANEL_GROUP_FROZEN_GROUP_Z_INDEX,
s2: this.spreadsheet,
});
this.panelGroup.appendChild(frozenGroup);
acc[name] = frozenGroup;
return acc;
}, {});
}
/**
* 获取冻结数量结果,主要是针对 col top level 的结果
*/
getFrozenOptions() {
if (!this.validFrozenOptions) {
const colLength = this.getColLeafNodes().length;
const cellRange = this.getCellRange();
this.validFrozenOptions = (0, utils_1.getValidFrozenOptions)(this.spreadsheet.options.frozen, colLength, cellRange.end - cellRange.start + 1);
}
return this.validFrozenOptions;
}
calculateFrozenGroupInfo() {
const { colCount, rowCount, trailingColCount, trailingRowCount } = this.getFrozenOptions();
const viewCellHeights = this.viewCellHeights;
const cellRange = this.getCellRange();
const leafColNodes = this.getColLeafNodes();
if (colCount > 0) {
this.frozenGroupAreas[constant_1.FrozenGroupArea.Col].width =
leafColNodes[colCount - 1].x + leafColNodes[colCount - 1].width;
this.frozenGroupAreas[constant_1.FrozenGroupArea.Col].x = 0;
this.frozenGroupAreas[constant_1.FrozenGroupArea.Col].range = [0, colCount - 1];
}
if (rowCount > 0) {
this.frozenGroupAreas[constant_1.FrozenGroupArea.Row].height =
viewCellHeights.getCellOffsetY(cellRange.start + rowCount) -
viewCellHeights.getCellOffsetY(cellRange.start);
this.frozenGroupAreas[constant_1.FrozenGroupArea.Row].y =
viewCellHeights.getCellOffsetY(cellRange.start);
this.frozenGroupAreas[constant_1.FrozenGroupArea.Row].range = [
cellRange.start,
cellRange.start + rowCount - 1,
];
}
if (trailingColCount > 0) {
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol].width =
leafColNodes[leafColNodes.length - 1].x -
leafColNodes[leafColNodes.length - trailingColCount].x +
leafColNodes[leafColNodes.length - 1].width;
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol].x =
leafColNodes[leafColNodes.length - trailingColCount].x;
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol].range = [
leafColNodes.length - trailingColCount,
leafColNodes.length - 1,
];
}
if (trailingRowCount > 0) {
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingRow].height =
viewCellHeights.getCellOffsetY(cellRange.end + 1) -
viewCellHeights.getCellOffsetY(cellRange.end + 1 - trailingRowCount);
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingRow].y =
viewCellHeights.getCellOffsetY(cellRange.end + 1 - trailingRowCount);
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingRow].range = [
cellRange.end - trailingRowCount + 1,
cellRange.end,
];
}
}
getFinalViewport() {
const { viewportHeight: height, viewportWidth: width } = this.panelBBox;
const { colCount, rowCount, trailingColCount, trailingRowCount } = this.getFrozenOptions();
const finalViewport = {
width,
height,
x: 0,
y: 0,
};
if (colCount > 0 || trailingColCount > 0) {
finalViewport.width -=
this.frozenGroupAreas[constant_1.FrozenGroupArea.Col].width +
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol].width;
finalViewport.x += this.frozenGroupAreas[constant_1.FrozenGroupArea.Col].width;
}
if (rowCount > 0 || trailingRowCount > 0) {
// canvas 高度小于 row height 和 trailingRow height 的时候 height 为 0
if (finalViewport.height <
this.frozenGroupAreas[constant_1.FrozenGroupArea.Row].height +
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingRow].height) {
finalViewport.height = 0;
finalViewport.y = 0;
}
else {
finalViewport.height -=
this.frozenGroupAreas[constant_1.FrozenGroupArea.Row].height +
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingRow].height;
finalViewport.y += this.frozenGroupAreas[constant_1.FrozenGroupArea.Row].height;
}
}
return finalViewport;
}
calculateXYIndexes(scrollX, scrollY) {
var _a, _b;
const finalViewport = this.getFinalViewport();
const indexes = this.spreadsheet.isTableMode() && ((_b = (_a = this.spreadsheet.dataSet) === null || _a === void 0 ? void 0 : _a.isEmpty) === null || _b === void 0 ? void 0 : _b.call(_a))
? this.spreadsheet.dataSet.getEmptyViewIndexes()
: (0, utils_2.calculateInViewIndexes)({
scrollX,
scrollY,
widths: this.viewCellWidths,
heights: this.viewCellHeights,
viewport: finalViewport,
rowRemainWidth: this.getRealScrollX(this.cornerBBox.width),
});
this.panelScrollGroupIndexes = indexes;
const colLength = this.getColLeafNodes().length;
const cellRange = this.getCellRange();
return (0, utils_2.splitInViewIndexesWithFrozen)(indexes, this.getFrozenOptions(), colLength, cellRange);
}
updateFrozenGroupGrid() {
[
constant_1.FrozenGroupArea.Col,
constant_1.FrozenGroupArea.Row,
constant_1.FrozenGroupArea.TrailingCol,
constant_1.FrozenGroupArea.TrailingRow,
].forEach((key) => {
if (!this.frozenGroupAreas[key].range) {
return;
}
let cols = [];
let rows = [];
if (key.toLowerCase().includes('row')) {
const [rowMin, rowMax] = this.frozenGroupAreas[key].range || [];
cols = this.gridInfo.cols;
rows = (0, grid_1.getRowsForGrid)(rowMin, rowMax, this.viewCellHeights);
if (key === constant_1.FrozenGroupArea.TrailingRow) {
const top = this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingRow].y;
rows = (0, grid_1.getFrozenRowsForGrid)(rowMin, rowMax, top, this.viewCellHeights);
}
}
else {
const [colMin, colMax] = this.frozenGroupAreas[key].range || [];
const nodes = this.getColLeafNodes();
cols = (0, grid_1.getColsForGrid)(colMin, colMax, nodes);
rows = this.gridInfo.rows;
}
const frozenGroup = constant_1.FrozenGroupAreaTypeMap[key];
this.frozenGroups[frozenGroup].updateGrid({
cols,
rows,
}, frozenGroup);
});
}
updatePanelScrollGroup() {
super.updatePanelScrollGroup();
this.updateFrozenGroupGrid();
}
translateRelatedGroups(scrollX, scrollY, hRowScroll) {
super.translateRelatedGroups(scrollX, scrollY, hRowScroll);
this.translateFrozenGroups();
this.renderRowResizeArea();
this.renderFrozenGroupSplitLine(scrollX, scrollY);
}
renderRowResizeArea() { }
getFrozenColSplitLineSize() {
const { viewportHeight, y: panelBBoxStartY } = this.panelBBox;
const height = viewportHeight + panelBBoxStartY;
return {
y: 0,
height,
};
}
renderFrozenColSplitLine(splitLineGroup, splitLine, verticalBorderStyle, scrollX) {
const { colCount } = this.getFrozenOptions();
const { x: panelBBoxStartX } = this.panelBBox;
if (colCount > 0) {
const cornerWidth = this.cornerBBox.width;
const colOffset = (0, util_1.getFrozenColOffset)(this, cornerWidth, scrollX);
const x = panelBBoxStartX +
this.frozenGroupAreas[constant_1.FrozenGroupArea.Col].width -
colOffset;
const { y, height } = this.getFrozenColSplitLineSize();
(0, utils_1.renderLine)(splitLineGroup, Object.assign(Object.assign({}, verticalBorderStyle), { x1: x, x2: x, y1: y, y2: y + height }));
if ((splitLine === null || splitLine === void 0 ? void 0 : splitLine.showShadow) &&
scrollX > 0 &&
(this.spreadsheet.isFrozenRowHeader() || colOffset >= cornerWidth)) {
splitLineGroup.appendChild(new g_1.Rect({
style: {
x,
y,
width: splitLine === null || splitLine === void 0 ? void 0 : splitLine.shadowWidth,
height,
fill: this.getShadowFill(0),
},
}));
}
}
}
renderFrozenTrailingColSplitLine(splitLineGroup, splitLine, verticalBorderStyle, scrollX) {
const { trailingColCount } = this.getFrozenOptions();
const { viewportWidth, x: panelBBoxStartX } = this.panelBBox;
if (trailingColCount > 0) {
const x = viewportWidth -
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol].width +
panelBBoxStartX;
const { y, height } = this.getFrozenColSplitLineSize();
const maxScrollX = Math.max(0, (0, lodash_1.last)(this.viewCellWidths) - viewportWidth);
(0, utils_1.renderLine)(splitLineGroup, Object.assign(Object.assign({}, verticalBorderStyle), { x1: x, x2: x, y1: y, y2: y + height }));
if ((splitLine === null || splitLine === void 0 ? void 0 : splitLine.showShadow) && (0, math_1.floor)(scrollX) < (0, math_1.floor)(maxScrollX)) {
splitLineGroup.appendChild(new g_1.Rect({
style: {
x: x - splitLine.shadowWidth,
y,
width: splitLine.shadowWidth,
height,
fill: this.getShadowFill(180),
},
}));
}
}
}
getFrozenRowSplitLineSize() {
const { viewportWidth, x: panelBBoxStartX } = this.panelBBox;
const width = panelBBoxStartX + viewportWidth;
return {
x: 0,
width,
};
}
renderFrozenRowSplitLine(splitLineGroup, splitLine, horizontalBorderStyle, scrollY) {
const { rowCount } = this.getFrozenOptions();
const { y: panelBBoxStartY } = this.panelBBox;
if (rowCount > 0) {
const y = panelBBoxStartY + this.frozenGroupAreas[constant_1.FrozenGroupArea.Row].height;
const { x, width } = this.getFrozenRowSplitLineSize();
(0, utils_1.renderLine)(splitLineGroup, Object.assign(Object.assign({}, horizontalBorderStyle), { x1: x, x2: x + width, y1: y, y2: y }));
if ((splitLine === null || splitLine === void 0 ? void 0 : splitLine.showShadow) && scrollY > 0) {
splitLineGroup.appendChild(new g_1.Rect({
style: {
x,
y,
width,
height: splitLine === null || splitLine === void 0 ? void 0 : splitLine.shadowWidth,
fill: this.getShadowFill(90),
},
}));
}
}
}
renderFrozenTrailingRowSplitLine(splitLineGroup, splitLine, horizontalBorderStyle, scrollY) {
const { trailingRowCount } = this.getFrozenOptions();
const { viewportHeight } = this.panelBBox;
if (trailingRowCount > 0) {
const y = this.panelBBox.maxY -
this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingRow].height;
const { x, width } = this.getFrozenRowSplitLineSize();
const cellRange = this.getCellRange();
// scroll boundary
const maxScrollY = Math.max(0, this.viewCellHeights.getCellOffsetY(cellRange.end + 1) -
this.viewCellHeights.getCellOffsetY(cellRange.start) -
viewportHeight);
(0, utils_1.renderLine)(splitLineGroup, Object.assign(Object.assign({}, horizontalBorderStyle), { x1: x, x2: x + width, y1: y, y2: y }));
if ((splitLine === null || splitLine === void 0 ? void 0 : splitLine.showShadow) && scrollY < (0, math_1.floor)(maxScrollY)) {
splitLineGroup.appendChild(new g_1.Rect({
style: {
x,
y: y - splitLine.shadowWidth,
width,
height: splitLine.shadowWidth,
fill: this.getShadowFill(270),
},
}));
}
}
}
render() {
if (!this.shouldRender()) {
return;
}
this.calculateFrozenGroupInfo();
this.renderFrozenPanelCornerGroup();
super.render();
}
getCenterFrameScrollX(scrollX) {
if (this.getFrozenOptions().colCount > 0) {
return (0, util_1.getFrozenColOffset)(this, this.cornerBBox.width, scrollX);
}
return super.getCenterFrameScrollX(scrollX);
}
getDefaultCellHeight() {
var _a;
return (_a = this.getRowCellHeight(null)) !== null && _a !== void 0 ? _a : 0;
}
clip() {
const { scrollX } = this.getScrollOffset();
const { x: panelScrollGroupClipX, width: panelScrollGroupClipWidth } = (0, util_1.getScrollGroupClip)(this, this.panelBBox);
const frozenColGroupWidth = this.frozenGroupAreas[constant_1.FrozenGroupArea.Col].width;
const frozenTrailingColWidth = this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol].width;
const frozenRowGroupHeight = this.frozenGroupAreas[constant_1.FrozenGroupArea.Row].height;
const frozenTrailingRowHeight = this.frozenGroupAreas[constant_1.FrozenGroupArea.TrailingRow].height;
const panelScrollGroupClipY = this.panelBBox.y + frozenRowGroupHeight;
const panelScrollGroupClipHeight = this.panelBBox.viewportHeight -
frozenRowGroupHeight -
frozenTrailingRowHeight;
this.panelScrollGroup.style.clipPath = new g_1.Rect({
style: {
x: panelScrollGroupClipX,
y: panelScrollGroupClipY,
width: panelScrollGroupClipWidth,
height: panelScrollGroupClipHeight,
},
});
/* frozen groups clip */
this.frozenGroups[constant_1.FrozenGroupType.Col].style.clipPath = new g_1.Rect({
style: {
x: this.panelBBox.x -
(0, util_1.getFrozenColOffset)(this, this.cornerBBox.width, scrollX),
y: panelScrollGroupClipY,
width: frozenColGroupWidth,
height: panelScrollGroupClipHeight,
},
});
this.frozenGroups[constant_1.FrozenGroupType.TrailingCol].style.clipPath = new g_1.Rect({
style: {
x: this.panelBBox.x +
this.panelBBox.viewportWidth -
frozenTrailingColWidth,
y: panelScrollGroupClipY,
width: frozenTrailingColWidth,
height: panelScrollGroupClipHeight,
},
});
this.frozenGroups[constant_1.FrozenGroupType.Row].style.clipPath = new g_1.Rect({
style: {
x: panelScrollGroupClipX,
y: this.panelBBox.y,
width: panelScrollGroupClipWidth,
height: frozenRowGroupHeight,
},
});
this.frozenGroups[constant_1.FrozenGroupType.TrailingRow].style.clipPath = new g_1.Rect({
style: {
x: panelScrollGroupClipX,
y: this.panelBBox.y +
this.panelBBox.viewportHeight -
frozenTrailingRowHeight,
width: panelScrollGroupClipWidth,
height: frozenTrailingRowHeight,
},
});
}
}
exports.FrozenFacet = FrozenFacet;
//# sourceMappingURL=frozen-facet.js.map