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: should beginPath before clip()
  • Loading branch information
lumixraku committed May 24, 2024
commit f97db727a9be8a998ccd9312e1cd9bc5a3e1a9e3
21 changes: 9 additions & 12 deletions packages/engine-render/src/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,18 @@ export class Canvas {
// this.setWidth(width || 0);
// this.setHeight(height || 0);
this._pixelRatio = pixelRatioParam || getDevicePixelRatio();
const canvsElement = this.getCanvasEle();

if (width !== undefined) {
this.getCanvasEle().width = width * this._pixelRatio;

this._width = this.getCanvasEle().width / this._pixelRatio;

this.getCanvasEle().style.width = `${this._width}px`;
if (canvsElement && width !== undefined) {
canvsElement.width = width * this._pixelRatio;
this._width = canvsElement.width / this._pixelRatio;
canvsElement.style.width = `${this._width}px`;
}

if (height !== undefined) {
this.getCanvasEle().height = height * this._pixelRatio;

this._height = this.getCanvasEle().height / this._pixelRatio;

this.getCanvasEle().style.height = `${this._height}px`;
if (canvsElement && height !== undefined) {
canvsElement.height = height * this._pixelRatio;
this._height = canvsElement.height / this._pixelRatio;
canvsElement.style.height = `${this._height}px`;
}

this.getContext().setTransform(this._pixelRatio, 0, 0, this._pixelRatio, 0, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export class Background extends SheetExtension {
return;
}
ctx.save();
// ctx.setGlobalCompositeOperation('destination-over');
const { scaleX, scaleY } = ctx.getScale();
background &&
Object.keys(background).forEach((rgb: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,15 @@ export class Font extends SheetExtension {
startX = mergeInfo.startX;
endX = mergeInfo.endX;
}

/**
* Incremental content rendering for texture mapping
* startRow endRow 和 diffRanges 在 row 上不相交, 那么返回不渲染
* PS 如果这个单元格并不在 merge 区域内, mergeInfo start 和 end 就是单元格本身
*/
if (!this.isRowInDiffRanges(mergeInfo.startRow, mergeInfo.endRow, diffRanges)) {
return true;
if (diffRanges) {
if (!this.isRowInRanges(mergeInfo.startRow, mergeInfo.endRow, diffRanges)) {
return true;
}
}

/**
Expand Down Expand Up @@ -257,6 +258,7 @@ export class Font extends SheetExtension {
}
} else {
ctx.rectByPrecision(startX + 1 / scale, startY + 1 / scale, cellWidth - 2 / scale, cellHeight - 2 / scale);
// for normal cell, forbid text overflow cellarea
ctx.clip();
// ctx.clearRectForTexture(
// startX + 1 / scale,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,15 @@ export class SheetExtension extends ComponentExtension<SpreadsheetSkeleton, SHEE
* 传入的 row 范围和 diffRanges 有相交, 返回 true
* @param curStartRow
* @param curEndRow
* @param diffRanges
* @param viewranges
* @returns
*/
isRowInDiffRanges(curStartRow: number, curEndRow: number, diffRanges?: IRange[]) {
if (diffRanges == null || diffRanges.length === 0) {
isRowInRanges(curStartRow: number, curEndRow: number, viewranges?: IRange[]) {
if (viewranges == null || viewranges.length === 0) {
return true;
}

for (const range of diffRanges) {
for (const range of viewranges) {
const { startRow, endRow } = range;
// if (curStartRow >= startRow && curStartRow <= endRow) {
// return true;
Expand Down
62 changes: 38 additions & 24 deletions packages/engine-render/src/components/sheets/spreadsheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,14 @@ export class Spreadsheet extends SheetComponent {
this._drawAuxiliary(ctx);
const parentScale = this.getParentScale();

const diffRanges = this._refreshIncrementalState && viewportInfo?.diffCacheBounds
const diffRanges = this._refreshIncrementalState && viewportInfo?.diffBounds
? viewportInfo?.diffBounds?.map((bound) => spreadsheetSkeleton.getRowColumnSegmentByViewBound(bound))
: undefined;

const viewRanges = [spreadsheetSkeleton.getRowColumnSegmentByViewBound(viewportInfo?.cacheBound)];
const extensions = this.getExtensionsByOrder();

// 此刻 ctx.transform is at topLeft of sheet content, cell(0, 0)
for (const extension of extensions) {
// const timeKey = `extension ${viewportInfo.viewPortKey}:${extension.constructor.name}`;
// console.time(timeKey);
Expand Down Expand Up @@ -271,7 +274,7 @@ export class Spreadsheet extends SheetComponent {
cacheCtx.restore();
}

paintNewAreaOfCacheCanvas(viewportBoundsInfo: IViewportInfo, param: {
paintNewAreaOfCacheCanvas(viewportInfo: IViewportInfo, param: {
cacheCanvas: Canvas; cacheCtx: UniverRenderingContext; mainCtx: UniverRenderingContext;
topOrigin: number;
leftOrigin: number;
Expand All @@ -283,50 +286,43 @@ export class Spreadsheet extends SheetComponent {
scaleY: number;
}) {
const { cacheCanvas, cacheCtx, mainCtx, topOrigin, leftOrigin, bufferEdgeX, bufferEdgeY, scaleX, scaleY, columnHeaderHeight, rowHeaderWidth } = param;
const { shouldCacheUpdate, diffCacheBounds, diffX, diffY } = viewportBoundsInfo;
const { shouldCacheUpdate, diffCacheBounds, diffX, diffY } = viewportInfo;
cacheCtx.save();
cacheCtx.setTransform(1, 0, 0, 1, 0, 0);
cacheCtx.globalCompositeOperation = 'copy';
cacheCtx.drawImage(cacheCanvas.getCanvasEle(), diffX * scaleX, diffY * scaleY);
cacheCtx.restore();

this._refreshIncrementalState = true;

// 绘制之前重设画笔位置到 spreadsheet 原点, 当没有滚动时, 这个值是 (rowHeaderWidth, colHeaderHeight)
const m = mainCtx.getTransform();
cacheCtx.setTransform(m.a, m.b, m.c, m.d, 0, 0);

// leftOrigin 是 viewport 相对 sheetcorner 的偏移(不考虑缩放)
// - (leftOrigin - bufferEdgeX) ----> 简化
// - (leftOrigin - bufferEdgeX) ----> 简化 - 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();

const { left: diffLeft, right: diffRight, bottom: diffBottom, top: diffTop } = diffBound;

// this.draw 的时候 ctx.translate 单元格偏移是相对 spreadsheet content
// 但是 diffBounds 包括 rowHeader 信息, 因此绘制前需要减去行头列头的偏移
const onePixelFix = FIX_ONE_PIXEL_BLUR_OFFSET * 0;
const x = diffLeft - rowHeaderWidth - onePixelFix;
const y = diffTop - columnHeaderHeight - onePixelFix;
const w = diffRight - diffLeft + onePixelFix;
const h = diffBottom - diffTop + onePixelFix;
cacheCtx.rectByPrecision(x, y, w, h);
// 但是 diffBounds 包括 rowHeader columnWidth, 因此绘制前需要减去行头列头的偏移
const x = diffLeft - rowHeaderWidth;
const y = diffTop - columnHeaderHeight;
const w = diffRight - diffLeft;
const h = diffBottom - diffTop; // w h 必须精确和 diffarea 大小匹配, 否则会造成往回滚时, clear 的区域过大, 导致上一帧有效内容被擦除

// 使用 clearRect 后, 很浅很细的白色线(even not zoom has blank line)
const onePixelFix2 = FIX_ONE_PIXEL_BLUR_OFFSET;
cacheCtx.clearRect(x + onePixelFix2, y + onePixelFix2, w - onePixelFix2 * 2, h - onePixelFix2 * 2);
// cacheCtx.save();
// const m = cacheCtx.getTransform();
// cacheCtx.setTransform(1, 0, 0, 1, m.e, m.f);
// cacheCtx.clearRect(Math.ceil(x * m.a), y * m.a, Math.floor(w * m.a), h * m.a);
// cacheCtx.restore();
cacheCtx.clearRectByPrecision(x, y, w, h);
// cacheCtx.fillStyle = this.getRandomLightColor();
// cacheCtx.fillRectByPrecision(x, y, w, h); // x, y is diffBounds, means it's relative to scrolling distance.

// 这里需要 clip 的原因是避免重复绘制 (否则文字有毛刺)
cacheCtx.save();
cacheCtx.beginPath();
cacheCtx.rectByPrecision(x, y, w, h);
// 这里需要 clip 的原因是避免重复绘制 (否则文字有毛刺, especially on Windows)
cacheCtx.clip();
this.draw(cacheCtx, {
...viewportBoundsInfo,
...viewportInfo,
diffBounds: [diffBound],
});
cacheCtx.restore();
Expand Down Expand Up @@ -714,4 +710,22 @@ export class Spreadsheet extends SheetComponent {
ctx.clearRectForTexture(startX, startY, endX - startX + 0.5, endY - startY + 0.5);
});
}

getRandomLightColor(): string {
const letters = 'ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 6)];
}

// 确保生成的颜色足够亮
const r = Number.parseInt(color.substring(1, 3), 16);
const g = Number.parseInt(color.substring(3, 5), 16);
const b = Number.parseInt(color.substring(5, 7), 16);
if (r + g + b < 610) {
return this.getRandomLightColor(); // 递归调用直到生成足够亮的颜色
}

return color;
}
}
8 changes: 4 additions & 4 deletions packages/engine-render/src/viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,12 @@ export class Viewport {
const showCache = (cacheCanvas: UniverCanvas) => {
cacheCanvas.getCanvasEle().style.zIndex = '100';
cacheCanvas.getCanvasEle().style.position = 'fixed';
cacheCanvas.getCanvasEle().style.background = '#fff';
cacheCanvas.getCanvasEle().style.background = 'blue';
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.translate = '20% 0%';
cacheCanvas.getCanvasEle().style.translate = '-20% 0%';
cacheCanvas.getCanvasEle().style.opacity = '1';
document.body.appendChild(cacheCanvas.getCanvasEle());
};
Expand Down Expand Up @@ -1294,8 +1294,8 @@ export class Viewport {
? 0b01
: 0b00;

const edgeX = this.bufferEdgeX / 2;
const edgeY = this.bufferEdgeY / 2;
const edgeX = this.bufferEdgeX / 4;
const edgeY = this.bufferEdgeY / 4;
const nearEdge = ((diffX < 0 && Math.abs(viewBound.right - cacheBounds.right) < edgeX) ||
(diffX > 0 && Math.abs(viewBound.left - cacheBounds.left) < edgeX) ||
// 滚动条向上, 向上往回滚
Expand Down
2 changes: 1 addition & 1 deletion packages/sheets-ui/src/views/sheet-canvas-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class SheetCanvasView extends RxDisposable implements IRenderController {
isRelativeY: true,
allowCache: true,
bufferEdgeX: 100,
bufferEdgeY: 50,
bufferEdgeY: 100,
});

const viewRowTop = new Viewport(VIEWPORT_KEY.VIEW_ROW_TOP, scene, {
Expand Down