From 7e5f993c6e2d96cc3be6eeff712d05c1179a3381 Mon Sep 17 00:00:00 2001 From: lumixraku Date: Fri, 10 May 2024 17:25:28 +0800 Subject: [PATCH] fix: 0510-1725 fix: #676 #677 --- .../components/sheets/extensions/border.ts | 9 +-- .../src/components/sheets/extensions/font.ts | 2 +- .../src/components/sheets/spreadsheet.ts | 79 +++++++++++++++---- packages/engine-render/src/viewport.ts | 8 +- .../controllers/sheet-render.controller.ts | 10 ++- 5 files changed, 80 insertions(+), 28 deletions(-) diff --git a/packages/engine-render/src/components/sheets/extensions/border.ts b/packages/engine-render/src/components/sheets/extensions/border.ts index febf461d4b..4126897f1f 100644 --- a/packages/engine-render/src/components/sheets/extensions/border.ts +++ b/packages/engine-render/src/components/sheets/extensions/border.ts @@ -19,7 +19,6 @@ import { BorderStyleTypes } from '@univerjs/core'; import { BORDER_TYPE, COLOR_BLACK_RGB, FIX_ONE_PIXEL_BLUR_OFFSET } from '../../../basics/const'; import { drawDiagonalLineByBorderType, drawLineByBorderType, getLineWidth, setLineType } from '../../../basics/draw'; -import { inViewRanges } from '../../../basics/tools'; import type { UniverRenderingContext } from '../../../context'; import { SpreadsheetExtensionRegistry } from '../../extension'; import type { BorderCacheItem } from '../interfaces'; @@ -39,8 +38,7 @@ export class Border extends SheetExtension { ctx: UniverRenderingContext, parentScale: IScale, spreadsheetSkeleton: SpreadsheetSkeleton, - diffRanges: IRange[], - { viewRanges }: { viewRanges?: IRange[]; diffRanges?: IRange[]; checkOutOfViewBound: boolean } + diffRanges?: IRange[] ) { const { dataMergeCache, stylesCache, overflowCache } = spreadsheetSkeleton; const { border } = stylesCache; @@ -72,9 +70,6 @@ export class Border extends SheetExtension { if (!borderCaches) { return true; } - if (!inViewRanges(viewRanges!, rowIndex, columnIndex)) { - return true; - } const cellInfo = this.getCellIndex( rowIndex, @@ -87,7 +82,7 @@ export class Border extends SheetExtension { const { startY: cellStartY, endY: cellEndY, startX: cellStartX, endX: cellEndX } = cellInfo; const { isMerged, isMergedMainCell, mergeInfo } = cellInfo; - if (!this.isRowInDiffRanges(mergeInfo.startRow, mergeInfo.endRow, diffRanges)) { + if (!this.isRenderDiffRangesByRow(mergeInfo.startRow, mergeInfo.endRow, diffRanges)) { return true; } diff --git a/packages/engine-render/src/components/sheets/extensions/font.ts b/packages/engine-render/src/components/sheets/extensions/font.ts index 645f5d14f7..9f6ec88edf 100644 --- a/packages/engine-render/src/components/sheets/extensions/font.ts +++ b/packages/engine-render/src/components/sheets/extensions/font.ts @@ -32,7 +32,7 @@ import { SheetExtension } from './sheet-extension'; const UNIQUE_KEY = 'DefaultFontExtension'; -const EXTENSION_Z_INDEX = 30; +const EXTENSION_Z_INDEX = 45; export interface ISheetFontRenderExtension { fontRenderExtension?: { leftOffset?: number; diff --git a/packages/engine-render/src/components/sheets/spreadsheet.ts b/packages/engine-render/src/components/sheets/spreadsheet.ts index d3d1126a6a..ad4d1d0cf4 100644 --- a/packages/engine-render/src/components/sheets/spreadsheet.ts +++ b/packages/engine-render/src/components/sheets/spreadsheet.ts @@ -138,6 +138,8 @@ export class Spreadsheet extends SheetComponent { const extensions = this.getExtensionsByOrder(); for (const extension of extensions) { + const m = ctx.getTransform(); + ctx.setTransform(m.a, m.b, m.c, m.d, Math.ceil(m.e), Math.ceil(m.f)); extension.draw(ctx, parentScale, spreadsheetSkeleton, diffRanges, { viewRanges, diffRanges, @@ -226,11 +228,11 @@ export class Spreadsheet extends SheetComponent { } /** - * canvas resize calling not this function * @param state */ override makeDirty(state: boolean = true) { super.makeDirty(state); + (this.getParent() as Scene)?.getViewports().forEach((vp) => vp.markDirty()); if (state === false) { this._dirtyBounds = []; } @@ -294,8 +296,11 @@ export class Spreadsheet extends SheetComponent { // 绘制之前重设画笔位置到 spreadsheet 原点, 当没有滚动时, 这个值是 (rowHeaderWidth, colHeaderHeight) const m = mainCtx.getTransform(); - cacheCtx.setTransform(m.a, m.b, m.c, m.d, m.e, m.f); - cacheCtx.translate(-leftOrigin + bufferEdgeX, -topOrigin + bufferEdgeY); + cacheCtx.setTransform(m.a, m.b, m.c, m.d, 0, 0); + + // leftOrigin 是 viewport 相对 sheetcorner 的偏移(不考虑缩放) + // - (leftOrigin - bufferEdgeX) ----> 简化 + cacheCtx.translateWithPrecision(m.e / m.a - leftOrigin + bufferEdgeX, m.f / m.d - topOrigin + bufferEdgeY); if (shouldCacheUpdate) { for (const diffBound of diffCacheBounds) { cacheCtx.save(); @@ -309,7 +314,7 @@ export class Spreadsheet extends SheetComponent { const y = diffTop - columnHeaderHeight - onePixelFix; const w = diffRight - diffLeft + onePixelFix; const h = diffBottom - diffTop + onePixelFix; - cacheCtx.rect(x, y, w, h); + cacheCtx.rectByPrecision(x, y, w, h); // 使用 clearRect 后, 很浅很细的白色线(even not zoom has blank line) @@ -353,11 +358,12 @@ export class Spreadsheet extends SheetComponent { cacheCtx.save(); // 所以 cacheCtx.setTransform 已经包含了 rowHeaderWidth + viewport + scroll 距离 const m = mainCtx.getTransform(); - cacheCtx.setTransform(m.a, m.b, m.c, m.d, m.e, m.f); + // cacheCtx.setTransform(m.a, m.b, m.c, m.d, m.e, m.f); + cacheCtx.setTransform(m.a, m.b, m.c, m.d, 0, 0); - // leftOrigin 是 viewport 相对 sheetcorner 的偏移(不考虑缩放) - // - (leftOrigin - bufferEdgeX) ----> 简化 - cacheCtx.translate(-leftOrigin + bufferEdgeX, -topOrigin + bufferEdgeY); + // // leftOrigin 是 viewport 相对 sheetcorner 的偏移(不考虑缩放) + // // - (leftOrigin - bufferEdgeX) ----> 简化 + cacheCtx.translateWithPrecision(m.e / m.a - leftOrigin + bufferEdgeX, m.f / m.d - topOrigin + bufferEdgeY); // extension 绘制时按照内容的左上角计算, 不考虑 rowHeaderWidth this.draw(cacheCtx, viewportBoundsInfo); @@ -429,7 +435,7 @@ export class Spreadsheet extends SheetComponent { * @returns */ protected _applyCacheFreeze( - mainCtx: UniverRenderingContext, + ctx?: UniverRenderingContext, cacheCanvas: Canvas, sx: number = 0, sy: number = 0, @@ -440,18 +446,18 @@ export class Spreadsheet extends SheetComponent { dw: number = 0, dh: number = 0 ) { - if (!mainCtx) { + if (!ctx) { return; } const pixelRatio = cacheCanvas.getPixelRatio(); + const cacheCtx = cacheCanvas.getContext(); cacheCtx.save(); - mainCtx.save(); - mainCtx.setTransform(1, 0, 0, 1, 0, 0); + ctx.save(); + ctx.setTransform(1, 0, 0, 1, 0, 0); cacheCtx.setTransform(1, 0, 0, 1, 0, 0); - mainCtx.globalCompositeOperation = 'source-over'; - mainCtx.drawImage( + ctx.drawImage( cacheCanvas.getCanvasEle(), sx * pixelRatio, sy * pixelRatio, @@ -462,7 +468,7 @@ export class Spreadsheet extends SheetComponent { dw * pixelRatio, dh * pixelRatio ); - mainCtx.restore(); + ctx.restore(); cacheCtx.restore(); } @@ -519,6 +525,7 @@ export class Spreadsheet extends SheetComponent { * @param bounds * @returns */ + // eslint-disable-next-line max-lines-per-function private _drawAuxiliary(ctx: UniverRenderingContext, bounds?: IViewportInfo) { const spreadsheetSkeleton = this.getSkeleton(); if (spreadsheetSkeleton == null) { @@ -600,6 +607,48 @@ export class Spreadsheet extends SheetComponent { ctx.closePathByEnv(); ctx.stroke(); } + // console.log('xx2', scaleX, scaleY, columnTotalWidth, rowTotalHeight, rowHeightAccumulation, columnWidthAccumulation); + + // border?.forValue((rowIndex, columnIndex, borderCaches) => { + // if (!borderCaches) { + // return true; + // } + + // const cellInfo = spreadsheetSkeleton.getCellByIndexWithNoHeader(rowIndex, columnIndex); + + // let { startY, endY, startX, endX } = cellInfo; + // const { isMerged, isMergedMainCell, mergeInfo } = cellInfo; + + // if (isMerged) { + // return true; + // } + + // if (isMergedMainCell) { + // startY = mergeInfo.startY; + // endY = mergeInfo.endY; + // startX = mergeInfo.startX; + // endX = mergeInfo.endX; + // } + + // if (!(mergeInfo.startRow >= rowStart && mergeInfo.endRow <= rowEnd)) { + // return true; + // } + + // for (const key in borderCaches) { + // const { type } = borderCaches[key] as BorderCacheItem; + + // clearLineByBorderType(ctx, type, { startX, startY, endX, endY }); + // } + // }); + + // Clearing the dashed line issue caused by overlaid auxiliary lines and strokes + // merge cell + this._clearRectangle(ctx, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache); + + // overflow cell + this._clearRectangle(ctx, rowHeightAccumulation, columnWidthAccumulation, overflowCache.toNativeArray()); + + this._clearBackground(ctx, backgroundPositions); ctx.restore(); } diff --git a/packages/engine-render/src/viewport.ts b/packages/engine-render/src/viewport.ts index 0052745fbd..d3cc7c4ea5 100644 --- a/packages/engine-render/src/viewport.ts +++ b/packages/engine-render/src/viewport.ts @@ -245,6 +245,7 @@ export class Viewport { this._resizeHandler(); }); this._resizeHandler(); + this._testDisplayCache(); } initCacheCanvas(props?: IViewProps) { @@ -267,12 +268,13 @@ export class Viewport { const showCache = (cacheCanvas: UniverCanvas) => { cacheCanvas.getCanvasEle().style.zIndex = '100'; cacheCanvas.getCanvasEle().style.position = 'fixed'; - cacheCanvas.getCanvasEle().style.background = 'red'; + cacheCanvas.getCanvasEle().style.background = '#fff'; cacheCanvas.getCanvasEle().style.pointerEvents = 'none'; // 禁用事件响应 cacheCanvas.getCanvasEle().style.border = '1px solid black'; // 设置边框样式 cacheCanvas.getCanvasEle().style.transformOrigin = '100% 100%'; cacheCanvas.getCanvasEle().style.transform = 'scale(0.5)'; - // cacheCanvas.getCanvasEle().style.opacity = '0.9'; + cacheCanvas.getCanvasEle().style.translate = '20% 20%'; + cacheCanvas.getCanvasEle().style.opacity = '0.9'; document.body.appendChild(cacheCanvas.getCanvasEle()); }; if (['viewMain', 'viewMainLeftTop', 'viewMainTop', 'viewMainLeft'].includes(this.viewportKey)) { @@ -417,7 +419,6 @@ export class Viewport { * this.width this.height 也有可能是 undefined * 因此应通过 _getViewPortSize 获取宽高 * @param position - * @returns */ resize(position: IViewPosition) { const positionKeys = Object.keys(position); @@ -673,6 +674,7 @@ export class Viewport { mainCtx.beginPath(); // DEPT: left is set by upper views but width and height is not // this.left has handle scale already, no need to `this.width * scale` + // const { scaleX, scaleY } = this._getBoundScale(m[0], m[3]); mainCtx.rect(this.left, this.top, (this.width || 0), (this.height || 0)); mainCtx.clip(); } diff --git a/packages/sheets-ui/src/controllers/sheet-render.controller.ts b/packages/sheets-ui/src/controllers/sheet-render.controller.ts index 2ac66fa12a..ccd2af2d73 100644 --- a/packages/sheets-ui/src/controllers/sheet-render.controller.ts +++ b/packages/sheets-ui/src/controllers/sheet-render.controller.ts @@ -28,7 +28,7 @@ import { CommandType, Tools, UniverInstanceType, } from '@univerjs/core'; -import type { IViewportInfos, Rect, SpreadsheetColumnHeader, SpreadsheetRowHeader, Viewport } from '@univerjs/engine-render'; +import type { IViewportInfos, Rect, Scene, SpreadsheetColumnHeader, SpreadsheetRowHeader, Viewport } from '@univerjs/engine-render'; import { IRenderManagerService, RENDER_RAW_FORMULA_KEY, Spreadsheet } from '@univerjs/engine-render'; import { COMMAND_LISTENER_SKELETON_CHANGE, @@ -203,17 +203,23 @@ export class SheetRenderController extends RxDisposable { }); } + private _spreadsheetViewports(scene: Scene) { + return scene.getViewports().filter((v) => ['viewMain', 'viewMainLeftTop', 'viewMainTop', 'viewMainLeft'].includes(v.viewportKey)); + } + private _markSpreadsheetDirty(unitId: string, command: ICommandInfo) { const currentRender = this._renderManagerService.getRenderById(unitId); if (!currentRender) return; const { mainComponent: spreadsheet, scene } = currentRender; + // 现在 spreadsheet.markDirty 会调用 vport.markDirty + // 因为其他 controller 中存在 mainComponent?.makeDirty() 的调用, 不止是 sheet-render.controller 在标脏 if (spreadsheet) { spreadsheet.makeDirty(); // refresh spreadsheet } scene.makeDirty(); if (!command.params) return; const cmdParams = command.params as Record; - const viewports = scene.getViewports().filter((v) => ['viewMain', 'viewMainLeftTop', 'viewMainTop', 'viewMainLeft'].includes(v.viewportKey)); + const viewports = this._spreadsheetViewports(scene); if (command.id === SetRangeValuesMutation.id && cmdParams.cellValue) { const dirtyRange: IRange = this._cellValueToRange(cmdParams.cellValue); const dirtyBounds = this._rangeToBounds([dirtyRange]);