Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(sheet): render viewport wrong size #1727

Draft
wants to merge 13 commits into
base: dev
Choose a base branch
from
Prev Previous commit
Next Next commit
fix: 0510-1725
fix: #676 #677

fix: browser native zoom
  • Loading branch information
lumixraku committed May 24, 2024
commit 1ec8a2d2409e48d4fadd4865e907292093f5ee94
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
85 changes: 68 additions & 17 deletions packages/engine-render/src/components/sheets/spreadsheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 = [];
}
Expand Down Expand Up @@ -259,14 +261,16 @@ export class Spreadsheet extends SheetComponent {
if (isDirty || isForceDirty) {
this.refreshCacheCanvas(viewportBoundsInfo, { cacheCanvas, cacheCtx, mainCtx, topOrigin, leftOrigin, bufferEdgeX, bufferEdgeY });
}
this._applyCacheFreeze(mainCtx, cacheCanvas, bufferEdgeSizeX, bufferEdgeSizeY, dw, dh, left, top, dw, dh);
} else if (diffBounds.length !== 0 || diffX !== 0 || diffY === 0) {
// scrolling && no dirty
this.paintNewAreaOfCacheCanvas(viewportBoundsInfo, {
cacheCanvas, cacheCtx, mainCtx, topOrigin, leftOrigin, bufferEdgeX, bufferEdgeY, scaleX, scaleY, columnHeaderHeight, rowHeaderWidth,
});
this._applyCacheFreeze(mainCtx, cacheCanvas, bufferEdgeSizeX, bufferEdgeSizeY, dw, dh, left, top, dw, dh);
}
// support for browser native zoom
const sourceLeft = bufferEdgeSizeX * Math.min(1, window.devicePixelRatio);
const sourceTop = bufferEdgeSizeY * Math.min(1, window.devicePixelRatio);
this._applyCacheFreeze(mainCtx, cacheCanvas, sourceLeft, sourceTop, dw, dh, left, top, dw, dh);
cacheCtx.restore();
}

Expand Down Expand Up @@ -294,8 +298,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();
Expand All @@ -309,7 +316,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)
Expand Down Expand Up @@ -353,11 +360,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);
Expand Down Expand Up @@ -429,7 +437,7 @@ export class Spreadsheet extends SheetComponent {
* @returns
*/
protected _applyCacheFreeze(
mainCtx: UniverRenderingContext,
ctx: UniverRenderingContext,
cacheCanvas: Canvas,
sx: number = 0,
sy: number = 0,
Expand All @@ -440,18 +448,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,
Expand All @@ -462,7 +470,7 @@ export class Spreadsheet extends SheetComponent {
dw * pixelRatio,
dh * pixelRatio
);
mainCtx.restore();
ctx.restore();
cacheCtx.restore();
}

Expand Down Expand Up @@ -519,6 +527,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) {
Expand Down Expand Up @@ -601,6 +610,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();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/engine-render/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ export class UniverRenderingContext2D implements CanvasRenderingContext2D {
* @method
*/
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterClockwise?: boolean) {
this._context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
this._context.arc(x, y, Math.max(0, radius), startAngle, endAngle, counterClockwise);
}

/**
Expand Down
8 changes: 5 additions & 3 deletions packages/engine-render/src/viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ export class Viewport {
this._resizeHandler();
});
this._resizeHandler();
// this._testDisplayCache();
}

initCacheCanvas(props?: IViewProps) {
Expand All @@ -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)) {
Expand Down Expand Up @@ -417,7 +419,6 @@ export class Viewport {
* this.width this.height 也有可能是 undefined
* 因此应通过 _getViewPortSize 获取宽高
* @param position
* @returns
*/
resize(position: IViewPosition) {
const positionKeys = Object.keys(position);
Expand Down Expand Up @@ -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();
}
Expand Down
10 changes: 8 additions & 2 deletions packages/sheets-ui/src/controllers/sheet-render.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<string, any>;
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]);
Expand Down