From f3d55f78983e202220124d90fa72f43187ca5662 Mon Sep 17 00:00:00 2001 From: VicKun Date: Tue, 10 Sep 2024 21:12:54 +0800 Subject: [PATCH] fix(render): fix the issue loop span many times (#3394) --- packages/engine-render/src/basics/tools.ts | 73 +++++++++++++++++++ .../src/components/sheets/sheet-skeleton.ts | 72 +++++++++++++++--- packages/engine-render/src/context.ts | 24 +++++- 3 files changed, 155 insertions(+), 14 deletions(-) diff --git a/packages/engine-render/src/basics/tools.ts b/packages/engine-render/src/basics/tools.ts index d0d740988e2..6a1af279e3f 100644 --- a/packages/engine-render/src/basics/tools.ts +++ b/packages/engine-render/src/basics/tools.ts @@ -18,6 +18,7 @@ import type { IRange, IRangeWithCoord, IScale, + ISelectionCell, ISelectionCellWithMergeInfo, IStyleBase, LocaleService, @@ -522,6 +523,78 @@ export function getCellPositionByIndex( }; } +export function getCellByIndexWithMergeInfo( + row: number, + column: number, + rowHeightAccumulation: number[], + columnWidthAccumulation: number[], + mergeDataInfo: ISelectionCell +) { + // eslint-disable-next-line prefer-const + let { startY, endY, startX, endX } = getCellPositionByIndex( + row, + column, + rowHeightAccumulation, + columnWidthAccumulation + ); + + const { isMerged, isMergedMainCell, startRow, startColumn, endRow, endColumn } = mergeDataInfo; + + let mergeInfo = { + startRow, + startColumn, + endRow, + endColumn, + + startY: 0, + endY: 0, + startX: 0, + endX: 0, + }; + + const rowAccumulationCount = rowHeightAccumulation.length - 1; + + const columnAccumulationCount = columnWidthAccumulation.length - 1; + + if (isMerged && startRow !== -1 && startColumn !== -1) { + const mergeStartY = rowHeightAccumulation[startRow - 1] || 0; + const mergeEndY = rowHeightAccumulation[endRow] || rowHeightAccumulation[rowAccumulationCount]; + + const mergeStartX = columnWidthAccumulation[startColumn - 1] || 0; + const mergeEndX = columnWidthAccumulation[endColumn] || columnWidthAccumulation[columnAccumulationCount]; + mergeInfo = { + ...mergeInfo, + startY: mergeStartY, + endY: mergeEndY, + startX: mergeStartX, + endX: mergeEndX, + }; + } else if (!isMerged && endRow !== -1 && endColumn !== -1) { + const mergeEndY = rowHeightAccumulation[endRow] || rowHeightAccumulation[rowAccumulationCount]; + const mergeEndX = columnWidthAccumulation[endColumn] || columnWidthAccumulation[columnAccumulationCount]; + + mergeInfo = { + ...mergeInfo, + startY, + endY: mergeEndY, + startX, + endX: mergeEndX, + }; + } + + return { + isMerged, + isMergedMainCell, + actualRow: row, + actualColumn: column, + startY, + endY, + startX, + endX, + mergeInfo, + }; +} + export function getCellByIndex( row: number, column: number, diff --git a/packages/engine-render/src/components/sheets/sheet-skeleton.ts b/packages/engine-render/src/components/sheets/sheet-skeleton.ts index 86609b4b8de..dad555c86b6 100644 --- a/packages/engine-render/src/components/sheets/sheet-skeleton.ts +++ b/packages/engine-render/src/components/sheets/sheet-skeleton.ts @@ -23,7 +23,6 @@ import { DEFAULT_STYLES, DocumentDataModel, extractPureTextFromCell, - getCellInfoInMergeData, getColorStyle, HorizontalAlign, IContextService, @@ -52,6 +51,7 @@ import type { IRange, IRowAutoHeightInfo, IRowData, + ISelectionCell, ISelectionCellWithMergeInfo, ISize, IStyleBase, @@ -71,7 +71,7 @@ import { getRotateOffsetAndFarthestHypotenuse } from '../../basics/draw'; import type { IDocumentSkeletonColumn } from '../../basics/i-document-skeleton-cached'; import { degToRad, - getCellByIndex, + getCellByIndexWithMergeInfo, getCellPositionByIndex, getFontStyleString, hasUnMergedCellInRow, @@ -234,6 +234,7 @@ export class SpreadsheetSkeleton extends Skeleton { }; private _dataMergeCache: IRange[] = []; + private _dataMergeCacheMap: Map = new Map(); private _overflowCache: ObjectMatrix = new ObjectMatrix(); private _stylesCache: IStylesCache = { background: {}, @@ -417,6 +418,7 @@ export class SpreadsheetSkeleton extends Skeleton { const { mergeData } = this._worksheetData; this._dataMergeCache = mergeData && this._getMergeCells(mergeData, this._rowColumnSegment); + this._dataMergeCacheMap = mergeData && this._getMergeCellsCache(mergeData); this._calculateStylesCache(); @@ -484,7 +486,7 @@ export class SpreadsheetSkeleton extends Skeleton { for (let i = 0; i < columnCount; i++) { // When calculating the automatic height of a row, if a cell is in a merged cell, // skip the cell directly, which currently follows the logic of Excel - const { isMerged, isMergedMainCell } = getCellInfoInMergeData(rowNum, i, mergeData); + const { isMerged, isMergedMainCell } = this._getCellMergeInfo(rowNum, i, mergeData); if (isMerged || isMergedMainCell) { continue; @@ -957,12 +959,12 @@ export class SpreadsheetSkeleton extends Skeleton { columnHeaderHeightAndMarginTop, } = this; - const primary = getCellByIndex( + const primary = getCellByIndexWithMergeInfo( row, column, rowHeightAccumulation, columnWidthAccumulation, - this._worksheetData.mergeData + this._getCellMergeInfo(row, column, this._worksheetData.mergeData) ); const { isMerged, isMergedMainCell } = primary; let { startY, endY, startX, endX, mergeInfo } = primary; @@ -990,12 +992,12 @@ export class SpreadsheetSkeleton extends Skeleton { getCellByIndexWithNoHeader(row: number, column: number): ISelectionCellWithMergeInfo { const { rowHeightAccumulation, columnWidthAccumulation } = this; - const primary = getCellByIndex( + const primary = getCellByIndexWithMergeInfo( row, column, rowHeightAccumulation, columnWidthAccumulation, - this._worksheetData.mergeData + this._getCellMergeInfo(row, column, this._worksheetData.mergeData) ); const { isMerged, isMergedMainCell } = primary; const { startY, endY, startX, endX, mergeInfo } = primary; @@ -1251,12 +1253,12 @@ export class SpreadsheetSkeleton extends Skeleton { } if (vertexAngle !== 0) { - const { startY, endY, startX, endX } = getCellByIndex( + const { startY, endY, startX, endX } = getCellByIndexWithMergeInfo( row, column, this.rowHeightAccumulation, this.columnWidthAccumulation, - this.mergeData + this._getCellMergeInfo(row, column, this._worksheetData.mergeData) ); const cellWidth = endX - startX; const cellHeight = endY - startY; @@ -1289,12 +1291,12 @@ export class SpreadsheetSkeleton extends Skeleton { return true; } - const { startY, endY } = getCellByIndex( + const { startY, endY } = getCellByIndexWithMergeInfo( row, column, this.rowHeightAccumulation, this.columnWidthAccumulation, - this.mergeData + this._getCellMergeInfo(row, column, this._worksheetData.mergeData) ); const cellHeight = endY - startY; @@ -1695,7 +1697,7 @@ export class SpreadsheetSkeleton extends Skeleton { const hidden = this.worksheet.getColVisible(c) === false || this.worksheet.getRowVisible(r) === false; if (hidden) { - const { isMerged, isMergedMainCell } = getCellInfoInMergeData( + const { isMerged, isMergedMainCell } = this._getCellMergeInfo( r, c, this._dataMergeCache @@ -2099,6 +2101,52 @@ export class SpreadsheetSkeleton extends Skeleton { } as ICellOtherConfig; } + private _getMergeCellsCache(mergeData: IRange[]) { + const map = new Map(); + mergeData.forEach((range) => { + for (let r = range.startRow; r <= range.endRow; r++) { + for (let c = range.startColumn; c <= range.endColumn; c++) { + map.set(`${r}-${c}`, range); + } + } + }); + return map; + } + + private _getCellMergeInfo(row: number, column: number, mergeData: IRange[]): ISelectionCell { + if (!this._dataMergeCacheMap) { + this._dataMergeCacheMap = this._getMergeCellsCache(mergeData); + } + const key = `${row}-${column}`; + const mergeRange = this._dataMergeCacheMap.get(key); + + let isMerged = false; // The upper left cell only renders the content + let isMergedMainCell = false; + let newEndRow = row; + let newEndColumn = column; + let mergeRow = row; + let mergeColumn = column; + if (mergeRange) { + isMerged = true; + isMergedMainCell = mergeRange.startRow === row && mergeRange.startColumn === column; + newEndRow = mergeRange.endRow; + newEndColumn = mergeRange.endColumn; + mergeRow = mergeRange.startRow; + mergeColumn = mergeRange.startColumn; + } + + return { + actualRow: row, + actualColumn: column, + isMergedMainCell, + isMerged, + endRow: newEndRow, + endColumn: newEndColumn, + startRow: mergeRow, + startColumn: mergeColumn, + }; + } + /** * Cache the merged cells on the current screen to improve computational performance. * @param mergeData all marge data diff --git a/packages/engine-render/src/context.ts b/packages/engine-render/src/context.ts index a6c7824d311..62acbf617fa 100644 --- a/packages/engine-render/src/context.ts +++ b/packages/engine-render/src/context.ts @@ -20,6 +20,8 @@ import { fixLineWidthByScale, getColor } from './basics/tools'; export class UniverRenderingContext2D implements CanvasRenderingContext2D { __mode = 'rendering'; + private _system: string; + private _browser: string; readonly canvas: HTMLCanvasElement; _context: CanvasRenderingContext2D; @@ -484,13 +486,31 @@ export class UniverRenderingContext2D implements CanvasRenderingContext2D { this._context.closePath(); } + getSystem() { + if (this._system) { + return this._system; + } else { + this._system = Tools.getSystemType(); + } + return this._system; + } + + getBrowser() { + if (this._browser) { + return this._browser; + } else { + this._browser = Tools.getBrowserType(); + } + return this._browser; + } + /** * Chrome hardware acceleration causes canvas stroke to fail to draw lines on Mac. */ closePathByEnv() { - const system = Tools.getSystemType(); + const system = this.getSystem(); const isMac = system === 'Mac'; - const browser = Tools.getBrowserType(); + const browser = this.getBrowser(); const isChrome = browser === 'Chrome'; if (isMac && isChrome) {