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: markdirty & scrolling was conflict before, so scrolling & dirty …
…did not refresh whole viewport
  • Loading branch information
lumixraku committed May 24, 2024
commit 5b162026b058a58ca585abe514e887a2ac7524f3
2 changes: 1 addition & 1 deletion packages/engine-render/src/basics/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ export function inRowViewRanges(ranges: IRange[], rowIndex: number) {
}

/**
* 如果 range 有相交, 那么扩展到第一个 range 中.
* 如果 range 有相交, 那么扩展到第一组 range 中.
* @param ranges
*/
export function mergeRangeIfIntersects(mainRanges: IRange[], ranges: IRange[]) {
Expand Down
5 changes: 4 additions & 1 deletion packages/engine-render/src/basics/vector2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,10 @@ export interface IViewportInfo {
*/
viewPortPosition: IBoundRectNoAngle;
viewPortKey: string;
isDirty?: boolean;
/**
* 后续会通过 number 来表示究竟是什么原因导致的标脏 这里采用二进制数值方便运算
*/
isDirty?: number;
isForceDirty?: boolean;

allowCache?: boolean;
Expand Down
4 changes: 2 additions & 2 deletions packages/engine-render/src/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,15 @@ export class Canvas {
// this.setHeight(height || 0);
this._pixelRatio = pixelRatioParam || getDevicePixelRatio();

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

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

this.getCanvasEle().style.width = `${this._width}px`;
}

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

this._height = this.getCanvasEle().height / this._pixelRatio;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export class Font extends SheetExtension {
/**
* 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;
Expand Down Expand Up @@ -346,7 +346,7 @@ export class Font extends SheetExtension {

ctx.rectByPrecision(startX, startY, endX - startX, endY - startY);
ctx.clip();
ctx.clearRectForTexture(startX, startY, endX - startX, endY - startY);
// ctx.clearRectForTexture(startX, startY, endX - startX, endY - startY);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1379,8 +1379,8 @@ export class SpreadsheetSkeleton extends Skeleton {
const row_ed = searchArray(rowHeightAccumulation, Math.round(viewBound.bottom) - this.columnHeaderHeightAndMarginTop);

if (row_st === -1 && row_ed === 0) {
dataset_row_st = -1;
dataset_row_ed = -1;
dataset_row_st = 0;
dataset_row_ed = 0;
} else {
if (row_st === -1) {
dataset_row_st = 0;
Expand All @@ -1401,8 +1401,8 @@ export class SpreadsheetSkeleton extends Skeleton {
const col_ed = searchArray(columnWidthAccumulation, Math.round(viewBound.right) - this.rowHeaderWidthAndMarginLeft);

if (col_st === -1 && col_ed === 0) {
dataset_col_st = -1;
dataset_col_ed = -1;
dataset_col_st = 0;
dataset_col_ed = 0;
} else {
if (col_st === -1) {
dataset_col_st = 0;
Expand Down
31 changes: 16 additions & 15 deletions packages/engine-render/src/components/sheets/spreadsheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ export class Spreadsheet extends SheetComponent {
this._fontExtension = null as unknown as Font;
}

/**
* 根据 viewport 绘制
* viewRange 根据 cacheBound 计算得到
* diffRange 根据 diffCacheBounds 得到
* @param ctx
* @param viewportInfo
* @returns
*/
override draw(ctx: UniverRenderingContext, viewportInfo: IViewportInfo) {
// const { parent = { scaleX: 1, scaleY: 1 } } = this;
// const mergeData = this.getMergeData();
Expand All @@ -123,7 +131,7 @@ export class Spreadsheet extends SheetComponent {

const parentScale = this.getParentScale();

const diffRanges = this._refreshIncrementalState && viewportInfo?.diffBounds
const diffRanges = this._refreshIncrementalState && viewportInfo?.diffCacheBounds
? viewportInfo?.diffBounds?.map((bound) => spreadsheetSkeleton.getRowColumnSegmentByViewBound(bound))
: undefined;
const viewRanges = [spreadsheetSkeleton.getRowColumnSegmentByViewBound(viewportInfo?.cacheBound)];
Expand Down Expand Up @@ -218,10 +226,8 @@ export class Spreadsheet extends SheetComponent {
}

/**
* canvas resize 并不会调用此函数
* resize 调用的是 forceDirty
* canvas resize calling not this function
* @param state
* @returns
*/
override makeDirty(state: boolean = true) {
super.makeDirty(state);
Expand All @@ -242,28 +248,23 @@ export class Spreadsheet extends SheetComponent {
const bufferEdgeSizeX = bufferEdgeX * scaleX / window.devicePixelRatio;
const bufferEdgeSizeY = bufferEdgeY * scaleY / window.devicePixelRatio;


const cacheCtx = cacheCanvas.getContext();
cacheCtx.save();

const { left, top, right, bottom } = viewPortPosition;

const dw = right - left + rowHeaderWidth;
const dh = bottom - top + columnHeaderHeight;


// 没有滚动
if (diffBounds.length === 0 || (diffX === 0 && diffY === 0) || isForceDirty) {
if (diffBounds.length === 0 || (diffX === 0 && diffY === 0) || isForceDirty || isDirty) {
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 (isDirty) {
this.paintNewAreaOfCacheCanvas(viewportBoundsInfo, {
cacheCanvas, cacheCtx, mainCtx, topOrigin, leftOrigin, bufferEdgeX, bufferEdgeY, scaleX, scaleY, columnHeaderHeight, rowHeaderWidth,
});
}
} 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);
}
cacheCtx.restore();
Expand Down
4 changes: 0 additions & 4 deletions packages/engine-render/src/scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,10 +471,6 @@ export class Scene extends ThinScene {
return this._viewports;
}

getSpreadSheetViewports() {
return this.getViewports().filter((v) => ['viewMain', 'viewMainLeftTop', 'viewMainTop', 'viewMainLeft'].includes(v.viewportKey));
}

getViewport(key: string) {
for (const viewport of this._viewports) {
if (viewport.viewportKey === key) {
Expand Down
117 changes: 53 additions & 64 deletions packages/engine-render/src/viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,6 @@ export class Viewport {
* @param objects
* @param isMaxLayer
* @param isLast
* @returns
*/
render(parentCtx?: UniverRenderingContext, objects: BaseObject[] = [], isMaxLayer = false, isLast = false) {
if (
Expand All @@ -673,24 +672,14 @@ export class Viewport {
if (this._renderClipState) {
mainCtx.beginPath();
// DEPT: left is set by upper views but width and height is not
// 这里用 (this.width || 0) * scale 反而出错了 选区不对
// 此刻 this.left 已经乘了 scale
// this.left has handle scale already, no need to `this.width * scale`
mainCtx.rect(this.left, this.top, (this.width || 0), (this.height || 0));
mainCtx.clip();
}

mainCtx.transform(tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]);
const viewPortInfo = this._calcViewportInfo();


// scrolling ---> make Dirty
if (viewPortInfo.diffX !== 0 || viewPortInfo.diffY !== 0 || viewPortInfo.diffBounds.length !== 0) {
this.markDirty();
viewPortInfo.isDirty = true;
}
viewPortInfo.cacheCanvas = this._cacheCanvas!;


objects.forEach((o) => {
o.render(mainCtx, viewPortInfo);
});
Expand Down Expand Up @@ -722,48 +711,54 @@ export class Viewport {
this._scrollRendered();
}


private _makeDefaultViewport() {
return {
viewBound: {
left: -1,
top: -1,
right: -1,
bottom: -1,
},
diffBounds: [],
diffX: -1,
diffY: -1,
viewPortPosition: {
top: 0,
left: 0,
bottom: 0,
right: 0,
},
viewPortKey: this.viewportKey,
// isDirty: this.isDirty,
isForceDirty: this.isForceDirty,
allowCache: false,
cacheBound: {
left: -1,
top: -1,
right: -1,
bottom: -1,
},
diffCacheBounds: [],
cacheViewPortPosition: {
top: 0,
left: 0,
bottom: 0,
right: 0,
},
shouldCacheUpdate: 0,
sceneTrans: Transform.create([1, 0, 0, 1, 0, 0]),
leftOrigin: 0,
topOrigin: 0,
bufferEdgeX: this.bufferEdgeX,
bufferEdgeY: this.bufferEdgeY,
} satisfies IViewportInfo;
}

// eslint-disable-next-line max-lines-per-function
private _calcViewportInfo(): IViewportInfo {
if (this.isActive === false) {
return {
viewBound: {
left: -1,
top: -1,
right: -1,
bottom: -1,
},
diffBounds: [],
diffX: -1,
diffY: -1,
viewPortPosition: {
top: 0,
left: 0,
bottom: 0,
right: 0,
},
viewPortKey: this.viewportKey,
isDirty: this.isDirty,
isForceDirty: this.isForceDirty,
allowCache: false,
cacheBound: {
left: -1,
top: -1,
right: -1,
bottom: -1,
},
diffCacheBounds: [],
cacheViewPortPosition: {
top: 0,
left: 0,
bottom: 0,
right: 0,
},
shouldCacheUpdate: 0,
sceneTrans: Transform.create([1, 0, 0, 1, 0, 0]),
leftOrigin: 0,
topOrigin: 0,
bufferEdgeX: this.bufferEdgeX,
bufferEdgeY: this.bufferEdgeY,
} satisfies IViewportInfo;
return this._makeDefaultViewport();
}

const sceneTrans = this._scene.transform.clone();
Expand Down Expand Up @@ -804,10 +799,6 @@ export class Viewport {

const viewBound = {
// 这里若对 top left 做 Math.floor 对 right bottom Math.ceil 操作, 放大后, 贴图会模糊
// top: parseFloat(topLeft.y.toFixed(3)),
// left: parseFloat(topLeft.x.toFixed(3)),
// right: parseFloat(bottomRight.x.toFixed(3)),
// bottom: parseFloat(bottomRight.y.toFixed(3)),
top: topLeft.y,
left: topLeft.x,
right: bottomRight.x,
Expand All @@ -833,7 +824,6 @@ export class Viewport {
const cacheViewPortPosition = this.expandBounds(viewPortPosition);

const shouldCacheUpdate = this._shouldCacheUpdate(viewBound, this._preCacheBound, diffX, diffY);
// console.log('shouldCacheUpdate', this.viewPortKey, shouldCacheUpdate);
if (shouldCacheUpdate) {
diffCacheBounds = this._calcDiffCacheBound(this._preCacheBound, cacheBound);
}
Expand All @@ -845,7 +835,7 @@ export class Viewport {
diffY,
viewPortPosition,
viewPortKey: this.viewportKey,
isDirty: this.isDirty,
isDirty: this.isDirty ? 0b10 : 0b00,
isForceDirty: this.isForceDirty,
allowCache: this._allowCache,
cacheBound: this.cacheBound,
Expand Down Expand Up @@ -881,18 +871,18 @@ export class Viewport {
return svCoord;
}


// eslint-disable-next-line complexity
onMouseWheel(evt: IWheelEvent, state: EventState) {
if (!this._scrollBar || this.isActive === false) {
return;
}
let isLimitedStore;
if (evt.inputIndex === PointerInput.MouseWheelX) {
const deltaFactor = Math.abs(evt.deltaX);
// let magicNumber = deltaFactor < 40 ? 2 : deltaFactor < 80 ? 3 : 4;
const allWidth = this._scene.width;
const viewWidth = this.width || 1;
const scrollNum = (viewWidth / allWidth) * deltaFactor;

if (evt.deltaX > 0) {
isLimitedStore = this.scrollBy({
x: scrollNum,
Expand Down Expand Up @@ -967,7 +957,6 @@ export class Viewport {
}
if (evt.inputIndex === PointerInput.MouseWheelZ) {
// TODO
// ...
}

this._scene.makeDirty(true);
Expand Down Expand Up @@ -1084,15 +1073,13 @@ export class Viewport {

private _resizeCacheCanvasAndScrollBar() {
const actualScrollX = this.actualScrollX;

const actualScrollY = this.actualScrollY;
const { width, height, parentHeight } = this._getViewPortSize();
const { width, height } = this._getViewPortSize();

const scaleX = this.scene.scaleX;
const scaleY = this.scene.scaleY;
const canvasW = width !== 0 ? width + this.bufferEdgeX * 2 * scaleX : 0;
const canvasH = height !== 0 ? height + this.bufferEdgeY * 2 * scaleY : 0;

this._cacheCanvas?.setSize(canvasW, canvasH);

const contentWidth = (this._scene.width - this._paddingEndX) * this._scene.scaleX;
Expand Down Expand Up @@ -1135,6 +1122,8 @@ export class Viewport {
} else {
height = (this._heightOrigin || 0) * scaleY;
}
width = Math.max(0, width);
height = Math.max(0, height);

this._width = width;
this._height = height;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,8 @@ export class SheetRenderController extends RxDisposable {
scene.makeDirty();
if (!command.params) return;
const cmdParams = command.params as Record<string, any>;
const viewports = scene.getSpreadSheetViewports();
// 还有个概念和这个很像, SetRangeValuesCommand
const viewports = scene.getViewports().filter((v) => ['viewMain', 'viewMainLeftTop', 'viewMainTop', 'viewMainLeft'].includes(v.viewportKey));
if (command.id === SetRangeValuesMutation.id && cmdParams.cellValue) {
// TODO command.params 数据结构有很多种
const dirtyRange: IRange = this._cellValueToRange(cmdParams.cellValue);
const dirtyBounds = this._rangeToBounds([dirtyRange]);
this.markViewportDirty(viewports, dirtyBounds);
Expand Down