diff --git a/packages/core/src/sheets/row-manager.ts b/packages/core/src/sheets/row-manager.ts index 79840789761..ca01ca20539 100644 --- a/packages/core/src/sheets/row-manager.ts +++ b/packages/core/src/sheets/row-manager.ts @@ -15,9 +15,9 @@ */ import { getArrayLength, type IObjectArrayPrimitiveType } from '../shared/object-matrix'; -import type { Nullable } from '../shared/types'; import { BooleanNumber } from '../types/enum'; import { type IRange, type IRowData, type IWorksheetData, RANGE_TYPE } from './typedef'; +import type { Nullable } from '../shared/types'; import type { SheetViewModel } from './view-model'; /** @@ -76,7 +76,7 @@ export class RowManager { /** * Get row data of given row * @param rowPos row index - * @returns + * @returns {Nullable>} rowData */ getRow(rowPos: number): Nullable> { return this._rowData[rowPos]; diff --git a/packages/core/src/sheets/view-model.ts b/packages/core/src/sheets/view-model.ts index 93cf5c571c3..f7596d8b8a6 100644 --- a/packages/core/src/sheets/view-model.ts +++ b/packages/core/src/sheets/view-model.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import type { IDisposable } from '../common/di'; - import { Disposable, toDisposable } from '../shared/lifecycle'; + +import type { IDisposable } from '../common/di'; import type { Nullable } from '../shared/types'; import type { ICellData, ICellDataForSheetInterceptor } from './typedef'; diff --git a/packages/core/src/sheets/worksheet.ts b/packages/core/src/sheets/worksheet.ts index 7753bb5cccd..4f9d695759b 100644 --- a/packages/core/src/sheets/worksheet.ts +++ b/packages/core/src/sheets/worksheet.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import type { IObjectMatrixPrimitiveType, Nullable } from '../shared'; import { ObjectMatrix, Rectangle, Tools } from '../shared'; import { createRowColIter } from '../shared/row-col-iter'; import { type BooleanNumber, CellValueType } from '../types/enum'; @@ -22,9 +21,10 @@ import { ColumnManager } from './column-manager'; import { Range } from './range'; import { RowManager } from './row-manager'; import { mergeWorksheetSnapshotWithDefault } from './sheet-snapshot-utils'; +import { SheetViewModel } from './view-model'; +import type { IObjectMatrixPrimitiveType, Nullable } from '../shared'; import type { Styles } from './styles'; import type { ICellData, ICellDataForSheetInterceptor, IFreeze, IRange, IWorksheetData } from './typedef'; -import { SheetViewModel } from './view-model'; /** * The model of a Worksheet. @@ -463,19 +463,25 @@ export class Worksheet { } /** - * Get if the row in visible. It may be affected by features like filter and view. + * Row is filtered out, that means this row is invisible. + * @param row + * @returns {boolean} is row hidden by filter + */ + isRowFiltered(row: number): boolean { + return this._viewModel.getRowFiltered(row); + } + + /** + * Get if the row is visible. It may be affected by features like filter and view. * @param row the row index - * @returns if the row in visible to the user + * @returns {boolean} if the row in visible to the user */ getRowVisible(row: number): boolean { - const filtered = this._viewModel.getRowFiltered(row); - if (filtered) return false; - - return this.getRowRawVisible(row); + return !this.isRowFiltered(row) && this.getRowRawVisible(row); } /** - * Get if the row does not have `hidden` property. + * Get if the row does not have `hidden` property. This value won't affected by features like filter and view. * @param row the row index * @returns if the row does not have `hidden` property */ @@ -504,7 +510,7 @@ export class Worksheet { } /** - * Get all visible rows in the sheet. + * Get all visible rows in the sheet.(not include filter & view, like getRawVisibleRows) * @returns Visible rows range list */ getVisibleRows(): IRange[] { @@ -513,7 +519,7 @@ export class Worksheet { } /** - * Get all visible columns in the sheet. + * Get all visible columns in the sheet.(not include filter & view) * @returns Visible columns range list */ getVisibleCols(): IRange[] { diff --git a/packages/engine-render/src/basics/tools.ts b/packages/engine-render/src/basics/tools.ts index 6a1af279e3f..2cf9af11d37 100644 --- a/packages/engine-render/src/basics/tools.ts +++ b/packages/engine-render/src/basics/tools.ts @@ -830,7 +830,8 @@ export function expandRangeIfIntersects(mainRanges: IRange[], ranges: IRange[]) } } } - return [...mainRanges, ...intersects]; + // return [...mainRanges, ...intersects]; + return mainRanges.concat(intersects); // concat is slightly faster than spread } export function clampRanges(range: IRange) { diff --git a/packages/engine-render/src/components/sheets/extensions/border.ts b/packages/engine-render/src/components/sheets/extensions/border.ts index 7f0feec58e4..f844583b6e4 100644 --- a/packages/engine-render/src/components/sheets/extensions/border.ts +++ b/packages/engine-render/src/components/sheets/extensions/border.ts @@ -67,7 +67,7 @@ export class Border extends SheetExtension { return true; } - const cellInfo = this.getCellIndex( + const cellInfo = this.getCellByIndex( rowIndex, columnIndex, rowHeightAccumulation, diff --git a/packages/engine-render/src/components/sheets/extensions/custom.ts b/packages/engine-render/src/components/sheets/extensions/custom.ts index 1fde914d0cb..62c8c449c37 100644 --- a/packages/engine-render/src/components/sheets/extensions/custom.ts +++ b/packages/engine-render/src/components/sheets/extensions/custom.ts @@ -44,12 +44,15 @@ export class Custom extends SheetExtension { const subUnitId = worksheet.getSheetId(); Range.foreach(rowColumnSegment, (row, col) => { + if (!worksheet.getRowVisible(row) || !worksheet.getColVisible(col)) { + return; + } let cellData = worksheet.getCell(row, col); if (!cellData?.customRender) { return; } - let primaryWithCoord = this.getCellIndex(row, col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + let primaryWithCoord = this.getCellByIndex(row, col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); const { mergeInfo } = primaryWithCoord; if (!this.isRenderDiffRangesByRow(mergeInfo.startRow, mergeInfo.endRow, diffRanges)) { @@ -75,7 +78,7 @@ export class Custom extends SheetExtension { return; } - primaryWithCoord = this.getCellIndex(mainCell.row, mainCell.col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + primaryWithCoord = this.getCellByIndex(mainCell.row, mainCell.col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); } const renderInfo = { @@ -89,11 +92,6 @@ export class Custom extends SheetExtension { unitId: worksheet.unitId, }; - // current cell is hidden - if (!worksheet.getColVisible(col) || !worksheet.getRowVisible(row)) { - return; - } - const customRender = cellData.customRender.sort(sortRules); ctx.save(); diff --git a/packages/engine-render/src/components/sheets/extensions/font.ts b/packages/engine-render/src/components/sheets/extensions/font.ts index cbbf7012012..001925b5460 100644 --- a/packages/engine-render/src/components/sheets/extensions/font.ts +++ b/packages/engine-render/src/components/sheets/extensions/font.ts @@ -60,10 +60,14 @@ export class Font extends SheetExtension { diffRanges: IRange[], moreBoundsInfo: IDrawInfo ) { - const { stylesCache, dataMergeCache, overflowCache, worksheet, rowHeightAccumulation, columnTotalWidth, columnWidthAccumulation, rowTotalHeight } = spreadsheetSkeleton; + const { stylesCache, dataMergeCache, overflowCache, worksheet } = spreadsheetSkeleton; const { font: fontList } = stylesCache; - if (!worksheet || !fontList) return; + if (!spreadsheetSkeleton || !worksheet || !fontList) { + return; + } + const { rowHeightAccumulation, columnTotalWidth, columnWidthAccumulation, rowTotalHeight } = + spreadsheetSkeleton; if ( !rowHeightAccumulation || !columnWidthAccumulation || @@ -100,7 +104,7 @@ export class Font extends SheetExtension { return true; } } - const cellInfo = this.getCellIndex( + const cellInfo = this.getCellByIndex( rowIndex, columnIndex, rowHeightAccumulation, @@ -296,6 +300,7 @@ export class Font extends SheetExtension { const cellHeight = endY - startY; const cellWidth = endX - startX; + // WRAP means next line if (wrapStrategy === WrapStrategy.WRAP && vertexAngle === 0) { documentSkeleton.getViewModel().getDataModel().updateDocumentDataPageSize(cellWidth); documentSkeleton.calculate(); @@ -306,7 +311,9 @@ export class Font extends SheetExtension { // Use fix https://github.com/dream-num/univer/issues/927, Set the actual width of the content to the page width of the document, // so that the divide will be aligned when the skeleton is calculated. const overflowRectangle = overflowCache.getValue(row, column); - if (!(wrapStrategy === WrapStrategy.WRAP && !overflowRectangle && vertexAngle === 0)) { + + const isOverflow = !(wrapStrategy === WrapStrategy.WRAP && !overflowRectangle && vertexAngle === 0); + if (isOverflow) { const contentSize = getDocsSkeletonPageSize(documentSkeleton); const documentStyle = documentSkeleton.getViewModel().getDataModel().getSnapshot().documentStyle; diff --git a/packages/engine-render/src/components/sheets/extensions/marker.ts b/packages/engine-render/src/components/sheets/extensions/marker.ts index 9bcc72db16b..901aff2c622 100644 --- a/packages/engine-render/src/components/sheets/extensions/marker.ts +++ b/packages/engine-render/src/components/sheets/extensions/marker.ts @@ -50,8 +50,12 @@ export class Marker extends SheetExtension { // eslint-disable-next-line max-lines-per-function Range.foreach(rowColumnSegment, (row, col) => { + if (!worksheet.getRowVisible(row) || !worksheet.getColVisible(col)) { + return; + } + let cellData = worksheet.getCell(row, col); - const cellInfo = this.getCellIndex( + const cellInfo = this.getCellByIndex( row, col, skeleton.rowHeightAccumulation, @@ -90,11 +94,6 @@ export class Marker extends SheetExtension { mergeCellRendered.add(rangeStr); } - // current cell is hidden - if (!worksheet.getColVisible(col) || !worksheet.getRowVisible(row)) { - return; - } - if (!cellData) { return; } diff --git a/packages/engine-render/src/components/sheets/extensions/sheet-extension.ts b/packages/engine-render/src/components/sheets/extensions/sheet-extension.ts index a2d3802d8b6..71c3dac3638 100644 --- a/packages/engine-render/src/components/sheets/extensions/sheet-extension.ts +++ b/packages/engine-render/src/components/sheets/extensions/sheet-extension.ts @@ -40,9 +40,9 @@ export class SheetExtension extends ComponentExtension; fontString: string; @@ -224,9 +219,9 @@ export class SpreadsheetSkeleton extends Skeleton { private _columnHeaderHeight = 0; /** - * skeletonData(row col range) of visible area + * Range of visible area(range in viewBounds) */ - private _rowColumnSegment: IRowColumnSegment = { + private _rowColumnSegment: IRowColumnRange = { startRow: -1, endRow: -1, startColumn: -1, @@ -244,7 +239,7 @@ export class SpreadsheetSkeleton extends Skeleton { }; /** A matrix to store if a (row, column) position has render cache. */ - private _renderedCellCache = new ObjectMatrix(); + private _cellBgAndBorderCache = new ObjectMatrix(); private _showGridlines: BooleanNumber = BooleanNumber.TRUE; @@ -298,9 +293,9 @@ export class SpreadsheetSkeleton extends Skeleton { } /** - * row col start & end range + * Range of visible area(range in viewBounds) */ - get rowColumnSegment(): IRowColumnSegment { + get rowColumnSegment(): IRowColumnRange { return this._rowColumnSegment; } @@ -343,8 +338,13 @@ export class SpreadsheetSkeleton extends Skeleton { this._columnHeaderHeight = 0; this._rowColumnSegment = null as any; this._dataMergeCache = []; - this._stylesCache = null as any; - this._renderedCellCache = null as unknown as ObjectMatrix; + this._stylesCache = { + background: {}, + backgroundPositions: new ObjectMatrix(), + font: {}, + border: new ObjectMatrix(), + }; + this._cellBgAndBorderCache = null as unknown as ObjectMatrix; this._overflowCache = null as unknown as ObjectMatrix; this._worksheetData = null as unknown as IWorksheetData; @@ -392,6 +392,11 @@ export class SpreadsheetSkeleton extends Skeleton { this._marginTop = top; } + /** + * Get range in visible area (range in viewbounds) and set into this._rowColumnSegment. + * @param bounds + * @returns boolean + */ calculateSegment(bounds?: IViewportInfo): boolean { if (!this._worksheetData) { return false; @@ -1604,43 +1609,40 @@ export class SpreadsheetSkeleton extends Skeleton { const columnWidthAccumulation = this.columnWidthAccumulation; const { startRow, endRow, startColumn, endColumn } = rowColumnSegment; - if (endColumn === -1 || endRow === -1) { - return; - } + if (endColumn === -1 || endRow === -1) return; for (const mergeRange of dataMergeCaches) { - this._setCellStylesCache(mergeRange.startRow, mergeRange.startColumn, { + this._setStylesCache(mergeRange.startRow, mergeRange.startColumn, { mergeRange, }); } for (let r = startRow; r <= endRow; r++) { - if (this.worksheet.getRowVisible(r) === false) { - continue; - } + if (this.worksheet.getRowVisible(r) === false) continue; + for (let c = startColumn; c <= endColumn; c++) { - this._setCellStylesCache(r, c); + this._setStylesCache(r, c, { cacheItem: { bg: true, border: true } }); } - // 针对溢出的情况计算文本长度,可视范围左侧列 + // Calculate the text length for overflow situations, focusing on the leftmost column within the visible range. + // for (let c = Math.max(startColumn - 20, 0); c < startColumn; c++) { for (let c = 0; c < startColumn; c++) { - this._setCellStylesCache(r, c, { cacheItem: { bg: false, border: false } }); + this._setStylesCache(r, c, { cacheItem: { bg: false, border: false } }); } + if (endColumn === 0) continue; - if (endColumn === 0) { - continue; - } - - // 针对溢出的情况计算文本长度,可视范围右侧列 + // Calculate the text length for overflow situations, focusing on the rightmost column within the visible range. + // for (let c = endColumn + 1; c < Math.min(endColumn + 20, columnWidthAccumulation.length); c++) { for (let c = endColumn + 1; c < columnWidthAccumulation.length; c++) { - this._setCellStylesCache(r, c, { cacheItem: { bg: false, border: false } }); + this._setStylesCache(r, c, { cacheItem: { bg: false, border: false } }); } } - - // this.calculateOverflow(); } - private _resetCache() { + /** + * Any changes to sheet model would reset cache. + */ + private _resetCache(): void { this._stylesCache = { background: {}, backgroundPositions: new ObjectMatrix(), @@ -1648,16 +1650,16 @@ export class SpreadsheetSkeleton extends Skeleton { border: new ObjectMatrix(), }; - this._renderedCellCache = new ObjectMatrix(); + this._cellBgAndBorderCache = new ObjectMatrix(); this._overflowCache.reset(); } - resetCache() { + resetCache(): void { this._resetCache(); } - private _makeDocumentSkeletonDirty(r: number, c: number) { + private _makeDocumentSkeletonDirty(r: number, c: number): void { if (this._stylesCache.font == null) { return; } @@ -1671,125 +1673,122 @@ export class SpreadsheetSkeleton extends Skeleton { } } + /** + * Set border background and font to this._stylesCache { border font background } + * @param row {number} + * @param col {number} + * @param options {{ mergeRange: IRange; cacheItem: ICacheItem } | undefined} + */ // eslint-disable-next-line complexity - private _setCellStylesCache(r: number, c: number, options?: { - mergeRange?: IRange; - cacheItem?: ICacheItem; - }) { - if (r === -1 || c === -1) { - return true; + private _setStylesCache(row: number, col: number, options?: { mergeRange?: IRange; cacheItem?: ICacheItem }): void { + if (row === -1 || col === -1) { + return; } - const needsRendering = this._renderedCellCache.getValue(r, c); - if (needsRendering === false) { - this._makeDocumentSkeletonDirty(r, c); - return true; + // In most cases, this._cellBgAndBorderCache(row, col) has value means this._styles.font has value. + // So we can return in advance by cellBgAndBorderCache(row, col) + const hasStyleCache = this._cellBgAndBorderCache.getValue(row, col); + if (hasStyleCache === true) { + this._makeDocumentSkeletonDirty(row, col); + return; } /** * TODO: DR-Univer getCellRaw for slide demo, the implementation approach will be changed in the future. */ // const cell = this.worksheet.getCellRaw(r, c); // getCellRaw would be faster but doesn't contain condition format info. - const cell = this.worksheet.getCell(r, c) || this.worksheet.getCellRaw(r, c); - if (!cell) { - return true; - } + const cell = this.worksheet.getCell(row, col) || this.worksheet.getCellRaw(row, col); + if (!cell) return; - const hidden = this.worksheet.getColVisible(c) === false || this.worksheet.getRowVisible(r) === false; + const hidden = this.worksheet.getColVisible(col) === false || this.worksheet.getRowVisible(row) === false; if (hidden) { const { isMerged, isMergedMainCell } = this._getCellMergeInfo( - r, - c, + row, + col, this._dataMergeCache ); if (isMerged && !isMergedMainCell) { // If the cell is merged and is not the main cell, the cell is not rendered. - return true; + return; } else if (!isMergedMainCell) { // If the cell no merged, the cell is not rendered. - return true; + return; } } - const cache = this._stylesCache; - - // style supports inline styles - // const style = styles && styles.get(cell.s); - // const style = getStyle(styles, cell); - const style = this._styles.getStyleByCell(cell); - // by default, style cache should includes border and background info. const cacheItem = options?.cacheItem || { bg: true, border: true }; + + const style = this._styles.getStyleByCell(cell); + //#region cache for background if (cacheItem.bg && style && style.bg && style.bg.rgb) { const rgb = style.bg.rgb; - if (!cache.background![rgb]) { - cache.background![rgb] = new ObjectMatrix(); + if (!this._stylesCache.background![rgb]) { + this._stylesCache.background![rgb] = new ObjectMatrix(); } - const bgCache = cache.background![rgb]; - - bgCache.setValue(r, c, rgb); - const cellInfo = this.getCellByIndexWithNoHeader(r, c); - - cache.backgroundPositions?.setValue(r, c, cellInfo); + const bgCache = this._stylesCache.background![rgb]; + bgCache.setValue(row, col, rgb); + const cellInfo = this.getCellByIndexWithNoHeader(row, col); + this._stylesCache.backgroundPositions?.setValue(row, col, cellInfo); } + //#endregion + //#region cache for border if (cacheItem.border && style && style.bd) { const mergeRange = options?.mergeRange; if (mergeRange) { - this._setMergeBorderProps(BORDER_TYPE.TOP, cache, mergeRange); - this._setMergeBorderProps(BORDER_TYPE.BOTTOM, cache, mergeRange); - this._setMergeBorderProps(BORDER_TYPE.LEFT, cache, mergeRange); - this._setMergeBorderProps(BORDER_TYPE.RIGHT, cache, mergeRange); - } else if (!this.intersectMergeRange(r, c)) { - this._setBorderProps(r, c, BORDER_TYPE.TOP, style, cache); - this._setBorderProps(r, c, BORDER_TYPE.BOTTOM, style, cache); - this._setBorderProps(r, c, BORDER_TYPE.LEFT, style, cache); - this._setBorderProps(r, c, BORDER_TYPE.RIGHT, style, cache); + this._setMergeBorderProps(BORDER_TYPE.TOP, this._stylesCache, mergeRange); + this._setMergeBorderProps(BORDER_TYPE.BOTTOM, this._stylesCache, mergeRange); + this._setMergeBorderProps(BORDER_TYPE.LEFT, this._stylesCache, mergeRange); + this._setMergeBorderProps(BORDER_TYPE.RIGHT, this._stylesCache, mergeRange); + } else if (!this.intersectMergeRange(row, col)) { + this._setBorderProps(row, col, BORDER_TYPE.TOP, style, this._stylesCache); + this._setBorderProps(row, col, BORDER_TYPE.BOTTOM, style, this._stylesCache); + this._setBorderProps(row, col, BORDER_TYPE.LEFT, style, this._stylesCache); + this._setBorderProps(row, col, BORDER_TYPE.RIGHT, style, this._stylesCache); } - this._setBorderProps(r, c, BORDER_TYPE.TL_BR, style, cache); - this._setBorderProps(r, c, BORDER_TYPE.TL_BC, style, cache); - this._setBorderProps(r, c, BORDER_TYPE.TL_MR, style, cache); - this._setBorderProps(r, c, BORDER_TYPE.BL_TR, style, cache); - this._setBorderProps(r, c, BORDER_TYPE.ML_TR, style, cache); - this._setBorderProps(r, c, BORDER_TYPE.BC_TR, style, cache); + this._setBorderProps(row, col, BORDER_TYPE.TL_BR, style, this._stylesCache); + this._setBorderProps(row, col, BORDER_TYPE.TL_BC, style, this._stylesCache); + this._setBorderProps(row, col, BORDER_TYPE.TL_MR, style, this._stylesCache); + this._setBorderProps(row, col, BORDER_TYPE.BL_TR, style, this._stylesCache); + this._setBorderProps(row, col, BORDER_TYPE.ML_TR, style, this._stylesCache); + this._setBorderProps(row, col, BORDER_TYPE.BC_TR, style, this._stylesCache); } - if (needsRendering === true) { - this._makeDocumentSkeletonDirty(r, c); - return true; + // same as: if (!skipBackgroundAndBorder) {...} + if (cacheItem.bg || cacheItem.border) { + this._cellBgAndBorderCache.setValue(row, col, true); + } else { + this._cellBgAndBorderCache.setValue(row, col, false); } - if (isNullCell(cell)) { - return; - } + // When execution reaches here, it indicates that this is a new cell, and the _stylesCache.font does not yet record the data for this cell. - const modelObject = cell && this._getCellDocumentModel(cell, { + //#region font style + if (isNullCell(cell)) return; + const modelObject = this._getCellDocumentModel(cell, { displayRawFormula: this._renderRawFormula, }); - if (modelObject == null) { - return; - } - + if (modelObject == null) return; const { documentModel } = modelObject; - if (documentModel == null) { - return; - } + if (documentModel == null) return; const { fontString, textRotation, wrapStrategy, verticalAlign, horizontalAlign } = modelObject; - const documentViewModel = new DocumentViewModel(documentModel); - if (!cache.font![fontString]) { - cache.font![fontString] = new ObjectMatrix(); + if (!this._stylesCache.font![fontString]) { + this._stylesCache.font![fontString] = new ObjectMatrix(); } - const fontCache = cache.font![fontString]; - - const { vertexAngle, centerAngle } = convertTextRotation(textRotation); + const fontCacheMatrix: ObjectMatrix = this._stylesCache.font![fontString]; + if (fontCacheMatrix.getValue(row, col)) return; + const documentViewModel = new DocumentViewModel(documentModel); if (documentViewModel) { + // return; + const { vertexAngle, centerAngle } = convertTextRotation(textRotation); const documentSkeleton = DocumentSkeleton.create(documentViewModel, this._localService); documentSkeleton.calculate(); @@ -1801,18 +1800,10 @@ export class SpreadsheetSkeleton extends Skeleton { horizontalAlign, wrapStrategy, }; - - fontCache.setValue(r, c, config); - - this._calculateOverflowCell(r, c, config); - } - - // same as: if (!skipBackgroundAndBorder) {...} - if (cacheItem.bg || cacheItem.border) { - this._renderedCellCache.setValue(r, c, false); - } else { - this._renderedCellCache.setValue(r, c, true); + fontCacheMatrix.setValue(row, col, config); + this._calculateOverflowCell(row, col, config); } + //#endregion } private _updateConfigAndGetDocumentModel( @@ -2159,23 +2150,23 @@ export class SpreadsheetSkeleton extends Skeleton { /** * Cache the merged cells on the current screen to improve computational performance. * @param mergeData all marge data - * @param rowColumnSegment current screen range, include row and column + * @param range current screen range, include row and column */ - private _getMergeCells(mergeData: IRange[], rowColumnSegment?: IRowColumnSegment): IRange[] { + private _getMergeCells(mergeData: IRange[], range?: IRange): IRange[] { // const rowColumnSegment = this._rowColumnSegment; const endColumnLast = this.columnWidthAccumulation.length - 1; - if (!rowColumnSegment) { + if (!range) { const endRow = this.rowHeightAccumulation.length - 1; - rowColumnSegment = { startRow: 0, startColumn: 0, endRow, endColumn: endColumnLast }; + range = { startRow: 0, startColumn: 0, endRow, endColumn: endColumnLast }; } else { - rowColumnSegment = { - startRow: rowColumnSegment.startRow, - endRow: rowColumnSegment.endRow, + range = { + startRow: range.startRow, + endRow: range.endRow, endColumn: endColumnLast, startColumn: 0, }; } - const { startRow, startColumn, endRow, endColumn } = rowColumnSegment; + const { startRow, startColumn, endRow, endColumn } = range; const cacheDataMerge: IRange[] = []; for (let i = 0; i < mergeData.length; i++) { const { diff --git a/packages/engine-render/src/context.ts b/packages/engine-render/src/context.ts index 62acbf617fa..315f94a0fa5 100644 --- a/packages/engine-render/src/context.ts +++ b/packages/engine-render/src/context.ts @@ -15,7 +15,6 @@ */ import { Tools } from '@univerjs/core'; -import { Transform } from './basics'; import { fixLineWidthByScale, getColor } from './basics/tools'; export class UniverRenderingContext2D implements CanvasRenderingContext2D { @@ -25,6 +24,8 @@ export class UniverRenderingContext2D implements CanvasRenderingContext2D { readonly canvas: HTMLCanvasElement; _context: CanvasRenderingContext2D; + private _systemType: string; + private _browserType: string; constructor(context: CanvasRenderingContext2D) { this._context = context; @@ -287,12 +288,9 @@ export class UniverRenderingContext2D implements CanvasRenderingContext2D { private _getScale() { const m = this.getTransform(); - const transformer = Transform.create([m.a, m.b, m.c, m.d, m.e, m.f]); - const { scaleX, scaleY } = transformer.decompose(); - return { - scaleX, - scaleY, + scaleX: m.a, + scaleY: m.d, }; } @@ -486,31 +484,27 @@ export class UniverRenderingContext2D implements CanvasRenderingContext2D { this._context.closePath(); } - getSystem() { - if (this._system) { - return this._system; - } else { - this._system = Tools.getSystemType(); + getSystemType() { + if (!this._systemType) { + this._systemType = Tools.getSystemType(); } - return this._system; + return this._systemType; } - getBrowser() { - if (this._browser) { - return this._browser; - } else { - this._browser = Tools.getBrowserType(); + getBrowserType() { + if (!this._browserType) { + this._browserType = Tools.getBrowserType(); } - return this._browser; + return this._browserType; } /** * Chrome hardware acceleration causes canvas stroke to fail to draw lines on Mac. */ closePathByEnv() { - const system = this.getSystem(); + const system = this.getSystemType(); const isMac = system === 'Mac'; - const browser = this.getBrowser(); + const browser = this.getBrowserType(); const isChrome = browser === 'Chrome'; if (isMac && isChrome) { diff --git a/packages/engine-render/src/viewport.ts b/packages/engine-render/src/viewport.ts index d9b0c8b8ff1..ead83de5559 100644 --- a/packages/engine-render/src/viewport.ts +++ b/packages/engine-render/src/viewport.ts @@ -109,8 +109,6 @@ export class Viewport { private _viewportScrollY: number = 0; private _preViewportScrollX: number = 0; private _preViewportScrollY: number = 0; - private _deltaViewportScrollX: number = 0; - private _deltaViewportScrollY: number = 0; /** * scene size in current viewport port with scale @@ -455,6 +453,22 @@ export class Viewport { this._preCacheVisibleBound = Object.assign({}, val); } + get _deltaScrollX() { + return this.scrollX - this._preScrollX; + } + + get _deltaScrollY() { + return this.scrollY - this._preScrollY; + } + + get _deltaViewportScrollX() { + return this.viewportScrollX - this._preViewportScrollX; + } + + get _deltaViewportScrollY() { + return this.viewportScrollY - this._preViewportScrollY; + } + enable() { this._active = true; } @@ -699,6 +713,7 @@ export class Viewport { /** * Just record state of scroll. This method won't scroll viewport and scrollbar. + * TODO: @lumixraku this method is so wierd, viewportMain did not call it, now only called in freeze situation. * @param current * @returns Viewport */ @@ -719,13 +734,11 @@ export class Viewport { if (viewportScrollX !== undefined) { this._preViewportScrollX = this.viewportScrollX; this.viewportScrollX = viewportScrollX; - this._deltaViewportScrollX = viewportScrollX - this._preViewportScrollX; } if (viewportScrollY !== undefined) { this._preViewportScrollY = this.viewportScrollY; this.viewportScrollY = viewportScrollY; - this._deltaViewportScrollY = viewportScrollY - this._preViewportScrollY; } return this; } @@ -1395,7 +1408,7 @@ export class Viewport { } /** - * + * Scroll to position in viewport. * When scroll just in X direction, there is no y definition in scrollVpPos. So scrollVpPos is Partial * @param scrollVpPos Partial * @param isTrigger @@ -1422,6 +1435,10 @@ export class Viewport { const scrollX = afterLimitScrollXY.x; const scrollY = afterLimitScrollXY.y; + this._preScrollX = this.scrollX; + this._preScrollY = this.scrollY; + this._preViewportScrollX = this.viewportScrollX; + this._preViewportScrollY = this.viewportScrollY; this.scrollX = scrollX; this.scrollY = scrollY; this.viewportScrollX = viewportScrollX; diff --git a/packages/sheets-conditional-formatting/src/render/data-bar.render.ts b/packages/sheets-conditional-formatting/src/render/data-bar.render.ts index e367b42afdd..2b7516a4e50 100644 --- a/packages/sheets-conditional-formatting/src/render/data-bar.render.ts +++ b/packages/sheets-conditional-formatting/src/render/data-bar.render.ts @@ -49,14 +49,13 @@ export class DataBar extends SheetExtension { ctx.save(); // ctx.globalCompositeOperation = 'destination-over'; Range.foreach(spreadsheetSkeleton.rowColumnSegment, (row, col) => { + if (!worksheet.getRowVisible(row) || !worksheet.getColVisible(col)) { + return; + } const cellData = worksheet.getCell(row, col) as IDataBarCellData; if (cellData && cellData.dataBar) { - if (!worksheet.getColVisible(col) || !worksheet.getRowRawVisible(row)) { - return; - } - const { color, value, startPoint, isGradient } = cellData.dataBar; - const cellInfo = this.getCellIndex(row, col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + const cellInfo = this.getCellByIndex(row, col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); let { isMerged, isMergedMainCell, mergeInfo, startY, endY, startX, endX } = cellInfo; if (isMerged) { return; diff --git a/packages/sheets-conditional-formatting/src/render/icon.render.ts b/packages/sheets-conditional-formatting/src/render/icon.render.ts index ac7b0bf4a46..bd74e152dc3 100644 --- a/packages/sheets-conditional-formatting/src/render/icon.render.ts +++ b/packages/sheets-conditional-formatting/src/render/icon.render.ts @@ -56,12 +56,11 @@ export class ConditionalFormattingIcon extends SheetExtension { ctx.save(); // ctx.globalCompositeOperation = 'destination-over'; Range.foreach(spreadsheetSkeleton.rowColumnSegment, (row, col) => { + if (!worksheet.getRowVisible(row) || !worksheet.getColVisible(col)) { + return; + } const cellData = worksheet.getCell(row, col) as IIconSetCellData; if (cellData?.iconSet) { - if (!worksheet.getColVisible(col) || !worksheet.getRowRawVisible(row)) { - return; - } - const { iconType, iconId } = cellData.iconSet; if (iconType === EMPTY_ICON_TYPE) { return; @@ -70,7 +69,7 @@ export class ConditionalFormattingIcon extends SheetExtension { if (!icon) { return; } - const cellInfo = this.getCellIndex(row, col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + const cellInfo = this.getCellByIndex(row, col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); let { isMerged, isMergedMainCell, mergeInfo, startY, endY, startX, endX } = cellInfo; if (isMerged) { return; diff --git a/packages/sheets-filter/src/controllers/sheets-filter.controller.ts b/packages/sheets-filter/src/controllers/sheets-filter.controller.ts index d36d647cf90..a5764d7b97b 100644 --- a/packages/sheets-filter/src/controllers/sheets-filter.controller.ts +++ b/packages/sheets-filter/src/controllers/sheets-filter.controller.ts @@ -638,6 +638,8 @@ export class SheetsFilterController extends Disposable { private _initRowFilteredInterceptor(): void { this.disposeWithMe(this._sheetInterceptorService.intercept(INTERCEPTOR_POINT.ROW_FILTERED, { + + // sheet-interceptor.service.ts handler: (filtered, rowLocation) => { if (filtered) return true; return this._sheetsFilterService.getFilterModel( @@ -835,4 +837,3 @@ export class SheetsFilterController extends Disposable { return true; } } - diff --git a/packages/sheets-filter/src/services/sheet-filter.service.ts b/packages/sheets-filter/src/services/sheet-filter.service.ts index 49f13590703..73a30d6a55a 100644 --- a/packages/sheets-filter/src/services/sheet-filter.service.ts +++ b/packages/sheets-filter/src/services/sheet-filter.service.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import type { Nullable, Workbook } from '@univerjs/core'; import { CommandType, Disposable, fromCallback, @@ -24,14 +23,15 @@ import { UniverInstanceType, } from '@univerjs/core'; import { BehaviorSubject, filter, merge, of, switchMap } from 'rxjs'; +import type { Nullable, Workbook } from '@univerjs/core'; -import { FilterModel } from '../models/filter-model'; import { ReCalcSheetsFilterMutation, RemoveSheetsFilterMutation, SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation, } from '../commands/mutations/sheets-filter.mutation'; +import { FilterModel } from '../models/filter-model'; import type { IAutoFilter } from '../models/types'; export const FILTER_MUTATIONS = new Set([ @@ -131,6 +131,7 @@ export class SheetsFilterService extends Disposable { return; } } catch (err) { + console.error('[SheetsFilterService]: could not get active workbook!', err); return; } diff --git a/packages/sheets-ui/src/services/scroll-manager.service.ts b/packages/sheets-ui/src/services/scroll-manager.service.ts index 198af6ee546..d3ade3f576e 100644 --- a/packages/sheets-ui/src/services/scroll-manager.service.ts +++ b/packages/sheets-ui/src/services/scroll-manager.service.ts @@ -117,7 +117,7 @@ export class SheetScrollManagerService implements IRenderModule { } /** - * set scrollInfo by cmd, call by scroll operation + * set scrollInfo by SetScrollOperation, call by scroll operation * @param param */ setScrollInfoAndEmitEvent(param: IScrollStateWithSearchParam) { diff --git a/packages/sheets-ui/src/views/permission/extensions/range-protection.render.ts b/packages/sheets-ui/src/views/permission/extensions/range-protection.render.ts index f8c3c06a059..6ba3945f594 100644 --- a/packages/sheets-ui/src/views/permission/extensions/range-protection.render.ts +++ b/packages/sheets-ui/src/views/permission/extensions/range-protection.render.ts @@ -64,7 +64,7 @@ export abstract class RangeProtectionRenderExtension extends SheetExtension { } this.renderCache.clear(); Range.foreach(spreadsheetSkeleton.rowColumnSegment, (row, col) => { - if (!worksheet.getColVisible(col) || !worksheet.getRowVisible(row)) { + if (!worksheet.getRowVisible(row) || !worksheet.getColVisible(col)) { return; } const { selectionProtection = [] } = worksheet.getCell(row, col) as IRangeProtectionRenderCellData || {}; @@ -85,8 +85,8 @@ export abstract class RangeProtectionRenderExtension extends SheetExtension { } this.renderCache.add(config.ruleId); config.ranges!.forEach((range) => { - const start = this.getCellIndex(range.startRow, range.startColumn, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); - const end = this.getCellIndex(range.endRow, range.endColumn, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + const start = this.getCellByIndex(range.startRow, range.startColumn, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + const end = this.getCellByIndex(range.endRow, range.endColumn, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); ctx.fillRect(start.startX, start.startY, end.endX - start.startX, end.endY - start.startY); }); } diff --git a/packages/sheets-ui/src/views/permission/extensions/worksheet-permission.render.ts b/packages/sheets-ui/src/views/permission/extensions/worksheet-permission.render.ts index 775c72b08f2..7ed7224532b 100644 --- a/packages/sheets-ui/src/views/permission/extensions/worksheet-permission.render.ts +++ b/packages/sheets-ui/src/views/permission/extensions/worksheet-permission.render.ts @@ -54,8 +54,8 @@ export class WorksheetProtectionRenderExtension extends SheetExtension { this._pattern = ctx.createPattern(this._img, 'repeat'); } const { startRow, startColumn, endRow, endColumn } = spreadsheetSkeleton.rowColumnSegment; - const start = this.getCellIndex(startRow, startColumn, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); - const end = this.getCellIndex(endRow, endColumn, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + const start = this.getCellByIndex(startRow, startColumn, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + const end = this.getCellByIndex(endRow, endColumn, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); const { hasWorksheetRule = false, selectionProtection = [] } = worksheet.getCell(startRow, startColumn) as IWorksheetProtectionRenderCellData || {}; if (!this._pattern) { diff --git a/packages/sheets/src/services/sheet-interceptor/__tests__/sheet-interceptor.service.spec.ts b/packages/sheets/src/services/sheet-interceptor/__tests__/sheet-interceptor.service.spec.ts index 6def963042c..6db7423bc3f 100644 --- a/packages/sheets/src/services/sheet-interceptor/__tests__/sheet-interceptor.service.spec.ts +++ b/packages/sheets/src/services/sheet-interceptor/__tests__/sheet-interceptor.service.spec.ts @@ -14,14 +14,14 @@ * limitations under the License. */ -import type { ICellData, Injector, Nullable, Univer, Workbook } from '@univerjs/core'; import { createInterceptorKey, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import type { ICellData, Injector, Nullable, Univer, Workbook } from '@univerjs/core'; import { INTERCEPTOR_POINT } from '../interceptor-const'; import { SheetInterceptorService } from '../sheet-interceptor.service'; -import type { ISheetLocation } from '../utils/interceptor'; import { createSheetTestBed } from './create-core-test-bed'; +import type { ISheetLocation } from '../utils/interceptor'; describe('Test SheetInterceptorService', () => { let univer: Univer; @@ -49,7 +49,7 @@ describe('Test SheetInterceptorService', () => { return sheet.getRowFiltered(row); } - function getRowRawVisible(row: number): boolean { + function getRowVisible(row: number): boolean { const cus = get(IUniverInstanceService); const sheet = cus.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!.getActiveSheet()!; return sheet.getRowVisible(row); @@ -112,13 +112,13 @@ describe('Test SheetInterceptorService', () => { }); expect(getRowFiltered(1)).toBeFalsy(); - expect(getRowRawVisible(1)).toBeTruthy(); + expect(getRowVisible(1)).toBeTruthy(); realFiltered = true; expect(getRowFiltered(1)).toBeTruthy(); - expect(getRowRawVisible(1)).toBeFalsy(); + expect(getRowVisible(1)).toBeFalsy(); expect(getRowFiltered(2)).toBeFalsy(); - expect(getRowRawVisible(2)).toBeTruthy(); + expect(getRowVisible(2)).toBeTruthy(); }); });