UNPKG

@antv/s2

Version:

effective spreadsheet render core lib

423 lines 19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ColCell = void 0; const lodash_1 = require("lodash"); const constant_1 = require("../common/constant"); const interface_1 = require("../common/interface"); const engine_1 = require("../engine"); const frame_1 = require("../facet/header/frame"); const cell_1 = require("../utils/cell/cell"); const text_scrolling_1 = require("../utils/cell/text-scrolling"); const g_renders_1 = require("../utils/g-renders"); const hide_columns_1 = require("../utils/hide-columns"); const resize_1 = require("../utils/interaction/resize"); const normalize_1 = require("../utils/normalize"); const header_cell_1 = require("./header-cell"); class ColCell extends header_cell_1.HeaderCell { get cellType() { return constant_1.CellType.COL_CELL; } getBorderPositions() { return [interface_1.CellBorderPosition.TOP, interface_1.CellBorderPosition.RIGHT]; } initCell() { super.initCell(); // 1、draw rect background this.drawBackgroundShape(); // interactive background shape this.drawInteractiveBgShape(); // interactive cell border shape this.drawInteractiveBorderShape(); // draw text this.drawTextOrCustomRenderer(); } afterDrawText() { // 绘制字段标记 -- icon this.drawActionAndConditionIcons(); // draw borders this.drawBorders(); // draw resize ares this.drawResizeArea(); this.addExpandColumnIconShapes(); this.update(); } getFormattedFieldValue() { var _a; const { extra, value, field } = this.meta; const { fields } = this.spreadsheet.dataSet; // 列头对应的数值标题不应该格式化 const isCustomValueFieldNode = (extra === null || extra === void 0 ? void 0 : extra.isCustomNode) && ((_a = fields === null || fields === void 0 ? void 0 : fields.values) === null || _a === void 0 ? void 0 : _a.includes(field)); if (isCustomValueFieldNode) { return { formattedValue: value, value, }; } return super.getFormattedFieldValue(); } getMaxTextWidth() { const { width } = this.getBBoxByType(interface_1.CellClipBox.CONTENT_BOX); return width - this.getActionAndConditionIconWidth(); } isBolderText() { // 非叶子节点、小计总计,均为粗体 const { isLeaf, isTotals } = this.meta; if (isTotals || !isLeaf) { return true; } return false; } /** * 计算文本位置时候需要,留给后代根据情况(固定列)覆盖 * @param viewport * @returns viewport */ handleViewport() { if (this.meta.isFrozen) { return { start: 0, size: Number.POSITIVE_INFINITY, }; } const { viewportWidth, cornerWidth = 0, scrollX = 0, } = this.getHeaderConfig(); const frozenGroupAreas = this.spreadsheet.facet .frozenGroupAreas; const frozenColGroupWidth = frozenGroupAreas[constant_1.FrozenGroupArea.Col].width; const frozenTrailingColGroupWidth = frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol].width; if (this.spreadsheet.isFrozenRowHeader()) { return { start: scrollX + frozenColGroupWidth, size: viewportWidth - frozenColGroupWidth - frozenTrailingColGroupWidth, }; } return { start: frozenColGroupWidth + Math.max(0, scrollX - cornerWidth), size: viewportWidth - frozenColGroupWidth - frozenTrailingColGroupWidth + Math.min(scrollX, cornerWidth), }; } getContentPosition({ contentWidth = this.getActualTextWidth(), } = {}) { var _a, _b, _c; const { isLeaf } = this.meta; const textStyle = this.getTextStyle(); const contentBox = this.getBBoxByType(interface_1.CellClipBox.CONTENT_BOX); const iconStyle = this.getIconStyle(); const textY = (0, cell_1.getVerticalTextPosition)(contentBox, textStyle.textBaseline); const iconY = (0, cell_1.getVerticalIconPosition)(iconStyle.size, textY, textStyle.fontSize, textStyle.textBaseline); if (isLeaf) { const { textX, leftIconX, rightIconX } = (0, cell_1.getHorizontalTextIconPosition)({ bbox: contentBox, textWidth: contentWidth, textAlign: textStyle.textAlign, groupedIcons: this.groupedIcons, iconStyle, isCustomRenderer: !!this.getRenderer(), }); this.leftIconPosition = { x: leftIconX, y: iconY, }; this.rightIconPosition = { x: rightIconX, y: iconY, }; return { x: textX, y: textY }; } const viewport = this.handleViewport(); const { cell, icon } = this.getStyle(); const { textAlign, textBaseline } = this.getTextStyle(); const { textStart, iconStart, iconEnd } = (0, text_scrolling_1.adjustTextIconPositionWhileScrolling)(viewport, { start: contentBox.x, size: contentBox.width }, { align: (0, normalize_1.normalizeTextAlign)(textAlign), size: { textSize: contentWidth, iconStartSize: this.getActionAndConditionIconWidth('left'), iconEndSize: this.getActionAndConditionIconWidth('right'), }, padding: { start: (_a = cell === null || cell === void 0 ? void 0 : cell.padding) === null || _a === void 0 ? void 0 : _a.left, end: (_b = cell === null || cell === void 0 ? void 0 : cell.padding) === null || _b === void 0 ? void 0 : _b.right, betweenTextAndEndIcon: (_c = icon === null || icon === void 0 ? void 0 : icon.margin) === null || _c === void 0 ? void 0 : _c.left, }, }, { isCustomRenderer: !!this.getRenderer(), }); const y = (0, cell_1.getVerticalTextPosition)(contentBox, textBaseline); this.leftIconPosition = { x: iconStart, y: iconY, }; this.rightIconPosition = { x: iconEnd, y: iconY, }; return { x: textStart, y }; } getTextPosition() { return this.getContentPosition(); } getColResizeArea() { return (0, resize_1.getOrCreateResizeAreaGroupById)(this.spreadsheet, constant_1.KEY_GROUP_COL_RESIZE_AREA); } getHorizontalResizeAreaName() { return `${constant_1.HORIZONTAL_RESIZE_AREA_KEY_PRE}${this.meta.field}`; } /** * @description 叶子节点, 但层级不同于其他节点 (如下图 a-1-1), 说明是任意不规则自定义节点, 此时不需要绘制热区 * -------------------------------------------------- * | 自定义节点 a-1 | | * |------------- |-----------| 自定义节点 a-1-1 | * | a-1-1 | a-1-2 | a-1-3 | | * ------------------------------------------------- */ isCrossColumnLeafNode() { var _a; const { colsHierarchy } = this.spreadsheet.facet.getLayoutResult(); const { level, isLeaf } = this.meta; return ((_a = colsHierarchy === null || colsHierarchy === void 0 ? void 0 : colsHierarchy.sampleNodeForLastLevel) === null || _a === void 0 ? void 0 : _a.level) !== level && isLeaf; } drawHorizontalResizeArea() { var _a, _b; // 隐藏列头时不绘制水平热区 https://github.com/antvis/S2/issues/1603 const isHiddenCol = ((_b = (_a = this.spreadsheet.options.style) === null || _a === void 0 ? void 0 : _a.colCell) === null || _b === void 0 ? void 0 : _b.height) === 0; if (isHiddenCol || !this.shouldDrawResizeAreaByType('colCellVertical', this)) { return; } const { y, height } = this.meta; const { position } = this.getHeaderConfig(); const resizeStyle = this.getResizeAreaStyle(); const resizeArea = this.getColResizeArea(); if (!resizeArea || this.isCrossColumnLeafNode()) { return; } const resizeAreaName = this.getHorizontalResizeAreaName(); const existedHorizontalResizeArea = resizeArea === null || resizeArea === void 0 ? void 0 : resizeArea.find((element) => element.name === resizeAreaName); // 如果已经绘制当前列高调整热区热区,则不再绘制 if (existedHorizontalResizeArea) { return; } const offsetY = position.y + y; const resizeAreaWidth = this.getResizeAreaWidth(); // 列高调整热区 const attrs = (0, resize_1.getResizeAreaAttrs)({ theme: resizeStyle, type: constant_1.ResizeDirectionType.Vertical, effect: constant_1.ResizeAreaEffect.Field, offsetX: 0, offsetY, width: resizeAreaWidth, height, meta: this.meta, cell: this, }); resizeArea.appendChild(new engine_1.CustomRect({ name: resizeAreaName, style: Object.assign(Object.assign({}, attrs.style), { x: 0, y: offsetY + height - resizeStyle.size, width: resizeAreaWidth }), }, attrs.appendInfo)); } getResizeAreaWidth() { const { cornerWidth = 0, viewportWidth: headerWidth } = this.getHeaderConfig(); return (frame_1.Frame.getVerticalBorderWidth(this.spreadsheet) + cornerWidth + headerWidth); } shouldAddVerticalResizeArea() { if (this.getMeta().isFrozen) { return true; } const { x, y, width, height } = this.meta; const { scrollX = 0, scrollY, cornerWidth = 0, height: headerHeight, width: headerWidth, } = this.getHeaderConfig(); const resizeStyle = this.getResizeAreaStyle(); const resizeAreaBBox = { x: x + width - resizeStyle.size, y, width: resizeStyle.size, height, }; const frozenGroupAreas = this.spreadsheet.facet .frozenGroupAreas; const colWidth = frozenGroupAreas[constant_1.FrozenGroupArea.Col].width; const trailingColWidth = frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol].width; let resizeClipAreaBBox; if (this.spreadsheet.isFrozenRowHeader()) { resizeClipAreaBBox = { x: colWidth, y: 0, width: headerWidth - colWidth - trailingColWidth, height: headerHeight, }; } else { resizeClipAreaBBox = { x: colWidth - cornerWidth, y: 0, width: headerWidth - colWidth - trailingColWidth + cornerWidth, height: headerHeight, }; } return (0, resize_1.shouldAddResizeArea)(resizeAreaBBox, resizeClipAreaBBox, { scrollX, scrollY, }); } getVerticalResizeAreaOffset() { const { x, y } = this.meta; const { scrollX = 0, position, cornerWidth = 0, viewportWidth, } = this.getHeaderConfig(); const isFrozenRowHeader = this.spreadsheet.isFrozenRowHeader(); const frozenGroupAreas = this.spreadsheet.facet .frozenGroupAreas; const frozenColGroup = frozenGroupAreas[constant_1.FrozenGroupArea.Col]; const frozenTrailingColGroup = frozenGroupAreas[constant_1.FrozenGroupArea.TrailingCol]; let offsetX = position === null || position === void 0 ? void 0 : position.x; if (this.getMeta().isFrozenHead) { offsetX += x - frozenColGroup.x - (isFrozenRowHeader ? 0 : Math.min(scrollX, cornerWidth)); } else if (this.getMeta().isFrozenTrailing) { offsetX += x - frozenTrailingColGroup.x + viewportWidth - frozenTrailingColGroup.width; } else { offsetX += x - scrollX; } return { x: offsetX, y: (position === null || position === void 0 ? void 0 : position.y) + y, }; } drawVerticalResizeArea() { if (!this.meta.isLeaf || this.meta.hideColCellHorizontalResize || !this.shouldDrawResizeAreaByType('colCellHorizontal', this)) { return; } const { width, height } = this.meta; const resizeStyle = this.getResizeAreaStyle(); const resizeArea = this.getColResizeArea(); if (!resizeArea || !this.shouldAddVerticalResizeArea()) { return; } const { x: offsetX, y: offsetY } = this.getVerticalResizeAreaOffset(); /* * 列宽调整热区 * 基准线是根据 container 坐标来的,因此把热区画在 container */ const attrs = (0, resize_1.getResizeAreaAttrs)({ theme: resizeStyle, type: constant_1.ResizeDirectionType.Horizontal, effect: constant_1.ResizeAreaEffect.Cell, offsetX, offsetY, width, height, meta: this.meta, cell: this, }); resizeArea.appendChild(new engine_1.CustomRect({ style: Object.assign(Object.assign({}, attrs.style), { x: offsetX + width - resizeStyle.size, y: offsetY, height }), }, attrs.appendInfo)); } // 绘制热区 drawResizeArea() { this.drawHorizontalResizeArea(); this.drawVerticalResizeArea(); } hasHiddenColumnCell() { const { interaction } = this.spreadsheet.options; const hiddenColumnsDetail = this.spreadsheet.store.get('hiddenColumnsDetail', []); if ((0, lodash_1.isEmpty)(hiddenColumnsDetail) || (0, lodash_1.isEmpty)(interaction === null || interaction === void 0 ? void 0 : interaction.hiddenColumnFields)) { return false; } return !!hiddenColumnsDetail.find((column) => (0, hide_columns_1.isEqualDisplaySiblingNodeId)(column === null || column === void 0 ? void 0 : column.displaySiblingNode, this.meta.id, this.isLastColumn() ? 'prev' : 'next')); } getExpandIconTheme() { const themeCfg = this.getStyle(); return themeCfg.icon; } addExpandColumnSplitLine() { const { x, y, width, height } = this.getBBoxByType(); const { horizontalBorderColor, horizontalBorderColorOpacity } = this.theme.splitLine; const lineX = this.isLastColumn() ? x + width : x; (0, g_renders_1.renderLine)(this, { x1: lineX, y1: y, x2: lineX, y2: y + height, stroke: horizontalBorderColor, lineWidth: constant_1.SPLIT_LINE_WIDTH, strokeOpacity: horizontalBorderColorOpacity, }); } addExpandColumnIconShapes() { if (!this.hasHiddenColumnCell()) { return; } this.addExpandColumnSplitLine(); this.addExpandColumnIcons(); } addExpandColumnIcons() { const isLastColumn = this.isLastColumn(); this.addExpandColumnIcon(isLastColumn); // 如果当前节点的兄弟节点 (前/后) 都被隐藏了, 隐藏后当前节点变为最后一个节点, 需要渲染两个展开按钮, 一个展开[前], 一个展开[后] if (this.isAllDisplaySiblingNodeHidden() && isLastColumn) { this.addExpandColumnIcon(false); } } addExpandColumnIcon(isLastColumn) { const iconConfig = this.getExpandColumnIconConfig(isLastColumn); const icon = (0, g_renders_1.renderIcon)(this, Object.assign(Object.assign({}, iconConfig), { name: 'ExpandColIcon', cursor: 'pointer' })); icon.addEventListener('click', () => { this.spreadsheet.emit(constant_1.S2Event.COL_CELL_EXPANDED, this.meta, isLastColumn ? 'prev' : 'next'); }); icon.addEventListener('mouseenter', (event) => { this.spreadsheet.emit(constant_1.S2Event.COL_CELL_EXPAND_ICON_HOVER, { event, meta: this.meta, hiddenColumns: (0, hide_columns_1.getHiddenColumnContinuousSiblingNodes)(this.spreadsheet, this.meta.id, isLastColumn ? 'prev' : 'next'), }); }); } // 在隐藏的下一个兄弟节点的起始坐标显示隐藏提示线和展开按钮, 如果是尾元素, 则显示在前一个兄弟节点的结束坐标 getExpandColumnIconConfig(isLastColumn) { const { size = 0 } = this.getExpandIconTheme(); const { x, y, width, height } = this.getBBoxByType(); const baseIconX = x - size; const iconX = isLastColumn ? baseIconX + width : baseIconX; const iconY = y + height / 2 - size / 2; return { x: iconX, y: iconY, width: size * 2, height: size, }; } isLastColumn() { return (0, hide_columns_1.isLastColumnAfterHidden)(this.spreadsheet, this.meta.id); } isAllDisplaySiblingNodeHidden() { const { id } = this.meta; const lastHiddenColumnDetail = this.spreadsheet.store.get('hiddenColumnsDetail', []); const isPrevSiblingNodeHidden = lastHiddenColumnDetail.find(({ displaySiblingNode }) => { var _a; return ((_a = displaySiblingNode === null || displaySiblingNode === void 0 ? void 0 : displaySiblingNode.next) === null || _a === void 0 ? void 0 : _a.id) === id; }); const isNextSiblingNodeHidden = lastHiddenColumnDetail.find(({ displaySiblingNode }) => { var _a; return ((_a = displaySiblingNode === null || displaySiblingNode === void 0 ? void 0 : displaySiblingNode.prev) === null || _a === void 0 ? void 0 : _a.id) === id; }); return isNextSiblingNodeHidden && isPrevSiblingNodeHidden; } /** * 以下场景根据当前高度动态计算 maxLines, 保证文本展示合理性 * 1.手动拖拽 2.预设高度 */ getResizedTextMaxLines() { var _a, _b, _c, _d, _e; const { colCell } = this.spreadsheet.options.style; return ((_d = (_b = (_a = colCell === null || colCell === void 0 ? void 0 : colCell.maxLinesByField) === null || _a === void 0 ? void 0 : _a[this.meta.id]) !== null && _b !== void 0 ? _b : (_c = colCell === null || colCell === void 0 ? void 0 : colCell.maxLinesByField) === null || _c === void 0 ? void 0 : _c[this.meta.field]) !== null && _d !== void 0 ? _d : this.getMaxLinesByCustomHeight({ isCustomHeight: (_e = this.meta.extra) === null || _e === void 0 ? void 0 : _e.isCustomHeight, })); } } exports.ColCell = ColCell; //# sourceMappingURL=col-cell.js.map