From 97698b8cca11b903d3d29bffe726d9e1e716306d Mon Sep 17 00:00:00 2001 From: lumix Date: Mon, 3 Jun 2024 14:02:36 +0800 Subject: [PATCH 1/3] feat: add scrollLeftTop for sheet snapshot (#2348) * feat: add scrollLeftTop for sheet snapshot * fix: set-frozen test case need ScrollManagerService -> SheetSkeletonManagerService * fix: switch tab sync state in scene and viewport fix: revert back _updateViewZoom chore: import SHEET_VIEWPORT_KEY from engine-render --- .../src/controllers/back-scroll.controller.ts | 2 +- .../doc-editor-bridge.controller.ts | 4 +- .../src/controllers/zoom.controller.ts | 2 +- .../engine-render/src/basics/scroll-xy.ts | 6 +- .../src/components/sheets/spreadsheet.ts | 4 - packages/engine-render/src/scene.ts | 2 +- packages/engine-render/src/scroll-timer.ts | 2 +- packages/engine-render/src/viewport.ts | 208 +++++++++++------- .../canvas-float-dom-manager.service.ts | 20 +- .../__tests__/create-command-test-bed.ts | 3 +- .../create-selection-command-test-bed.ts | 4 +- .../__tests__/set-frozen.command.spec.ts | 4 +- .../commands/commands/set-frozen.command.ts | 2 +- .../commands/commands/set-scroll.command.ts | 12 +- .../commands/operations/scroll.operation.ts | 5 +- packages/sheets-ui/src/common/keys.ts | 2 +- packages/sheets-ui/src/common/utils.ts | 21 +- .../editor/formula-editor.controller.ts | 8 +- .../editor/start-edit.controller.ts | 12 +- .../freeze.render-controller.ts | 84 +++---- .../header-move.render-controller.ts | 7 +- .../header-resize.render-controller.ts | 6 +- .../scroll.render-controller.ts | 149 +++++++++---- .../selection.render-controller.ts | 6 +- .../src/controllers/utils/component-tools.ts | 6 +- packages/sheets-ui/src/index.ts | 2 +- .../src/services/drag-manager.service.ts | 3 +- .../src/services/hover-manager.service.ts | 2 +- .../src/services/scroll-manager.service.ts | 140 +++++++++--- .../selection/selection-render.service.ts | 37 ++-- .../selection/selection-shape-extension.ts | 27 ++- .../sheet-skeleton-manager.service.ts | 13 +- packages/sheets-ui/src/sheets-ui-plugin.ts | 2 +- .../src/controllers/zen-editor.controller.ts | 9 +- .../src/views/render/adaptors/docs-adaptor.ts | 2 +- .../render/adaptors/spreadsheet-adaptor.ts | 6 +- .../slides/src/views/render/canvas-view.ts | 2 +- 37 files changed, 503 insertions(+), 323 deletions(-) diff --git a/packages/docs-ui/src/controllers/back-scroll.controller.ts b/packages/docs-ui/src/controllers/back-scroll.controller.ts index 03a70f5d952..19e885d6249 100644 --- a/packages/docs-ui/src/controllers/back-scroll.controller.ts +++ b/packages/docs-ui/src/controllers/back-scroll.controller.ts @@ -112,7 +112,7 @@ export class BackScrollController extends RxDisposable { offsetX = left - boundRight + ANCHOR_WIDTH; } - const config = viewportMain.getBarScroll(offsetX, offsetY); + const config = viewportMain.transViewportScroll2ScrollValue(offsetX, offsetY); viewportMain.scrollBy(config); } diff --git a/packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts b/packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts index d2d32e9176f..40b9bb90915 100644 --- a/packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts +++ b/packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts @@ -120,7 +120,7 @@ export class DocEditorBridgeController extends Disposable { if (scrollBar == null) { viewportMain && new ScrollBar(viewportMain, { enableHorizontal: false, barSize: 8 }); } else { - viewportMain?.resetSizeAndScrollBar(); + viewportMain?.resetCanvasSizeAndUpdateScrollBar(); } } else { scrollBar = null; @@ -132,7 +132,7 @@ export class DocEditorBridgeController extends Disposable { if (scrollBar == null) { viewportMain && new ScrollBar(viewportMain, { barSize: 8, enableVertical: false }); } else { - viewportMain?.resetSizeAndScrollBar(); + viewportMain?.resetCanvasSizeAndUpdateScrollBar(); } } else { scrollBar = null; diff --git a/packages/docs-ui/src/controllers/zoom.controller.ts b/packages/docs-ui/src/controllers/zoom.controller.ts index 30d07efac6d..88373a2fb09 100644 --- a/packages/docs-ui/src/controllers/zoom.controller.ts +++ b/packages/docs-ui/src/controllers/zoom.controller.ts @@ -240,7 +240,7 @@ export class ZoomController extends Disposable { const viewport = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); if (scrollToX !== Number.POSITIVE_INFINITY && viewport != null) { - const actualX = viewport.getBarScroll(scrollToX, 0).x; + const actualX = viewport.transViewportScroll2ScrollValue(scrollToX, 0).x; viewport.scrollTo({ x: actualX, }); diff --git a/packages/engine-render/src/basics/scroll-xy.ts b/packages/engine-render/src/basics/scroll-xy.ts index 84cada083f8..98e6cc1fe7d 100644 --- a/packages/engine-render/src/basics/scroll-xy.ts +++ b/packages/engine-render/src/basics/scroll-xy.ts @@ -14,9 +14,11 @@ * limitations under the License. */ +import type { Viewport } from '../viewport'; + export function getCurrentScrollXY(scrollTimer: any) { const scene = scrollTimer.getScene(); - const viewport = scrollTimer.getViewportByCoord(scene); + const viewport = scrollTimer.getViewportByCoord(scene) as Viewport; const scrollX = 0; const scrollY = 0; if (!viewport) { @@ -25,7 +27,7 @@ export function getCurrentScrollXY(scrollTimer: any) { scrollY, }; } - const actualScroll = viewport.getActualScroll(viewport.scrollX, viewport.scrollY); + const actualScroll = viewport.transScroll2ViewportScrollValue(viewport.scrollX, viewport.scrollY); return { scrollX: actualScroll.x, scrollY: actualScroll.y, diff --git a/packages/engine-render/src/components/sheets/spreadsheet.ts b/packages/engine-render/src/components/sheets/spreadsheet.ts index 1a6ff47c021..4f75e44cab9 100644 --- a/packages/engine-render/src/components/sheets/spreadsheet.ts +++ b/packages/engine-render/src/components/sheets/spreadsheet.ts @@ -705,10 +705,6 @@ export class Spreadsheet extends SheetComponent { const spreadsheetSkeleton = this.getSkeleton()!; const { rowHeaderWidth, columnHeaderHeight } = spreadsheetSkeleton; const { left, top, right, bottom } = cacheBound; - // left -= rowHeaderWidth; - // top -= columnHeaderHeight; - // right -= rowHeaderWidth; - // bottom -= columnHeaderHeight; const findClosestHundred = (number: number) => { const remainder = number % 100; return number + (100 - remainder); diff --git a/packages/engine-render/src/scene.ts b/packages/engine-render/src/scene.ts index 777d45efd1e..28b0f8e4ccb 100644 --- a/packages/engine-render/src/scene.ts +++ b/packages/engine-render/src/scene.ts @@ -958,7 +958,7 @@ export class Scene extends ThinScene { this.transform = composeResult; this.getViewports().forEach((vp: Viewport) => { - vp.resetSizeAndScrollBar(); + vp.resetCanvasSizeAndUpdateScrollBar(); }); this.makeDirty(true); } diff --git a/packages/engine-render/src/scroll-timer.ts b/packages/engine-render/src/scroll-timer.ts index 80b2f84e615..b645454e7aa 100644 --- a/packages/engine-render/src/scroll-timer.ts +++ b/packages/engine-render/src/scroll-timer.ts @@ -143,7 +143,7 @@ export class ScrollTimer { y, }); - const actualScroll = viewport?.getActualScroll(x, y); + const actualScroll = viewport?.transScroll2ViewportScrollValue(x, y); this._scrollX = actualScroll?.x || 0; this._scrollY = actualScroll?.y || 0; diff --git a/packages/engine-render/src/viewport.ts b/packages/engine-render/src/viewport.ts index 18c315b0e10..a022d59b6e5 100644 --- a/packages/engine-render/src/viewport.ts +++ b/packages/engine-render/src/viewport.ts @@ -68,8 +68,8 @@ export interface IScrollObserverParam { /** * scrollX for viewport */ - actualScrollX?: number; - actualScrollY?: number; + viewportScrollX?: number; + viewportScrollY?: number; limitX?: number; limitY?: number; isTrigger?: boolean; @@ -94,19 +94,19 @@ export class Viewport { */ scrollX: number = 0; scrollY: number = 0; - _preScrollX: number = 0; - _preScrollY: number = 0; + private _preScrollX: number = 0; + private _preScrollY: number = 0; /** - * The actual scroll offset equals the distance from the content area position to the top, and there is a conversion relationship with scrollX and scrollY - * use getActualScroll to get scrolling value for spreadsheet. + * The viewport scroll offset equals the distance from the content area position to the top, and there is a conversion relationship with scrollX and scrollY + * use transScroll2ViewportScrollValue to get scrolling value for spreadsheet. */ - viewportScrollX: number = 0; - viewportScrollY: number = 0; - preViewportScrollX: number = 0; - preViewportScrollY: number = 0; - _deltaViewportScrollX: number = 0; - _deltaViewportScrollY: number = 0; + private _viewportScrollX: number = 0; + private _viewportScrollY: number = 0; + private _preViewportScrollX: number = 0; + private _preViewportScrollY: number = 0; + private _deltaViewportScrollX: number = 0; + private _deltaViewportScrollY: number = 0; onMouseWheelObserver = new Observable(); @@ -239,13 +239,13 @@ export class Viewport { this._isRelativeY = props.isRelativeY; } - this._setWithAndHeight(props); + this._setViewportWidthAndHeight(props); this.initCacheCanvas(props); this._isWheelPreventDefaultX = props?.isWheelPreventDefaultX || false; this._isWheelPreventDefaultY = props?.isWheelPreventDefaultY || false; - this._resizeCacheCanvas(); + this.resetCanvasSizeAndUpdateScrollBar(); this.getBounding(); this.scene.getEngine()?.onTransformChangeObservable.add(() => { @@ -374,6 +374,22 @@ export class Viewport { return this._active; } + set viewportScrollX(val: number) { + this._viewportScrollX = val; + } + + get viewportScrollX() { + return this._viewportScrollX; + } + + set viewportScrollY(val: number) { + this._viewportScrollY = val; + } + + get viewportScrollY() { + return this._viewportScrollY; + } + private set top(num: number) { this._topOrigin = num; this._top = toPx(num, this._scene?.getParent()?.height); @@ -424,15 +440,16 @@ export class Viewport { } /** - * 物理 canvas 大小改变时调用(调整 window 大小时触发) + * call when canvas element size change */ - resetSizeAndScrollBar() { + resetCanvasSizeAndUpdateScrollBar() { this._resizeCacheCanvas(); + this._updateScrollBarPosByViewportScroll(); } setScrollBar(instance: BaseScrollBar) { this._scrollBar = instance; - this._resizeCacheCanvas(); + this._updateScrollBarPosByViewportScroll(); } removeScrollBar() { @@ -440,7 +457,7 @@ export class Viewport { } /** - * 和 resetSizeAndScrollBar 不同 + * 和 resetCanvasSizeAndScrollbar 不同 * 此方法是调整冻结行列设置时 & 初始化时触发, resize window 时并不会触发 * * 注意参数 position 不一定有 height & width 对于 viewMain 只有 left top bottom right @@ -460,8 +477,8 @@ export class Viewport { // (this as IKeyValue)[pKey] = position[pKey as keyof IViewPosition]; // } // }); - this._setWithAndHeight(position); - this._resizeCacheCanvas(); + this._setViewportWidthAndHeight(position); + this.resetCanvasSizeAndUpdateScrollBar(); } setPadding(param: IPosition) { @@ -471,7 +488,7 @@ export class Viewport { this._paddingStartY = startY; this._paddingEndY = endY; - this._resizeCacheCanvas(); + this.resetCanvasSizeAndUpdateScrollBar(); } resetPadding() { @@ -484,32 +501,40 @@ export class Viewport { } /** + * set scrollXY and viewportScrollXY, and update scrollInfo without notify listeners of scrollInfo$ + * mainly call by scroll.render-controller and viewport.resize ... + * only viewMain would call scrollTo, other views did not call scroll, see scroll.render-controller + * @param pos + * + * when scrolling: + * + * scroll.render-controller@_scrollManagerService.scrollInfo$.subscribe --> scrollTo * - * 改动 scrollbar 的位置,不是 viewport content 滚动 - * scroll to position, absolute - * 只有 viewMain 才会被调用 scrollTo 其他 viewport 都不会调用此方法 - * 具体在 scroll.controller 中 + * when change skelenton: + * _currentSkeletonBefore$ ---> scroll.render-controller@_updateSceneSize --> setSearchParam --> scene@_setTransForm ---> viewport.resetCanvasSizeAndUpdateScrollBar ---> scrollTo ---> _scroll + * --> onScrollAfterObserver.notifyObservers --> scroll.render-controller@onScrollAfterObserver ---> setScrollInfoToCurrSheetWithoutNotify ---> sms._setScrollInfo * + * _currentSkeleton$ ---> selection.render-controller ---> formula@_autoScroll ---> viewport.resize ---> get scrollXY by viewportScrollXY ---> scrollTo + * _currentSkeleton$ ---> selection.render-controller ---> setCurrentSelection ---> formula@_autoScroll ---> scrollTo + * _currentSkeleton$ ---> freeze.render-controller@_refreshFreeze --> viewport.resize ---> scrollTo ---> _scroll * Debug * window.scene.getViewports()[0].scrollTo({x: 14.2, y: 1.8}, true) - * @param pos - * @returns */ - scrollTo(pos: IScrollBarPosition, isTrigger = true) { - return this._scroll(SCROLL_TYPE.scrollTo, pos, isTrigger); + scrollTo(pos: IScrollBarPosition) { + return this._scrollToScrollbarPos(SCROLL_TYPE.scrollTo, pos); } /** * current position plus offset, relative * @param pos - * @returns + * @returns isLimited */ scrollBy(pos: IScrollBarPosition, isTrigger = true) { - return this._scroll(SCROLL_TYPE.scrollBy, pos, isTrigger); + return this._scrollToScrollbarPos(SCROLL_TYPE.scrollBy, pos, isTrigger); } scrollByBar(pos: IScrollBarPosition, isTrigger = true) { - this._scroll(SCROLL_TYPE.scrollBy, pos, isTrigger); + this._scrollToScrollbarPos(SCROLL_TYPE.scrollBy, pos, isTrigger); const { x, y } = pos; this.onScrollByBarObserver.notifyObservers({ viewport: this, @@ -517,8 +542,8 @@ export class Viewport { scrollY: this.scrollY, x, y, - actualScrollX: this.viewportScrollX, - actualScrollY: this.viewportScrollY, + viewportScrollX: this.viewportScrollX, + viewportScrollY: this.viewportScrollY, limitX: this._scrollBar?.limitX, limitY: this._scrollBar?.limitY, isTrigger, @@ -539,13 +564,13 @@ export class Viewport { } const x = offsetX + this._paddingStartX; const y = offsetY + this._paddingStartY; - const param = this.getBarScroll(x, y); + const param = this.transViewportScroll2ScrollValue(x, y); return this.scrollBy(param, isTrigger); } - getBarScroll(actualX: number, actualY: number) { - let x = actualX - this._paddingStartX; - let y = actualY - this._paddingStartY; + transViewportScroll2ScrollValue(viewportScrollX: number, viewportScrollY: number) { + let x = viewportScrollX - this._paddingStartX; + let y = viewportScrollY - this._paddingStartY; if (this._scrollBar) { x *= this._scrollBar.ratioScrollX; // convert to scroll coord @@ -569,7 +594,7 @@ export class Viewport { }; } - getActualScroll(scrollX: number, scrollY: number) { + transScroll2ViewportScrollValue(scrollX: number, scrollY: number) { let x = scrollX; let y = scrollY; if (this._scrollBar) { @@ -622,25 +647,25 @@ export class Viewport { * get actual scroll value by scrollXY * @returns */ - getTransformedScroll() { + getViewportScrollByScroll() { const x = this.scrollX; const y = this.scrollY; - return this.getActualScroll(x, y); + return this.transScroll2ViewportScrollValue(x, y); } getScrollBar() { return this._scrollBar; } - // _scrollTo ---> _scroll ---> onScrollAfterObserver.notifyObservers ---> updateScroll - updateScroll(param: IScrollObserverParam) { + // scrollTo ---> _scroll ---> onScrollAfterObserver.notifyObservers ---> scroll.render-controller@updateScroll + updateScroll(current: IScrollObserverParam) { // scrollvalue for scrollbar, when rows over 5000(big sheet), deltaScrollY always 0 when scrolling. Do not use this value to judge scrolling // this._deltaScrollX = this.scrollX - this._preScrollX; // this._deltaScrollY = this.scrollY - this._preScrollY; this._preScrollX = this.scrollX; this._preScrollY = this.scrollY; - const { scrollX, scrollY, actualScrollX, actualScrollY } = param; + const { scrollX, scrollY, viewportScrollX, viewportScrollY } = current; if (scrollX !== undefined) { this.scrollX = scrollX; } @@ -649,16 +674,16 @@ export class Viewport { this.scrollY = scrollY; } - if (actualScrollX !== undefined) { - this.preViewportScrollX = this.viewportScrollX; - this.viewportScrollX = actualScrollX; - this._deltaViewportScrollX = actualScrollX - this.preViewportScrollX; + if (viewportScrollX !== undefined) { + this._preViewportScrollX = this.viewportScrollX; + this.viewportScrollX = viewportScrollX; + this._deltaViewportScrollX = viewportScrollX - this._preViewportScrollX; } - if (actualScrollY !== undefined) { - this.preViewportScrollY = this.viewportScrollY; - this.viewportScrollY = actualScrollY; - this._deltaViewportScrollY = actualScrollY - this.preViewportScrollY; + if (viewportScrollY !== undefined) { + this._preViewportScrollY = this.viewportScrollY; + this.viewportScrollY = viewportScrollY; + this._deltaViewportScrollY = viewportScrollY - this._preViewportScrollY; } return this; } @@ -739,8 +764,8 @@ export class Viewport { this._drawScrollbar(mainCtx); mainCtx.restore(); } - - this._scrollRendered(); + // TODO @lumix, preScrollX is also handled by updateScroll(), this method is empty. + this._afterRender(); } private _makeDefaultViewport() { @@ -901,7 +926,7 @@ export class Viewport { getRelativeVector(coord: Vector2) { const sceneTrans = this.scene.transform.clone().invert(); - const scroll = this.getTransformedScroll(); + const scroll = this.getViewportScrollByScroll(); const svCoord = sceneTrans.applyPoint(coord).add(Vector2.FromArray([scroll.x, scroll.y])); return svCoord; @@ -909,7 +934,7 @@ export class Viewport { getAbsoluteVector(coord: Vector2) { const sceneTrans = this.scene.transform.clone(); - const scroll = this.getTransformedScroll(); + const scroll = this.getViewportScrollByScroll(); const svCoord = sceneTrans.applyPoint(coord.subtract(Vector2.FromArray([scroll.x, scroll.y]))); return svCoord; @@ -1114,9 +1139,10 @@ export class Viewport { return this._isForceDirty; } + /** + * resize canvas & use viewportScrollXY to scrollTo + */ private _resizeCacheCanvas() { - const actualScrollX = this.viewportScrollX; - const actualScrollY = this.viewportScrollY; const { width, height } = this._getViewPortSize(); const scaleX = this.scene.scaleX; @@ -1127,12 +1153,19 @@ export class Viewport { this.cacheBound = this._viewBound; this.preCacheBound = null; + this.markForceDirty(true); + } + + private _updateScrollBarPosByViewportScroll() { + const viewportScrollX = this.viewportScrollX; + const viewportScrollY = this.viewportScrollY; + const { width, height } = this._getViewPortSize(); const contentWidth = (this._scene.width - this._paddingEndX) * this._scene.scaleX; const contentHeight = (this._scene.height - this._paddingEndY) * this._scene.scaleY; if (this._scrollBar) { this._scrollBar.resize(width, height, contentWidth, contentHeight); - const { x, y } = this.getBarScroll(actualScrollX, actualScrollY); + const { x, y } = this.transViewportScroll2ScrollValue(viewportScrollX, viewportScrollY); this.scrollTo({ x, y, @@ -1198,9 +1231,12 @@ export class Viewport { }; } - private _scrollRendered() { - this._preScrollX = this.scrollX; - this._preScrollY = this.scrollY; + /** + * update pre scroll value has handled in updateScroll() + */ + private _afterRender() { + // this._preScrollX = this.scrollX; + // this._preScrollY = this.scrollY; } private _triggerScrollStop( @@ -1208,9 +1244,8 @@ export class Viewport { x: number; y: number; }, - x?: number, - y?: number, - isTrigger = true + scollBarX?: number, + scrollBarY?: number, ) { clearTimeout(this._scrollStopNum); this._scrollStopNum = setTimeout(() => { @@ -1218,13 +1253,13 @@ export class Viewport { viewport: this, scrollX: this.scrollX, scrollY: this.scrollY, - x, - y, - actualScrollX: scroll.x, - actualScrollY: scroll.y, + x: scollBarX, + y: scrollBarY, + viewportScrollX: scroll.x, + viewportScrollY: scroll.y, limitX: this._scrollBar?.limitX, limitY: this._scrollBar?.limitY, - isTrigger, + isTrigger: false }); }, 2); } @@ -1233,13 +1268,14 @@ export class Viewport { * Scroll Viewport * Only the 'viewMain' will enter this function, other viewports will not. * - * caller: scroll.controller viewportMain.proscrollTo(config) + * caller: scroll.render-controller viewportMain.scrollTo({x, y})) + * this._scrollManagerService.scrollInfo$.subscribe --> scrollTo --> _scroll * @param scrollType - * @param pos viewMain 滚动条的位置 + * @param scrollBarPos viewMain 滚动条的位置 * @param isTrigger */ - private _scroll(scrollType: SCROLL_TYPE, pos: IScrollBarPosition, isTrigger = true) { - const { x, y } = pos; + private _scrollToScrollbarPos(scrollType: SCROLL_TYPE, scrollBarPos: IScrollBarPosition, isTrigger: boolean = true) { + const { x, y } = scrollBarPos; if (this._scrollBar == null) { return; } @@ -1284,24 +1320,27 @@ export class Viewport { this._scrollBar.makeDirty(true); } - const scroll = this.getTransformedScroll(); - this.viewportScrollX = scroll.x; - this.viewportScrollY = scroll.y; + const clampedViewportScroll = this.getViewportScrollByScroll(); + this.viewportScrollX = clampedViewportScroll.x; + this.viewportScrollY = clampedViewportScroll.y; + // scroll.render-controller@onScrollAfterObserver ---> setScrollInfo but no notify + // calc startRow & offset by viewportScrollXY, then update scrollInfo + // other viewports, rowHeader & colHeader depend on this notify this.onScrollAfterObserver.notifyObservers({ + isTrigger, viewport: this, - scrollX: this.scrollX, - scrollY: this.scrollY, x, y, - actualScrollX: scroll.x, - actualScrollY: scroll.y, + scrollX: this.scrollX, + scrollY: this.scrollY, + viewportScrollX: clampedViewportScroll.x, + viewportScrollY: clampedViewportScroll.y, limitX: this._scrollBar?.limitX, limitY: this._scrollBar?.limitY, - isTrigger, }); - this._triggerScrollStop(scroll, x, y, isTrigger); + this._triggerScrollStop(clampedViewportScroll, x, y); return limited; } @@ -1347,7 +1386,6 @@ export class Viewport { : 0b00; const shouldCacheUpdate = nearEdge | viewBoundOutCacheArea; - // console.log(`shouldCacheUpdate${shouldCacheUpdate}`, `${this.viewportKey}:`, this.preCacheBound, this.cacheBound, this.viewBound, this._preCacheVisibleBound); return shouldCacheUpdate; } @@ -1448,7 +1486,7 @@ export class Viewport { } } - private _setWithAndHeight(props?: IViewProps) { + private _setViewportWidthAndHeight(props?: IViewProps) { if (props?.top != null) { this.top = props.top; } diff --git a/packages/sheets-drawing-ui/src/services/canvas-float-dom-manager.service.ts b/packages/sheets-drawing-ui/src/services/canvas-float-dom-manager.service.ts index 39241e7c272..3e8b5bf9f87 100644 --- a/packages/sheets-drawing-ui/src/services/canvas-float-dom-manager.service.ts +++ b/packages/sheets-drawing-ui/src/services/canvas-float-dom-manager.service.ts @@ -16,22 +16,22 @@ import type { IPosition, ITransformState, Nullable, Worksheet } from '@univerjs/core'; import { Disposable, DisposableCollection, DrawingTypeEnum, ICommandService, IUniverInstanceService, Tools } from '@univerjs/core'; -import type { BaseObject, IBoundRectNoAngle, IRectProps, IRender, Scene, SpreadsheetSkeleton } from '@univerjs/engine-render'; -import { DRAWING_OBJECT_LAYER_INDEX, IRenderManagerService, Rect } from '@univerjs/engine-render'; -import type { IFloatDomLayout } from '@univerjs/ui'; -import { CanvasFloatDomService } from '@univerjs/ui'; -import type { IDisposable } from '@wendellhu/redi'; -import { Inject } from '@wendellhu/redi'; -import { BehaviorSubject, Subject } from 'rxjs'; import type { IDrawingJsonUndo1 } from '@univerjs/drawing'; import { getDrawingShapeKeyByDrawingSearch, IDrawingManagerService } from '@univerjs/drawing'; -import { ISelectionRenderService, SetScrollOperation, SetZoomRatioOperation, SheetSkeletonManagerService, VIEWPORT_KEY } from '@univerjs/sheets-ui'; +import type { BaseObject, IBoundRectNoAngle, IRectProps, IRender, Scene, SpreadsheetSkeleton } from '@univerjs/engine-render'; +import { DRAWING_OBJECT_LAYER_INDEX, IRenderManagerService, Rect, SHEET_VIEWPORT_KEY } from '@univerjs/engine-render'; import type { ISetFrozenMutationParams } from '@univerjs/sheets'; import { getSheetCommandTarget, SetFrozenMutation } from '@univerjs/sheets'; import type { IFloatDomData, ISheetDrawingPosition, ISheetFloatDom } from '@univerjs/sheets-drawing'; import { DrawingApplyType, ISheetDrawingService, SetDrawingApplyMutation } from '@univerjs/sheets-drawing'; -import type { IInsertDrawingCommandParams } from '../commands/commands/interfaces'; +import { ISelectionRenderService, SetScrollOperation, SetZoomRatioOperation, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; +import type { IFloatDomLayout } from '@univerjs/ui'; +import { CanvasFloatDomService } from '@univerjs/ui'; +import type { IDisposable } from '@wendellhu/redi'; +import { Inject } from '@wendellhu/redi'; +import { BehaviorSubject, Subject } from 'rxjs'; import { InsertSheetDrawingCommand } from '../commands/commands/insert-sheet-drawing.command'; +import type { IInsertDrawingCommandParams } from '../commands/commands/interfaces'; export interface ICanvasFloatDom { allowTransform: boolean; @@ -51,7 +51,7 @@ interface ICanvasFloatDomInfo { export function transformBound2DOMBound(originBound: IBoundRectNoAngle, scene: Scene, skeleton: SpreadsheetSkeleton, worksheet: Worksheet) { const { scaleX, scaleY } = scene.getAncestorScale(); - const viewMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); const absolute = { left: true, top: true, diff --git a/packages/sheets-ui/src/commands/commands/__tests__/create-command-test-bed.ts b/packages/sheets-ui/src/commands/commands/__tests__/create-command-test-bed.ts index 68838621b93..73ffd234aab 100644 --- a/packages/sheets-ui/src/commands/commands/__tests__/create-command-test-bed.ts +++ b/packages/sheets-ui/src/commands/commands/__tests__/create-command-test-bed.ts @@ -23,6 +23,7 @@ import { LocaleType, LogLevel, Plugin, + Tools, Univer, UniverInstanceType, } from '@univerjs/core'; @@ -112,7 +113,7 @@ export function createCommandTestBed(workbookData?: IWorkbookData, dependencies? } univer.registerPlugin(TestPlugin); - const sheet = univer.createUniverSheet(workbookData || getTestWorkbookDataDemo()); + const sheet = univer.createUniverSheet(Tools.deepClone(workbookData || getTestWorkbookDataDemo())); const univerInstanceService = injector.get(IUniverInstanceService); univerInstanceService.focusUnit('test'); diff --git a/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts b/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts index c4a0f18db54..afb19dc78f3 100644 --- a/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts +++ b/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts @@ -18,9 +18,9 @@ import type { IWorkbookData } from '@univerjs/core'; import { ICommandService, LocaleType } from '@univerjs/core'; import { SetFrozenMutation, SetSelectionsOperation } from '@univerjs/sheets'; // FIXME: should not import from the inside of the package -import { createCommandTestBed } from '@univerjs/sheets/commands/commands/__tests__/create-command-test-bed.js'; import { ScrollManagerService } from '../../../services/scroll-manager.service'; +import { SheetSkeletonManagerService } from '../../../services/sheet-skeleton-manager.service'; import { ShortcutExperienceService } from '../../../services/shortcut-experience.service'; import { CancelFrozenCommand, @@ -29,6 +29,7 @@ import { SetSelectionFrozenCommand, } from '../set-frozen.command'; import { ExpandSelectionCommand, MoveSelectionCommand, SelectAllCommand } from '../set-selection.command'; +import { createCommandTestBed } from './create-command-test-bed'; export function createSelectionCommandTestBed(workbookData?: IWorkbookData) { const { univer, get, sheet } = createCommandTestBed(workbookData || SIMPLE_SELECTION_WORKBOOK_DATA, [ @@ -51,6 +52,7 @@ export function createFrozenCommandTestBed(workbookData?: IWorkbookData) { const { univer, get, sheet } = createCommandTestBed(workbookData || SIMPLE_SELECTION_WORKBOOK_DATA, [ [ShortcutExperienceService], [ScrollManagerService], + [SheetSkeletonManagerService], ]); const commandService = get(ICommandService); diff --git a/packages/sheets-ui/src/commands/commands/__tests__/set-frozen.command.spec.ts b/packages/sheets-ui/src/commands/commands/__tests__/set-frozen.command.spec.ts index 8848f9d8fef..c53bc49e7eb 100644 --- a/packages/sheets-ui/src/commands/commands/__tests__/set-frozen.command.spec.ts +++ b/packages/sheets-ui/src/commands/commands/__tests__/set-frozen.command.spec.ts @@ -75,7 +75,7 @@ describe('Test commands used for change selections', () => { } const scrollTo = (startRow: number, startColumn: number, offsetX = 0, offsetY = 0) => { - scrollManagerService.addOrReplaceByParam({ + scrollManagerService.setScrollInfoToCurrSheet({ sheetViewStartRow: startRow, sheetViewStartColumn: startColumn, offsetX, @@ -108,7 +108,7 @@ describe('Test commands used for change selections', () => { ...currentInfo, }); scrollManagerService = get(ScrollManagerService); - scrollManagerService.setCurrentScroll({ + scrollManagerService.setSearchParamAndRefresh({ ...currentInfo, }); } diff --git a/packages/sheets-ui/src/commands/commands/set-frozen.command.ts b/packages/sheets-ui/src/commands/commands/set-frozen.command.ts index 0dff6db4147..7023a78f484 100644 --- a/packages/sheets-ui/src/commands/commands/set-frozen.command.ts +++ b/packages/sheets-ui/src/commands/commands/set-frozen.command.ts @@ -51,7 +51,7 @@ export const SetSelectionFrozenCommand: ICommand = { id: 'sheet.command.set-scroll-relative', type: CommandType.COMMAND, + // offsetXY derived from mouse wheel event handler: async (accessor, params = { offsetX: 0, offsetY: 0 }) => { const commandService = accessor.get(ICommandService); const scrollManagerService = accessor.get(ScrollManagerService); @@ -44,7 +47,7 @@ export const SetScrollRelativeCommand: ICommand const { unitId, subUnitId, worksheet } = target; const { xSplit, ySplit } = worksheet.getConfig().freeze; - const currentScroll = scrollManagerService.getCurrentScroll(); + const currentScroll = scrollManagerService.getCurrentScrollInfo(); const { offsetX = 0, offsetY = 0 } = params || {}; const { sheetViewStartRow = 0, @@ -58,7 +61,7 @@ export const SetScrollRelativeCommand: ICommand sheetId: subUnitId, sheetViewStartRow: sheetViewStartRow + ySplit, sheetViewStartColumn: sheetViewStartColumn + xSplit, - offsetX: currentOffsetX + offsetX, + offsetX: currentOffsetX + offsetX, // offsetX may be negative or over max offsetY: currentOffsetY + offsetY, }); }, @@ -73,6 +76,7 @@ export interface IScrollCommandParams { /** * This command is used to manage the scroll position of the current view by specifying the cell index of the top left cell + * Usually triggered by click scrollbar or moving selection range. */ export const ScrollCommand: ICommand = { id: 'sheet.command.scroll-view', @@ -89,7 +93,7 @@ export const ScrollCommand: ICommand = { if (!target) return false; const { workbook, worksheet } = target; - const currentScroll = scrollManagerService.getCurrentScroll(); + const currentScroll: Readonly> = scrollManagerService.getCurrentScrollInfo(); if (!worksheet) { return false; diff --git a/packages/sheets-ui/src/commands/operations/scroll.operation.ts b/packages/sheets-ui/src/commands/operations/scroll.operation.ts index 46bd1db2e1d..2e1c7e2adbf 100644 --- a/packages/sheets-ui/src/commands/operations/scroll.operation.ts +++ b/packages/sheets-ui/src/commands/operations/scroll.operation.ts @@ -22,10 +22,9 @@ import { ScrollManagerService } from '../../services/scroll-manager.service'; export const SetScrollOperation: IOperation = { id: 'sheet.operation.set-scroll', - type: CommandType.OPERATION, - handler: (accessor, params) => { + handler: (accessor, params: IScrollManagerInsertParam) => { if (params == null) { return false; } @@ -36,7 +35,7 @@ export const SetScrollOperation: IOperation = { const worksheet = workbook!.getSheetBySheetId(params!.sheetId); const { xSplit, ySplit } = worksheet!.getConfig().freeze; - scrollManagerService.addOrReplaceByParam({ + scrollManagerService.setScrollInfo({ ...params, sheetViewStartRow: params.sheetViewStartRow - ySplit, sheetViewStartColumn: params.sheetViewStartColumn - xSplit, diff --git a/packages/sheets-ui/src/common/keys.ts b/packages/sheets-ui/src/common/keys.ts index f68be992342..e3801873b96 100644 --- a/packages/sheets-ui/src/common/keys.ts +++ b/packages/sheets-ui/src/common/keys.ts @@ -21,7 +21,7 @@ export enum SHEET_VIEW_KEY { LEFT_TOP = '__SpreadsheetLeftTopPlaceholder__', } -export enum VIEWPORT_KEY { +export enum SHEET_VIEWPORT_KEY { VIEW_MAIN = 'viewMain', VIEW_MAIN_LEFT_TOP = 'viewMainLeftTop', VIEW_MAIN_TOP = 'viewMainTop', diff --git a/packages/sheets-ui/src/common/utils.ts b/packages/sheets-ui/src/common/utils.ts index 6fed9b6f7d5..3a8b1979512 100644 --- a/packages/sheets-ui/src/common/utils.ts +++ b/packages/sheets-ui/src/common/utils.ts @@ -16,14 +16,13 @@ import type { ICellData, IMutationInfo, IPosition, IRange, Nullable, Workbook, Worksheet } from '@univerjs/core'; import { ObjectMatrix } from '@univerjs/core'; -import { Vector2 } from '@univerjs/engine-render'; +import { SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; import type { ISetRangeValuesMutationParams, ISheetLocation } from '@univerjs/sheets'; import { SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '@univerjs/sheets'; import type { IAccessor } from '@wendellhu/redi'; import type { IBoundRectNoAngle, IRender, Scene, SpreadsheetSkeleton } from '@univerjs/engine-render'; import type { ICollaborator } from '@univerjs/protocol'; import type { ISheetSkeletonManagerParam } from '../services/sheet-skeleton-manager.service'; -import { VIEWPORT_KEY } from './keys'; export function getUserListEqual(userList1: ICollaborator[], userList2: ICollaborator[]) { if (userList1.length !== userList2.length) return false; @@ -143,23 +142,23 @@ export function getCellIndexByOffsetWithMerge(offsetX: number, offsetY: number, export function getViewportByCell(row: number, column: number, scene: Scene, worksheet: Worksheet) { const freeze = worksheet.getFreeze(); if (!freeze || (freeze.startRow <= 0 && freeze.startColumn <= 0)) { - return scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + return scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); } if (row > freeze.startRow && column > freeze.startColumn) { - return scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + return scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); } if (row <= freeze.startRow && column <= freeze.startColumn) { - return scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP); + return scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP); } if (row <= freeze.startRow && column > freeze.startColumn) { - return scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_TOP); + return scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP); } if (row > freeze.startRow && column <= freeze.startColumn) { - return scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_LEFT); + return scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT); } } @@ -177,7 +176,7 @@ export function transformBound2OffsetBound(originBound: IBoundRectNoAngle, scene export function transformPosition2Offset(x: number, y: number, scene: Scene, skeleton: SpreadsheetSkeleton, worksheet: Worksheet) { const { scaleX, scaleY } = scene.getAncestorScale(); - const viewMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); if (!viewMain) { return { x, @@ -194,18 +193,18 @@ export function transformPosition2Offset(x: number, y: number, scene: Scene, ske const freezeWidth = endSheetView.startX - startSheetView.startX; const freezeHeight = endSheetView.startY - startSheetView.startY; - const { top, left, viewportScrollX: actualScrollX, viewportScrollY: actualScrollY } = viewMain; + const { top, left, viewportScrollX, viewportScrollY } = viewMain; let offsetX: number; // viewMain or viewTop if (x > left) { - offsetX = (x - actualScrollX) * scaleX; + offsetX = (x - viewportScrollX) * scaleX; } else { offsetX = ((freezeWidth + rowHeaderWidth) - (left - x)) * scaleX; } let offsetY: number; if (y > top) { - offsetY = (y - actualScrollY) * scaleY; + offsetY = (y - viewportScrollY) * scaleY; } else { offsetY = ((freezeHeight + columnHeaderHeight) - (top - y)) * scaleX; } diff --git a/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts b/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts index 64b3bd71020..8bbfcb9f14f 100644 --- a/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts +++ b/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts @@ -36,11 +36,11 @@ import { import type { IRichTextEditingMutationParams } from '@univerjs/docs'; import { CoverContentCommand, + VIEWPORT_KEY as DOC_VIEWPORT_KEY, DocSkeletonManagerService, DocViewModelManagerService, RichTextEditingMutation, TextSelectionManagerService, - VIEWPORT_KEY, } from '@univerjs/docs'; import type { RenderComponentType } from '@univerjs/engine-render'; import { DeviceInputEventType, IRenderManagerService, ScrollBar } from '@univerjs/engine-render'; @@ -51,9 +51,9 @@ import { takeUntil } from 'rxjs'; import { SetEditorResizeOperation } from '@univerjs/ui'; import { getEditorObject } from '../../basics/editor/get-editor-object'; -import { IFormulaEditorManagerService } from '../../services/editor/formula-editor-manager.service'; import type { IEditorBridgeServiceParam } from '../../services/editor-bridge.service'; import { IEditorBridgeService } from '../../services/editor-bridge.service'; +import { IFormulaEditorManagerService } from '../../services/editor/formula-editor-manager.service'; @OnLifecycle(LifecycleStages.Rendered, FormulaEditorController) export class FormulaEditorController extends RxDisposable { @@ -553,7 +553,7 @@ export class FormulaEditorController extends RxDisposable { actualHeight += marginTop + marginBottom; const { width, height } = position; - const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewportMain = scene.getViewport(DOC_VIEWPORT_KEY.VIEW_MAIN); let scrollBar = viewportMain?.getScrollBar() as Nullable; @@ -568,7 +568,7 @@ export class FormulaEditorController extends RxDisposable { if (scrollBar == null) { viewportMain && new ScrollBar(viewportMain, { enableHorizontal: false, barSize: 8 }); } else { - viewportMain?.resetSizeAndScrollBar(); + viewportMain?.resetCanvasSizeAndUpdateScrollBar(); } } else { scrollBar = null; diff --git a/packages/sheets-ui/src/controllers/editor/start-edit.controller.ts b/packages/sheets-ui/src/controllers/editor/start-edit.controller.ts index 89a190334a7..e8098b7ee22 100644 --- a/packages/sheets-ui/src/controllers/editor/start-edit.controller.ts +++ b/packages/sheets-ui/src/controllers/editor/start-edit.controller.ts @@ -38,12 +38,12 @@ import { } from '@univerjs/core'; import type { IRichTextEditingMutationParams } from '@univerjs/docs'; import { + VIEWPORT_KEY as DOC_VIEWPORT_KEY, DOCS_COMPONENT_MAIN_LAYER_INDEX, DocSkeletonManagerService, DocViewModelManagerService, RichTextEditingMutation, TextSelectionManagerService, - VIEWPORT_KEY, } from '@univerjs/docs'; import type { DocumentSkeleton, IDocumentLayoutObject, IEditorInputConfig, Scene } from '@univerjs/engine-render'; import { @@ -59,12 +59,12 @@ import { import { IEditorService, KeyCode, SetEditorResizeOperation } from '@univerjs/ui'; import { Inject } from '@wendellhu/redi'; -import { filter } from 'rxjs'; import { ClearSelectionFormatCommand } from '@univerjs/sheets'; +import { filter } from 'rxjs'; import { getEditorObject } from '../../basics/editor/get-editor-object'; import { SetCellEditVisibleOperation } from '../../commands/operations/cell-edit.operation'; -import { ICellEditorManagerService } from '../../services/editor/cell-editor-manager.service'; import { IEditorBridgeService } from '../../services/editor-bridge.service'; +import { ICellEditorManagerService } from '../../services/editor/cell-editor-manager.service'; import styles from '../../views/sheet-container/index.module.less'; const HIDDEN_EDITOR_POSITION = -1000; @@ -345,7 +345,7 @@ export class StartEditController extends Disposable { const { document: documentComponent, scene, engine } = editorObject; - const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewportMain = scene.getViewport(DOC_VIEWPORT_KEY.VIEW_MAIN); const clientHeight = document.body.clientHeight - @@ -366,7 +366,7 @@ export class StartEditController extends Disposable { if (scrollBar == null) { viewportMain && new ScrollBar(viewportMain, { enableHorizontal: false, barSize: 8 }); } else { - viewportMain?.resetSizeAndScrollBar(); + viewportMain?.resetCanvasSizeAndUpdateScrollBar(); } } else { scrollBar = null; @@ -550,7 +550,7 @@ export class StartEditController extends Disposable { // TODO: @JOCS, Get the position close to the cursor after clicking on the cell. const cursor = documentDataModel.getBody()!.dataStream.length - 2 || 0; - scene.getViewport(VIEWPORT_KEY.VIEW_MAIN)?.scrollTo({ + scene.getViewport(DOC_VIEWPORT_KEY.VIEW_MAIN)?.scrollTo({ y: Number.POSITIVE_INFINITY, }); diff --git a/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts index c67c1fb4285..2239df51256 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts @@ -26,7 +26,7 @@ import { toDisposable, } from '@univerjs/core'; import type { IMouseEvent, IPointerEvent, IRenderContext, IRenderModule, IScrollObserverParam, Viewport } from '@univerjs/engine-render'; -import { CURSOR_TYPE, Rect, TRANSFORM_CHANGE_OBSERVABLE_TYPE, Vector2 } from '@univerjs/engine-render'; +import { CURSOR_TYPE, Rect, SHEET_VIEWPORT_KEY, TRANSFORM_CHANGE_OBSERVABLE_TYPE, Vector2 } from '@univerjs/engine-render'; import type { IInsertColCommandParams, IInsertRowCommandParams, @@ -67,7 +67,8 @@ import { Inject, Injector } from '@wendellhu/redi'; import { ScrollCommand } from '../../commands/commands/set-scroll.command'; import { SetZoomRatioOperation } from '../../commands/operations/set-zoom-ratio.operation'; -import { SHEET_COMPONENT_HEADER_LAYER_INDEX, VIEWPORT_KEY } from '../../common/keys'; +import { SHEET_COMPONENT_HEADER_LAYER_INDEX } from '../../common/keys'; + import { ScrollManagerService } from '../../services/scroll-manager.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import { getCoordByOffset, getSheetObject } from '../utils/component-tools'; @@ -184,6 +185,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM this._zoomRefresh(); } + // eslint-disable-next-line max-lines-per-function private _createFreeze( freezeDirectionType: FREEZE_DIRECTION_TYPE = FREEZE_DIRECTION_TYPE.ROW, freezeConfig?: IFreeze @@ -368,7 +370,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM const scene = sheetObject.scene; const scale = Math.max(scene.scaleX, scene.scaleY); - const currentScroll = this._scrollManagerService.getCurrentScroll(); + const currentScroll = this._scrollManagerService.getCurrentScrollInfo(); const skeletonViewHeight = (sheetObject.engine.height - skeleton.columnHeaderHeight) / scale; const start = currentScroll?.sheetViewStartRow ?? 0; @@ -562,7 +564,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM // alert(`moveColumnTo: ${this._changeToColumn}`); } - const sheetViewScroll = this._scrollManagerService.getCurrentScroll() || { + const sheetViewScroll = this._scrollManagerService.getCurrentScrollInfo() || { sheetViewStartRow: 0, sheetViewStartColumn: 0, }; @@ -588,10 +590,10 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM if (freezeDirectionType === FREEZE_DIRECTION_TYPE.ROW) { if ( !viewPortKey || - viewPortKey === VIEWPORT_KEY.VIEW_LEFT_TOP || - viewPortKey === VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP || - viewPortKey === VIEWPORT_KEY.VIEW_MAIN_TOP || - viewPortKey === VIEWPORT_KEY.VIEW_ROW_TOP + viewPortKey === SHEET_VIEWPORT_KEY.VIEW_LEFT_TOP || + viewPortKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP || + viewPortKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP || + viewPortKey === SHEET_VIEWPORT_KEY.VIEW_ROW_TOP ) { ySplit = this._changeToRow - (oldFreeze.startRow - oldFreeze.ySplit); } else { @@ -604,10 +606,10 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM if (freezeDirectionType === FREEZE_DIRECTION_TYPE.COLUMN) { if ( !viewPortKey || - viewPortKey === VIEWPORT_KEY.VIEW_LEFT_TOP || - viewPortKey === VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP || - viewPortKey === VIEWPORT_KEY.VIEW_MAIN_LEFT || - viewPortKey === VIEWPORT_KEY.VIEW_COLUMN_LEFT + viewPortKey === SHEET_VIEWPORT_KEY.VIEW_LEFT_TOP || + viewPortKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP || + viewPortKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT || + viewPortKey === SHEET_VIEWPORT_KEY.VIEW_COLUMN_LEFT ) { xSplit = this._changeToColumn - (oldFreeze.startColumn - oldFreeze.xSplit); } else { @@ -635,20 +637,20 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM } const { scene } = sheetObject; - const viewColumnLeft = scene.getViewport(VIEWPORT_KEY.VIEW_COLUMN_LEFT); - const viewColumnRight = scene.getViewport(VIEWPORT_KEY.VIEW_COLUMN_RIGHT); + const viewColumnLeft = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_COLUMN_LEFT); + const viewColumnRight = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_COLUMN_RIGHT); // row header - const viewRowTop = scene.getViewport(VIEWPORT_KEY.VIEW_ROW_TOP); - const viewRowBottom = scene.getViewport(VIEWPORT_KEY.VIEW_ROW_BOTTOM); + const viewRowTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_ROW_TOP); + const viewRowBottom = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_ROW_BOTTOM); - const viewLeftTop = scene.getViewport(VIEWPORT_KEY.VIEW_LEFT_TOP); + const viewLeftTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_LEFT_TOP); // skeleton - const viewMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); - const viewMainLeftTop = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP); - const viewMainLeft = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_LEFT); - const viewMainTop = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_TOP); + const viewMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); + const viewMainLeftTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP); + const viewMainLeft = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT); + const viewMainTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP); if ( viewColumnLeft == null || @@ -688,13 +690,13 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM this.disposeWithMe( viewMain.onScrollAfterObserver.add((param: IScrollObserverParam) => { - const { scrollX, scrollY, actualScrollX, actualScrollY } = param; + const { scrollX, scrollY, viewportScrollX, viewportScrollY } = param; if (viewRowBottom.isActive) { viewRowBottom .updateScroll({ scrollY, - actualScrollY, + viewportScrollY, }); } @@ -702,14 +704,14 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewColumnRight .updateScroll({ scrollX, - actualScrollX, + viewportScrollX, }); } if (viewMainLeft.isActive) { viewMainLeft .updateScroll({ scrollY, - actualScrollY, + viewportScrollY, }); } @@ -717,10 +719,10 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewMainTop .updateScroll({ scrollX, - actualScrollX, + viewportScrollX, }); } - })! + }) ); } @@ -848,9 +850,9 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); viewMainTop .updateScroll({ - actualScrollY: startSheetView.startY, + viewportScrollY: startSheetView.startY, x: viewMain.scrollX, - actualScrollX: viewMain.viewportScrollX, + viewportScrollX: viewMain.viewportScrollX, }); viewRowTop.resize({ left: 0, @@ -860,7 +862,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); viewRowTop .updateScroll({ - actualScrollY: startSheetView.startY, + viewportScrollY: startSheetView.startY, }); viewRowBottom.resize({ left: 0, @@ -903,9 +905,9 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); viewMainLeft .updateScroll({ - actualScrollX: startSheetView.startX, + viewportScrollX: startSheetView.startX, y: viewMain.scrollY, - actualScrollY: viewMain.viewportScrollY, + viewportScrollY: viewMain.viewportScrollY, }); viewColumnLeft.resize({ left: rowHeaderWidthAndMarginLeft, @@ -915,7 +917,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); viewColumnLeft .updateScroll({ - actualScrollX: startSheetView.startX, + viewportScrollX: startSheetView.startX, }); viewColumnRight.resize({ left: rowHeaderWidthAndMarginLeft + leftGap, @@ -967,9 +969,9 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); viewMainLeft .updateScroll({ - actualScrollX: startSheetView.startX, + viewportScrollX: startSheetView.startX, y: viewMain.scrollY, - actualScrollY: viewMain.viewportScrollY, + viewportScrollY: viewMain.viewportScrollY, }); viewMainTop.resize({ left: rowHeaderWidthAndMarginLeft + leftGap, @@ -979,9 +981,9 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); viewMainTop .updateScroll({ - actualScrollY: startSheetView.startY, + viewportScrollY: startSheetView.startY, x: viewMain.scrollX, - actualScrollX: viewMain.viewportScrollX, + viewportScrollX: viewMain.viewportScrollX, }); viewMainLeftTop.resize({ left: rowHeaderWidthAndMarginLeft, @@ -992,8 +994,8 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewMainLeftTop .updateScroll({ - actualScrollX: startSheetView.startX, - actualScrollY: startSheetView.startY, + viewportScrollX: startSheetView.startX, + viewportScrollY: startSheetView.startY, }); viewRowTop.resize({ @@ -1005,7 +1007,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewRowTop .updateScroll({ - actualScrollY: startSheetView.startY, + viewportScrollY: startSheetView.startY, }); viewRowBottom.resize({ @@ -1024,7 +1026,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewColumnLeft .updateScroll({ - actualScrollX: startSheetView.startX, + viewportScrollX: startSheetView.startX, }); viewColumnRight.resize({ diff --git a/packages/sheets-ui/src/controllers/render-controllers/header-move.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/header-move.render-controller.ts index dec989e3359..ef8532c1fd1 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/header-move.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/header-move.render-controller.ts @@ -28,6 +28,7 @@ import { Rect, ScrollTimer, ScrollTimerType, + SHEET_VIEWPORT_KEY, Vector2, } from '@univerjs/engine-render'; import type { IMoveColsCommandParams, IMoveRowsCommandParams, ISelectionWithStyle } from '@univerjs/sheets'; @@ -39,7 +40,7 @@ import { } from '@univerjs/sheets'; import { Inject } from '@wendellhu/redi'; -import { SHEET_COMPONENT_HEADER_LAYER_INDEX, SHEET_VIEW_KEY, VIEWPORT_KEY } from '../../common/keys'; +import { SHEET_COMPONENT_HEADER_LAYER_INDEX, SHEET_VIEW_KEY } from '../../common/keys'; import { ISelectionRenderService } from '../../services/selection/selection-render.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import { getCoordByOffset } from '../utils/component-tools'; @@ -253,7 +254,7 @@ export class HeaderMoveRenderController extends Disposable implements IRenderMod scrollTimer = ScrollTimer.create(scene, scrollType); - const mainViewport = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const mainViewport = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); scrollTimer.startScroll(newEvtOffsetX, newEvtOffsetY, mainViewport); @@ -373,7 +374,7 @@ export class HeaderMoveRenderController extends Disposable implements IRenderMod const { rowHeaderWidth, columnHeaderHeight, rowTotalHeight, columnTotalWidth } = skeleton; // const scrollXY = scene.getScrollXYByRelativeCoords(Vector2.FromArray([this._startOffsetX, this._startOffsetY])); - const scrollXY = scene.getScrollXY(scene.getViewport(VIEWPORT_KEY.VIEW_MAIN)!); + const scrollXY = scene.getScrollXY(scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN)!); const { scaleX, scaleY } = scene.getAncestorScale(); const moveActualSelection = skeleton.getCellPositionByOffset( diff --git a/packages/sheets-ui/src/controllers/render-controllers/header-resize.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/header-resize.render-controller.ts index f0c9a329894..b99b0c5d4a9 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/header-resize.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/header-resize.render-controller.ts @@ -25,7 +25,7 @@ import { toDisposable, } from '@univerjs/core'; import type { IMouseEvent, IPointerEvent, IRenderContext, IRenderModule, SpreadsheetColumnHeader, SpreadsheetHeader } from '@univerjs/engine-render'; -import { CURSOR_TYPE, DeviceInputEventType, Rect, Vector2 } from '@univerjs/engine-render'; +import { CURSOR_TYPE, DeviceInputEventType, Rect, SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; import type { IDeltaColumnWidthCommandParams, IDeltaRowHeightCommand, @@ -34,7 +34,7 @@ import type { import { DeltaColumnWidthCommand, DeltaRowHeightCommand, SetWorksheetRowIsAutoHeightCommand } from '@univerjs/sheets'; import { Inject } from '@wendellhu/redi'; -import { SHEET_COMPONENT_HEADER_LAYER_INDEX, SHEET_VIEW_KEY, VIEWPORT_KEY } from '../../common/keys'; +import { SHEET_COMPONENT_HEADER_LAYER_INDEX, SHEET_VIEW_KEY, SHEET_VIEWPORT_KEY } from '../../common/keys'; import { IEditorBridgeService } from '../../services/editor-bridge.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import { @@ -316,7 +316,7 @@ export class HeaderResizeRenderController extends Disposable implements IRenderM const engine = scene.getEngine(); const canvasMaxHeight = engine?.height || 0; const canvasMaxWidth = engine?.width || 0; - const viewPort = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewPort = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); const scrollBarHorizontalHeight = (viewPort?.getScrollBar()?.horizonBarRect?.height || 0) + 10; const scrollBarVerticalWidth = (viewPort?.getScrollBar()?.verticalBarRect?.width || 0) + 10; diff --git a/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts index 019dc51e60c..28f7b9810bd 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts @@ -23,17 +23,17 @@ import { toDisposable, } from '@univerjs/core'; import type { IRenderContext, IRenderModule } from '@univerjs/engine-render'; -import { IRenderManagerService } from '@univerjs/engine-render'; +import { IRenderManagerService, SHEET_VIEWPORT_KEY } from '@univerjs/engine-render'; import { ScrollToCellOperation, SelectionManagerService } from '@univerjs/sheets'; import { Inject } from '@wendellhu/redi'; import { ScrollCommand } from '../../commands/commands/set-scroll.command'; -import { VIEWPORT_KEY } from '../../common/keys'; +import type { IExpandSelectionCommandParams } from '../../commands/commands/set-selection.command'; +import { ExpandSelectionCommand, MoveSelectionCommand, MoveSelectionEnterAndTabCommand } from '../../commands/commands/set-selection.command'; +import type { IScrollManagerParam, IScrollManagerSearchParam } from '../../services/scroll-manager.service'; import { ScrollManagerService } from '../../services/scroll-manager.service'; import type { ISheetSkeletonManagerParam } from '../../services/sheet-skeleton-manager.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; -import type { IExpandSelectionCommandParams } from '../../commands/commands/set-selection.command'; -import { ExpandSelectionCommand, MoveSelectionCommand, MoveSelectionEnterAndTabCommand } from '../../commands/commands/set-selection.command'; import { getSheetObject } from '../utils/component-tools'; const SHEET_NAVIGATION_COMMANDS = [MoveSelectionCommand.id, MoveSelectionEnterAndTabCommand.id]; @@ -162,10 +162,11 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM return; } - const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); this.disposeWithMe( toDisposable( - viewportMain?.onScrollAfterObserver.add((param) => { + // set scrollInfo, event triggered in viewport@_scrollToScrollbarPos + viewportMain?.onScrollAfterObserver.add((param: IScrollObserverParam) => { const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; if (skeleton == null || param.isTrigger === false) { return; @@ -176,21 +177,25 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM return; } - const { actualScrollX = 0, actualScrollY = 0 } = param; + const { viewportScrollX = 0, viewportScrollY = 0 } = param; // according to the actual scroll position, the most suitable row, column and offset combination is recalculated. const { row, column, rowOffset, columnOffset } = skeleton.getDecomposedOffset( - actualScrollX, - actualScrollY + viewportScrollX, + viewportScrollY ); - // update scroll infos in scroll manager service - this._scrollManagerService.addOrReplaceNoRefresh({ + // update scroll infos in scrollManagerService again! + // because raw param from scroll-command offsetX may be negative or over max value. + // by the way, there is no need to set viewportScrollXY in lastestScrollInfo, _scrollManagerService._setScrollInfo would do this process. + const lastestScrollInfo: IScrollManagerParam = { sheetViewStartRow: row, sheetViewStartColumn: column, offsetX: columnOffset, offsetY: rowOffset, - }); + }; + this._scrollManagerService.setScrollInfoToCurrSheetWithoutNotify(lastestScrollInfo); + this._scrollManagerService.setScrollInfoToSnapshot({...lastestScrollInfo, viewportScrollX, viewportScrollY}); }) ) ); @@ -206,14 +211,13 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM if (skeleton == null || sheetObject == null) { return; } - const { actualScrollX = 0, actualScrollY = 0 } = param; + const { viewportScrollX = 0, viewportScrollY = 0 } = param; const freeze = this._getFreeze(); - // according to the actual scroll position, the most suitable row, column and offset combination is recalculated. const { row, column, rowOffset, columnOffset } = skeleton.getDecomposedOffset( - actualScrollX, - actualScrollY + viewportScrollX, + viewportScrollY ); this._commandService.executeCommand(ScrollCommand.id, { @@ -227,10 +231,11 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM ); } - // scroll command -> scroll manager service -> scrollInfo$ -> viewport scroll API private _scrollSubscribeBinding() { this.disposeWithMe( toDisposable( + // wheel event --> set-scroll.command('sheet.operation.set-scroll') --> scroll.operation.ts --> scrollManagerService.setScrollInfo(raw value, may be negative) --> scrollInfo$.next --> current fn() --> viewport.scrollTo + // --> onScrollAfterObserver.notify ---> scrollManagerService.setScrollInfo again!(valid scroll value) this._scrollManagerService.scrollInfo$.subscribe((param) => { const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; const sheetObject = this._getSheetObject(); @@ -239,15 +244,11 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM } const scene = sheetObject.scene; - - const { scaleX, scaleY } = sheetObject.scene.getAncestorScale(); - - const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); if (viewportMain == null) { return; } - if (param == null) { viewportMain.scrollTo({ x: 0, @@ -256,17 +257,19 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM return; } - // 数据源 packages/sheets-ui/src/services/scroll-manager.service.ts@_addByParam + // data source: scroll-manager.service.ts@_scrollInfo const { sheetViewStartRow, sheetViewStartColumn, offsetX, offsetY } = param; const { startX, startY } = skeleton.getCellByIndexWithNoHeader( sheetViewStartRow, sheetViewStartColumn ); - const x = startX + offsetX; - const y = startY + offsetY; - const config = viewportMain.getBarScroll(x, y); + // viewportScrollXByEvent is not same as viewportScrollX, by event, the value may be negative, or over max + const viewportScrollXByEvent = startX + offsetX; + const viewportScrollYByEvent = startY + offsetY; + + const config = viewportMain.transViewportScroll2ScrollValue(viewportScrollXByEvent, viewportScrollYByEvent); viewportMain.scrollTo(config); }) ) @@ -274,20 +277,28 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM } private _initSkeletonListener() { - this.disposeWithMe(toDisposable(this._sheetSkeletonManagerService.currentSkeleton$.subscribe((param) => { - if (param == null) { - return; - } - - const { unitId } = this._context; - const { sheetId } = param; - - this._updateSceneSize(param); - this._scrollManagerService.setCurrentScroll({ - unitId, - sheetId, - }); - }))); + this.disposeWithMe(toDisposable( + this._sheetSkeletonManagerService.currentSkeletonBefore$.subscribe((param) => { + if (param == null) { + return; + } + + // const { unitId } = this._context; + // const { sheetId } = param; + + // this._scrollManagerService.setSearchParam(param as unknown as ISheetSkeletonManagerParam); + const sheetObject = this._getSheetObject(); + if (!sheetObject) return; + const scene = sheetObject.scene; + const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); + const currScrollInfo = this._scrollManagerService.getScrollInfoByParam(param as unknown as IScrollManagerSearchParam); + if (viewportMain && currScrollInfo) { + viewportMain.viewportScrollX = currScrollInfo.viewportScrollX || 0; + viewportMain.viewportScrollY = currScrollInfo.viewportScrollY || 0; + } + // this function would call setSearchParam + this._updateSceneSize(param as unknown as ISheetSkeletonManagerParam); + }))); } private _updateSceneSize(param: ISheetSkeletonManagerParam) { @@ -305,7 +316,9 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM const { rowTotalHeight, columnTotalWidth, rowHeaderWidthAndMarginLeft, columnHeaderHeightAndMarginTop } = skeleton; + this._scrollManagerService.setSearchParam(param); + // would cause viewport.resetSizeAndScrollBar scene?.transformByState({ width: rowHeaderWidthAndMarginLeft + columnTotalWidth, height: columnHeaderHeightAndMarginTop + rowTotalHeight, @@ -371,7 +384,7 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM return; } - const viewport = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewport = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); if (viewport == null) { return; } @@ -385,6 +398,7 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM return skeleton.getRowColumnSegment(bounds); } + // eslint-disable-next-line max-lines-per-function, complexity private _scrollToCell(row: number, column: number): boolean { const { rowHeightAccumulation, columnWidthAccumulation } = this._sheetSkeletonManagerService.getCurrent()?.skeleton ?? {}; @@ -393,7 +407,7 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM const scene = this._getSheetObject()?.scene; if (scene == null) return false; - const viewport = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewport = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); if (viewport == null) return false; const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; @@ -459,7 +473,7 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM if (startSheetViewRow === undefined && startSheetViewColumn === undefined) return false; - const { offsetX, offsetY } = this._scrollManagerService.getCurrentScroll() || {}; + const { offsetX, offsetY } = this._scrollManagerService.getCurrentScrollInfo() || {}; return this._commandService.syncExecuteCommand(ScrollCommand.id, { sheetViewStartRow: startSheetViewRow, sheetViewStartColumn: startSheetViewColumn, @@ -467,4 +481,53 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM offsetY: startSheetViewRow === undefined ? offsetY : 0, }); } + + private _getViewports() { + const sheetObject = this._getSheetObject(); + if (sheetObject == null) { + return; + } + const { scene } = sheetObject; + + const viewColumnLeft = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_COLUMN_LEFT); + const viewColumnRight = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_COLUMN_RIGHT); + + // row header + const viewRowTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_ROW_TOP); + const viewRowBottom = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_ROW_BOTTOM); + + const viewLeftTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_LEFT_TOP); + + // skeleton + const viewMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); + const viewMainLeftTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP); + const viewMainLeft = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT); + const viewMainTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP); + + if ( + viewColumnLeft == null || + viewColumnRight == null || + viewRowTop == null || + viewRowBottom == null || + viewLeftTop == null || + viewMain == null || + viewMainLeftTop == null || + viewMainLeft == null || + viewMainTop == null + ) { + return; + } + + return { + viewMain, + viewMainLeftTop, + viewMainLeft, + viewMainTop, + viewColumnLeft, + viewColumnRight, + viewRowTop, + viewRowBottom, + viewLeftTop, + }; + } } diff --git a/packages/sheets-ui/src/controllers/render-controllers/selection.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/selection.render-controller.ts index e69ccb2abd7..93e2ea72c4b 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/selection.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/selection.render-controller.ts @@ -23,7 +23,7 @@ import { toDisposable, } from '@univerjs/core'; import type { IMouseEvent, IPointerEvent, IRenderContext, IRenderModule, SpreadsheetSkeleton } from '@univerjs/engine-render'; -import { ScrollTimerType, Vector2 } from '@univerjs/engine-render'; +import { ScrollTimerType, SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; import type { ISelectionWithCoordAndStyle, ISelectionWithStyle } from '@univerjs/sheets'; import { convertSelectionDataToRange, @@ -42,7 +42,7 @@ import { Inject } from '@wendellhu/redi'; import { deserializeRangeWithSheet, IDefinedNamesService, isReferenceStrings, operatorToken } from '@univerjs/engine-formula'; import type { ISetZoomRatioOperationParams } from '../../commands/operations/set-zoom-ratio.operation'; import { SetZoomRatioOperation } from '../../commands/operations/set-zoom-ratio.operation'; -import { VIEWPORT_KEY } from '../../common/keys'; +import { SHEET_VIEWPORT_KEY } from '../../common/keys'; import { ISelectionRenderService } from '../../services/selection/selection-render.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import type { ISheetObjectParam } from '../utils/component-tools'; @@ -446,7 +446,7 @@ export class SelectionRenderController extends Disposable implements IRenderModu const { sheetId, skeleton } = param; const { scene } = this._context; - const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); this._selectionRenderService.changeRuntime(skeleton, scene, viewportMain); diff --git a/packages/sheets-ui/src/controllers/utils/component-tools.ts b/packages/sheets-ui/src/controllers/utils/component-tools.ts index a64c29c7e92..f49f631522d 100644 --- a/packages/sheets-ui/src/controllers/utils/component-tools.ts +++ b/packages/sheets-ui/src/controllers/utils/component-tools.ts @@ -28,9 +28,9 @@ import type { SpreadsheetSkeleton, Viewport, } from '@univerjs/engine-render'; -import { Vector2 } from '@univerjs/engine-render'; +import { SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; -import { SHEET_VIEW_KEY, VIEWPORT_KEY } from '../../common/keys'; +import { SHEET_VIEW_KEY } from '../../common/keys'; export interface ISheetObjectParam { spreadsheet: Spreadsheet; @@ -145,7 +145,7 @@ export function getCoordByOffset( export function getTransformCoord(evtOffsetX: number, evtOffsetY: number, scene: Scene, skeleton: SpreadsheetSkeleton) { const relativeCoords = scene.getRelativeCoord(Vector2.FromArray([evtOffsetX, evtOffsetY])); - const viewMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); const scrollXY = scene.getScrollXYByRelativeCoords(relativeCoords, viewMain); const { scaleX, scaleY } = scene.getAncestorScale(); diff --git a/packages/sheets-ui/src/index.ts b/packages/sheets-ui/src/index.ts index 4d6eab6607d..4c8d903a1ca 100644 --- a/packages/sheets-ui/src/index.ts +++ b/packages/sheets-ui/src/index.ts @@ -35,7 +35,7 @@ export { type IScrollToCellCommandParams, type ISetScrollRelativeCommandParams, } from './commands/commands/set-scroll.command'; -export { VIEWPORT_KEY } from './common/keys'; +export { SHEET_VIEWPORT_KEY as VIEWPORT_KEY } from './common/keys'; export { AutoFillController } from './controllers/auto-fill.controller'; export { CellCustomRenderController } from './controllers/cell-custom-render.controller'; export { PASTE_SPECIAL_MENU_ID } from './controllers/menu/menu'; diff --git a/packages/sheets-ui/src/services/drag-manager.service.ts b/packages/sheets-ui/src/services/drag-manager.service.ts index 7946337b04f..f22bb86333d 100644 --- a/packages/sheets-ui/src/services/drag-manager.service.ts +++ b/packages/sheets-ui/src/services/drag-manager.service.ts @@ -77,7 +77,8 @@ export class DragManagerService extends Disposable { const worksheet = workbook.getActiveSheet(); const currentRender = this._renderManagerService.getRenderById(workbook.getUnitId()); const skeletonParam = currentRender?.with(SheetSkeletonManagerService)?.getCurrent(); - const scrollInfo = this._scrollManagerService.getCurrentScroll(); + + const scrollInfo = this._scrollManagerService.getCurrentScrollInfo(); if (!skeletonParam || !scrollInfo || !currentRender) return; diff --git a/packages/sheets-ui/src/services/hover-manager.service.ts b/packages/sheets-ui/src/services/hover-manager.service.ts index 1ca53424133..783e2574864 100644 --- a/packages/sheets-ui/src/services/hover-manager.service.ts +++ b/packages/sheets-ui/src/services/hover-manager.service.ts @@ -82,7 +82,7 @@ export class HoverManagerService extends Disposable { const worksheet = workbook.getActiveSheet(); const currentRender = this._renderManagerService.getRenderById(workbook.getUnitId()); const skeletonParam = currentRender?.with(SheetSkeletonManagerService).getUnitSkeleton(workbook.getUnitId(), worksheet.getSheetId()); - const scrollInfo = this._scrollManagerService.getCurrentScroll(); + const scrollInfo = this._scrollManagerService.getCurrentScrollInfo(); if (!skeletonParam || !scrollInfo || !currentRender) return; diff --git a/packages/sheets-ui/src/services/scroll-manager.service.ts b/packages/sheets-ui/src/services/scroll-manager.service.ts index 06827b2b9e5..d95f2fe3a8c 100644 --- a/packages/sheets-ui/src/services/scroll-manager.service.ts +++ b/packages/sheets-ui/src/services/scroll-manager.service.ts @@ -14,14 +14,18 @@ * limitations under the License. */ -import type { Nullable } from '@univerjs/core'; +import { IUniverInstanceService, type Nullable } from '@univerjs/core'; import { BehaviorSubject } from 'rxjs'; +import { Inject } from '@wendellhu/redi'; +import { SheetSkeletonManagerService } from './sheet-skeleton-manager.service'; export interface IScrollManagerParam { offsetX: number; offsetY: number; sheetViewStartRow: number; sheetViewStartColumn: number; + viewportScrollX?: number; + viewportScrollY?: number; } export interface IScrollManagerSearchParam { @@ -45,60 +49,94 @@ export class ScrollManagerService { private readonly _scrollInfo$ = new BehaviorSubject>(null); readonly scrollInfo$ = this._scrollInfo$.asObservable(); - private _currentScroll: Nullable = null; + private _searchParamForScroll: Nullable = null; + + constructor( + @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, + @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService + ) { + } dispose(): void { this._scrollInfo$.complete(); } - setCurrentScroll(param: IScrollManagerSearchParam) { - this._currentScroll = param; + setSearchParam(param: IScrollManagerSearchParam) { + this._searchParamForScroll = param; + } - this._refresh(param); + setSearchParamAndRefresh(param: IScrollManagerSearchParam) { + this._searchParamForScroll = param; + this._notifyCurrentScrollInfo(param); } - getScrollByParam(param: IScrollManagerSearchParam): Readonly> { + getScrollInfoByParam(param: IScrollManagerSearchParam): Readonly> { return this._getCurrentScroll(param); } - getCurrentScroll(): Readonly> { - return this._getCurrentScroll(this._currentScroll); + getCurrentScrollInfo(): Readonly> { + return this._getCurrentScroll(this._searchParamForScroll); + } + + setScrollInfoToSnapshot(scrollInfo: IScrollManagerParam) { + if (this._searchParamForScroll == null) { + return; + } + const { unitId, sheetId } = this._searchParamForScroll; + const workbook = this._univerInstanceService.getUniverSheetInstance(unitId); + const worksheet = workbook?.getSheetBySheetId(sheetId); + const snapshot = worksheet?.getConfig(); + if (snapshot) { + snapshot.scrollLeft = scrollInfo.viewportScrollX || 0; + snapshot.scrollTop = scrollInfo.viewportScrollY || 0; + } + } + + /** + * set scrollInfo by cmd, + * call _setScrollInfo twice after one scrolling. + * first time set scrollInfo bt scrollOperation, but offsetXY is derived from scroll event. + * second time set scrollInfo by viewport.scrollTo(scrol.render-controller --> onScrollAfterObserver), this time offsetXY has been limited. + * + * wheelevent --> sheetCanvasView --> set-scroll.command('sheet.command.set-scroll-relative') --> scrollOperation --> this.setScrollInfo --> scrollInfo$.next --> scroll.render-controller@viewportMain.scrollTo & notify --> + * scroll.render-controller@onScrollAfterObserver --> this.setScrollInfoToCurrSheetWithoutNotify --> this._setScrollInfo({}, false) + * call _setScrollInfo again, a loop!, so we should call setScrollInfoToCurrSheetWithoutNotify + * @param param + */ + setScrollInfo(param: IScrollManagerInsertParam) { + this._setScrollInfo(param); } - addOrReplace(scroll: IScrollManagerParam) { - if (this._currentScroll == null) { + setScrollInfoToCurrSheet(scrollInfo: IScrollManagerParam) { + if (this._searchParamForScroll == null) { return; } - this._addByParam({ - ...this._currentScroll, - ...scroll, + this._setScrollInfo({ + ...this._searchParamForScroll, + ...scrollInfo, }); } - addOrReplaceNoRefresh(scroll: IScrollManagerParam) { - if (this._currentScroll == null) { + setScrollInfoToCurrSheetWithoutNotify(scroll: IScrollManagerParam) { + if (this._searchParamForScroll == null) { return; } - this._addByParam( + this._setScrollInfo( { - ...this._currentScroll, + ...this._searchParamForScroll, ...scroll, }, false ); } - addOrReplaceByParam(param: IScrollManagerInsertParam) { - this._addByParam(param); - } - clear(): void { - if (this._currentScroll == null) { + if (this._searchParamForScroll == null) { return; } - this._clearByParam(this._currentScroll); + this._clearByParam(this._searchParamForScroll); } // scrollToCell(startRow: number, startColumn: number) { @@ -111,29 +149,56 @@ export class ScrollManagerService { // const {} = skeleton.getCellByIndex(startRow, startColumn); // } - private _addByParam(insertParam: IScrollManagerInsertParam, isRefresh = true): void { - const { unitId, sheetId, sheetViewStartColumn, sheetViewStartRow, offsetX, offsetY } = insertParam; + calcViewportScrollFromOffset(scrollInfo: IScrollManagerInsertParam) { + const { unitId } = scrollInfo; + const workbookScrollInfo = this._scrollInfo.get(unitId); + if (workbookScrollInfo == null) { + return { + scrollTop: 0, + scrollLeft: 0, + }; + } + // const scrollInfo = workbookScrollInfo.get(param.sheetId); + let { sheetViewStartColumn, sheetViewStartRow, offsetX, offsetY } = scrollInfo; + sheetViewStartRow = sheetViewStartRow || 0; + offsetY = offsetY || 0; + const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; + const rowAcc = skeleton?.rowHeightAccumulation[sheetViewStartRow - 1] || 0; + const colAcc = skeleton?.columnWidthAccumulation[sheetViewStartColumn - 1] || 0; + const viewportScrollX = colAcc + offsetX; + const viewportScrollY = rowAcc + offsetY; + + return { + viewportScrollX, + viewportScrollY, + }; + } + + private _setScrollInfo(newScrollInfo: IScrollManagerInsertParam, notifyScrollInfo = true): void { + const { unitId, sheetId, sheetViewStartColumn, sheetViewStartRow, offsetX, offsetY } = newScrollInfo; if (!this._scrollInfo.has(unitId)) { this._scrollInfo.set(unitId, new Map()); } - const sheetScroll = this._scrollInfo.get(unitId)!; - - sheetScroll.set(sheetId, { + const worksheetScrollInfoMap = this._scrollInfo.get(unitId)!; + const scrollLeftTopByRowColOffset = this.calcViewportScrollFromOffset(newScrollInfo); + const scrollInfo: IScrollManagerParam = { sheetViewStartRow, sheetViewStartColumn, offsetX, offsetY, - }); - - if (isRefresh === true) { - this._refresh({ unitId, sheetId }); + viewportScrollX: scrollLeftTopByRowColOffset.viewportScrollX, + viewportScrollY: scrollLeftTopByRowColOffset.viewportScrollY, + }; + worksheetScrollInfoMap.set(sheetId, scrollInfo); + if (notifyScrollInfo === true) { + this._notifyCurrentScrollInfo({ unitId, sheetId }); } } private _clearByParam(param: IScrollManagerSearchParam): void { - this._addByParam({ + this._setScrollInfo({ ...param, sheetViewStartRow: 0, sheetViewStartColumn: 0, @@ -141,7 +206,7 @@ export class ScrollManagerService { offsetY: 0, }); - this._refresh(param); + this._notifyCurrentScrollInfo(param); } private _getCurrentScroll(param: Nullable) { @@ -152,7 +217,10 @@ export class ScrollManagerService { return this._scrollInfo.get(unitId)?.get(sheetId); } - private _refresh(param: IScrollManagerSearchParam): void { - this._scrollInfo$.next(this._getCurrentScroll(param)); + private _notifyCurrentScrollInfo(param: IScrollManagerSearchParam): void { + const scrollInfo = this._getCurrentScroll(param); + + // subscribe this._scrollManagerService.scrollInfo$ in scroll.render-controller + this._scrollInfo$.next(scrollInfo); } } diff --git a/packages/sheets-ui/src/services/selection/selection-render.service.ts b/packages/sheets-ui/src/services/selection/selection-render.service.ts index f627de8ff61..69e1b27b5a2 100644 --- a/packages/sheets-ui/src/services/selection/selection-render.service.ts +++ b/packages/sheets-ui/src/services/selection/selection-render.service.ts @@ -30,7 +30,7 @@ import type { } from '@univerjs/core'; import { createInterceptorKey, InterceptorManager, IUniverInstanceService, makeCellToSelection, RANGE_TYPE, ThemeService, UniverInstanceType } from '@univerjs/core'; import type { IMouseEvent, IPointerEvent, Scene, SpreadsheetSkeleton, Viewport } from '@univerjs/engine-render'; -import { IRenderManagerService, ScrollTimer, ScrollTimerType, Vector2 } from '@univerjs/engine-render'; +import { IRenderManagerService, ScrollTimer, ScrollTimerType, SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; import type { ISelectionStyle, ISelectionWithCoordAndStyle, ISelectionWithStyle } from '@univerjs/sheets'; import { getNormalSelectionStyle } from '@univerjs/sheets'; import { IShortcutService } from '@univerjs/ui'; @@ -38,7 +38,6 @@ import { createIdentifier, Inject, Injector } from '@wendellhu/redi'; import type { Observable } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs'; -import { VIEWPORT_KEY } from '../../common/keys'; import { SheetSkeletonManagerService } from '../sheet-skeleton-manager.service'; import type { SelectionRenderModel } from './selection-render-model'; import { SelectionShape } from './selection-shape'; @@ -420,23 +419,23 @@ export class SelectionRenderService implements ISelectionRenderService { } const freeze = this._getFreeze(); if (!freeze || (freeze.startRow <= 0 && freeze.startColumn <= 0)) { - return this._scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + return this._scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); } if (row > freeze.startRow && column > freeze.startColumn) { - return this._scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + return this._scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); } if (row <= freeze.startRow && column <= freeze.startColumn) { - return this._scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP); + return this._scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP); } if (row <= freeze.startRow && column > freeze.startColumn) { - return this._scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_TOP); + return this._scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP); } if (row > freeze.startRow && column <= freeze.startColumn) { - return this._scene.getViewport(VIEWPORT_KEY.VIEW_MAIN_LEFT); + return this._scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT); } } @@ -563,7 +562,7 @@ export class SelectionRenderService implements ISelectionRenderService { this._activeViewport = viewport; } - const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); const relativeCoords = scene.getRelativeCoord(Vector2.FromArray([evtOffsetX, evtOffsetY])); let { x: newEvtOffsetX, y: newEvtOffsetY } = relativeCoords; @@ -824,7 +823,7 @@ export class SelectionRenderService implements ISelectionRenderService { const startKey = startViewport.viewportKey; const endKey = endViewport.viewportKey; - if (startKey === VIEWPORT_KEY.VIEW_ROW_TOP) { + if (startKey === SHEET_VIEWPORT_KEY.VIEW_ROW_TOP) { if (moveOffsetY < viewportMain.top && (selection?.endRow ?? 0) < (freeze?.startRow ?? 0)) { scrollOffsetY = viewportMain.top; } else if (isCrossingY && yCrossTime % 2 === 1) { @@ -832,7 +831,7 @@ export class SelectionRenderService implements ISelectionRenderService { y: 0, }); } - } else if (startKey === VIEWPORT_KEY.VIEW_COLUMN_LEFT) { + } else if (startKey === SHEET_VIEWPORT_KEY.VIEW_COLUMN_LEFT) { if (moveOffsetX < viewportMain.left && (selection?.endColumn ?? 0) < (freeze?.startColumn ?? 0)) { scrollOffsetX = viewportMain.left; } else if (isCrossingX && xCrossTime % 2 === 1) { @@ -843,12 +842,12 @@ export class SelectionRenderService implements ISelectionRenderService { } else if (startKey === endKey) { let disableX = false; let disableY = false; - if (startKey === VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP) { + if (startKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP) { disableX = true; disableY = true; - } else if (startKey === VIEWPORT_KEY.VIEW_MAIN_TOP) { + } else if (startKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP) { disableY = true; - } else if (startKey === VIEWPORT_KEY.VIEW_MAIN_LEFT) { + } else if (startKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT) { disableX = true; } @@ -894,15 +893,15 @@ export class SelectionRenderService implements ISelectionRenderService { } if ( - (startKey === VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP && endKey === VIEWPORT_KEY.VIEW_MAIN_LEFT) || - (endKey === VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP && startKey === VIEWPORT_KEY.VIEW_MAIN_LEFT) + (startKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP && endKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT) || + (endKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP && startKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT) ) { scrollOffsetX = viewportMain.left; } if ( - (startKey === VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP && endKey === VIEWPORT_KEY.VIEW_MAIN_TOP) || - (endKey === VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP && startKey === VIEWPORT_KEY.VIEW_MAIN_TOP) + (startKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP && endKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP) || + (endKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP && startKey === SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP) ) { scrollOffsetY = viewportMain.top; } @@ -1028,7 +1027,7 @@ export class SelectionRenderService implements ISelectionRenderService { } // const scrollXY = scene.getScrollXYByRelativeCoords(Vector2.FromArray([this._startOffsetX, this._startOffsetY])); - const scrollXY = scene.getScrollXY(scene.getViewport(VIEWPORT_KEY.VIEW_MAIN)!); + const scrollXY = scene.getScrollXY(scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN)!); const { scaleX, scaleY } = scene.getAncestorScale(); return skeleton.calculateCellIndexByPosition( @@ -1066,7 +1065,7 @@ export class SelectionRenderService implements ISelectionRenderService { endColumn: oldEndColumn, } = selectionControl?.model || { startRow: -1, endRow: -1, startColumn: -1, endColumn: -1 }; - const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN)!; + const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN)!; const targetViewport = this._getViewportByCell(oldEndRow, oldEndColumn) ?? viewportMain; diff --git a/packages/sheets-ui/src/services/selection/selection-shape-extension.ts b/packages/sheets-ui/src/services/selection/selection-shape-extension.ts index 579d1434581..096db2a2fbc 100644 --- a/packages/sheets-ui/src/services/selection/selection-shape-extension.ts +++ b/packages/sheets-ui/src/services/selection/selection-shape-extension.ts @@ -18,11 +18,10 @@ import type { IFreeze, IRangeWithCoord, Nullable, Observer, ThemeService } from '@univerjs/core'; import { ColorKit } from '@univerjs/core'; import type { IMouseEvent, IPointerEvent, Scene, SpreadsheetSkeleton, Viewport } from '@univerjs/engine-render'; -import { CURSOR_TYPE, isRectIntersect, Rect, ScrollTimer, ScrollTimerType, Vector2 } from '@univerjs/engine-render'; +import { CURSOR_TYPE, isRectIntersect, Rect, ScrollTimer, ScrollTimerType, SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; import { getNormalSelectionStyle, SELECTION_CONTROL_BORDER_BUFFER_WIDTH } from '@univerjs/sheets'; import type { Injector } from '@wendellhu/redi'; -import { VIEWPORT_KEY } from '../../common/keys'; import { SheetSkeletonManagerService } from '../sheet-skeleton-manager.service'; import type { SelectionShape } from './selection-shape'; import { ISelectionRenderService, RANGE_FILL_PERMISSION_CHECK, RANGE_MOVE_PERMISSION_CHECK } from './selection-render.service'; @@ -117,21 +116,21 @@ export class SelectionShapeExtension { }; switch (viewport.viewportKey) { - case VIEWPORT_KEY.VIEW_MAIN: + case SHEET_VIEWPORT_KEY.VIEW_MAIN: return selection.endRow >= freeze.startRow && selection.endColumn >= freeze.startColumn; - case VIEWPORT_KEY.VIEW_MAIN_TOP: - case VIEWPORT_KEY.VIEW_COLUMN_RIGHT: + case SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP: + case SHEET_VIEWPORT_KEY.VIEW_COLUMN_RIGHT: return selection.endColumn >= freeze.startColumn && selection.startRow < freeze.startRow; - case VIEWPORT_KEY.VIEW_MAIN_LEFT: - case VIEWPORT_KEY.VIEW_ROW_BOTTOM: + case SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT: + case SHEET_VIEWPORT_KEY.VIEW_ROW_BOTTOM: return selection.endRow >= freeze.startRow && selection.startColumn < freeze.startColumn; - case VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP: - case VIEWPORT_KEY.VIEW_COLUMN_LEFT: - case VIEWPORT_KEY.VIEW_ROW_TOP: - case VIEWPORT_KEY.VIEW_LEFT_TOP: + case SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP: + case SHEET_VIEWPORT_KEY.VIEW_COLUMN_LEFT: + case SHEET_VIEWPORT_KEY.VIEW_ROW_TOP: + case SHEET_VIEWPORT_KEY.VIEW_LEFT_TOP: return selection.startRow < freeze.startRow && selection.startColumn < freeze.startColumn; default: break; @@ -321,7 +320,7 @@ export class SelectionShapeExtension { // const relativeCoords = scene.getRelativeCoord(Vector2.FromArray([evtOffsetX, evtOffsetY])); // const { x: newEvtOffsetX, y: newEvtOffsetY } = relativeCoords; - const viewMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN)!; + const viewMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN)!; const scrollTimer = ScrollTimer.create(scene); @@ -804,11 +803,11 @@ export class SelectionShapeExtension { this._activeViewport = scene.getActiveViewportByCoord(Vector2.FromArray([evtOffsetX, evtOffsetY]))!; - const viewportMain = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); const scrollTimer = ScrollTimer.create( scene, - this._activeViewport.viewportKey === VIEWPORT_KEY.VIEW_MAIN ? ScrollTimerType.ALL : ScrollTimerType.NONE + this._activeViewport.viewportKey === SHEET_VIEWPORT_KEY.VIEW_MAIN ? ScrollTimerType.ALL : ScrollTimerType.NONE ); scrollTimer.startScroll(newEvtOffsetX, newEvtOffsetY, viewportMain); diff --git a/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts b/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts index 0db09dbe49b..311dbfbe601 100644 --- a/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts +++ b/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts @@ -43,8 +43,9 @@ export interface ISheetSkeletonManagerSearch { * The viewModel is also a temporary storage variable, which does not need to be persisted, * so it is managed uniformly through the service. */ -export class SheetSkeletonManagerService implements IDisposable, IRenderModule { - private _currentSkeleton: ISheetSkeletonManagerSearch = { +export class SheetSkeletonManagerService implements IDisposable { + private _currentSkeletonSearchParam: ISheetSkeletonManagerSearch = { + unitId: '', sheetId: '', }; @@ -78,7 +79,7 @@ export class SheetSkeletonManagerService implements IDisposable, IRenderModule { /** @deprecated */ getCurrent(): Nullable { - return this._getSkeleton(this._currentSkeleton); + return this._getSkeleton(this._currentSkeletonSearchParam); } getUnitSkeleton(unitId: string, sheetId: string): Nullable { @@ -109,7 +110,7 @@ export class SheetSkeletonManagerService implements IDisposable, IRenderModule { }); } - this._currentSkeleton = searchParam; + this._currentSkeletonSearchParam = searchParam; const nextParam = this.getCurrent(); this._currentSkeletonBefore$.next(nextParam); @@ -132,6 +133,10 @@ export class SheetSkeletonManagerService implements IDisposable, IRenderModule { param.skeleton.calculate(); } + makeDirtyCurrent(state: boolean = true) { + this.makeDirty(this._currentSkeletonSearchParam, state); + } + makeDirty(searchParm: ISheetSkeletonManagerSearch, state: boolean = true) { const param = this._getSkeleton(searchParm); if (param == null) { diff --git a/packages/sheets-ui/src/sheets-ui-plugin.ts b/packages/sheets-ui/src/sheets-ui-plugin.ts index e78d0c8778c..a9c6adb7e81 100644 --- a/packages/sheets-ui/src/sheets-ui-plugin.ts +++ b/packages/sheets-ui/src/sheets-ui-plugin.ts @@ -200,8 +200,8 @@ export class UniverSheetsUIPlugin extends Plugin { HeaderFreezeRenderController, HeaderUnhideRenderController, HeaderResizeRenderController, - SheetsZoomRenderController, SheetsScrollRenderController, + SheetsZoomRenderController, FormatPainterRenderController, HeaderMenuRenderController, CellAlertRenderController, diff --git a/packages/sheets-zen-editor/src/controllers/zen-editor.controller.ts b/packages/sheets-zen-editor/src/controllers/zen-editor.controller.ts index 24ce8dcf36b..299b8492f5a 100644 --- a/packages/sheets-zen-editor/src/controllers/zen-editor.controller.ts +++ b/packages/sheets-zen-editor/src/controllers/zen-editor.controller.ts @@ -29,16 +29,17 @@ import { } from '@univerjs/core'; import type { IDocObjectParam, IRichTextEditingMutationParams } from '@univerjs/docs'; import { + VIEWPORT_KEY as DOC_VIEWPORT_KEY, DocSkeletonManagerService, DocViewModelManagerService, getDocObject, RichTextEditingMutation, TextSelectionManagerService, - VIEWPORT_KEY, } from '@univerjs/docs'; +import type { Viewport } from '@univerjs/engine-render'; import { DeviceInputEventType, IRenderManagerService } from '@univerjs/engine-render'; -import { getEditorObject, IEditorBridgeService } from '@univerjs/sheets-ui'; import type { IEditorBridgeServiceParam } from '@univerjs/sheets-ui'; +import { getEditorObject, IEditorBridgeService } from '@univerjs/sheets-ui'; import { IZenZoneService } from '@univerjs/ui'; import { Inject, Injector } from '@wendellhu/redi'; import { takeUntil } from 'rxjs'; @@ -307,9 +308,9 @@ export class ZenEditorController extends RxDisposable { docsComponent.translate(docsLeft, docsTop); docBackground.translate(docsLeft, docsTop); - const viewport = scene.getViewport(VIEWPORT_KEY.VIEW_MAIN); + const viewport = scene.getViewport(DOC_VIEWPORT_KEY.VIEW_MAIN) as Viewport; if (scrollToX !== Number.POSITIVE_INFINITY && viewport != null) { - const actualX = viewport.getBarScroll(scrollToX, 0).x; + const actualX = viewport.transScroll2ViewportScrollValue(scrollToX, 0).x; viewport.scrollTo({ x: actualX, }); diff --git a/packages/slides/src/views/render/adaptors/docs-adaptor.ts b/packages/slides/src/views/render/adaptors/docs-adaptor.ts index 7ea87b7cf68..7b1055e5045 100644 --- a/packages/slides/src/views/render/adaptors/docs-adaptor.ts +++ b/packages/slides/src/views/render/adaptors/docs-adaptor.ts @@ -351,7 +351,7 @@ export class DocsAdaptor extends ObjectAdaptor { docsComponent.translate(docsLeft, docsTop); if (scrollToX !== Number.POSITIVE_INFINITY && viewport != null) { - const actualX = viewport.getBarScroll(scrollToX, 0).x; + const actualX = viewport.transScroll2ViewportScrollValue(scrollToX, 0).x; viewport.scrollTo({ x: actualX, }); diff --git a/packages/slides/src/views/render/adaptors/spreadsheet-adaptor.ts b/packages/slides/src/views/render/adaptors/spreadsheet-adaptor.ts index 31b911c36a7..64fd196e3b5 100644 --- a/packages/slides/src/views/render/adaptors/spreadsheet-adaptor.ts +++ b/packages/slides/src/views/render/adaptors/spreadsheet-adaptor.ts @@ -204,18 +204,18 @@ export class SpreadsheetAdaptor extends ObjectAdaptor { // viewMain.linkToViewport(viewLeft, LINK_VIEW_PORT_TYPE.Y); // viewMain.linkToViewport(viewTop, LINK_VIEW_PORT_TYPE.X); viewMain.onScrollAfterObserver.add((param: IScrollObserverParam) => { - const { scrollX, scrollY, actualScrollX, actualScrollY } = param; + const { scrollX, scrollY, viewportScrollX, viewportScrollY } = param; viewTop .updateScroll({ scrollX, - actualScrollX, + viewportScrollX, }); viewLeft .updateScroll({ scrollY, - actualScrollY, + viewportScrollY, }); }); diff --git a/packages/slides/src/views/render/canvas-view.ts b/packages/slides/src/views/render/canvas-view.ts index a172ff8c28d..fcb4bec7097 100644 --- a/packages/slides/src/views/render/canvas-view.ts +++ b/packages/slides/src/views/render/canvas-view.ts @@ -109,7 +109,7 @@ export class CanvasView extends RxDisposable { if (!viewMain || !getCenterPositionViewPort) return; const { left: viewPortLeft, top: viewPortTop } = getCenterPositionViewPort; - const { x, y } = viewMain.getBarScroll(viewPortLeft, viewPortTop); + const { x, y } = viewMain.transViewportScroll2ScrollValue(viewPortLeft, viewPortTop); viewMain.scrollTo({ x, From cd08cc9aaf40414ba3ceece69c5b748131624b49 Mon Sep 17 00:00:00 2001 From: lumixraku Date: Mon, 3 Jun 2024 20:27:18 +0800 Subject: [PATCH 2/3] fix: when update scroll should consider scale factor chore: do not change scrollXY when viewport width is negative --- packages/core/src/sheets/worksheet.ts | 7 ++ .../src/components/sheets/spreadsheet.ts | 2 + packages/engine-render/src/scene.ts | 18 ++++ packages/engine-render/src/viewport.ts | 33 +++++-- .../header-resize.render-controller.ts | 2 +- .../scroll.render-controller.ts | 91 +++++-------------- .../selection.render-controller.ts | 1 - .../zoom.render-controller.ts | 1 + .../controllers/sheet-render.controller.ts | 1 + .../src/services/scroll-manager.service.ts | 1 + packages/sheets-ui/src/sheets-ui-plugin.ts | 2 + 11 files changed, 83 insertions(+), 76 deletions(-) create mode 100644 packages/sheets-ui/src/controllers/sheet-render.controller.ts diff --git a/packages/core/src/sheets/worksheet.ts b/packages/core/src/sheets/worksheet.ts index 7f3b5af8a61..0ffd23dc59f 100644 --- a/packages/core/src/sheets/worksheet.ts +++ b/packages/core/src/sheets/worksheet.ts @@ -329,6 +329,13 @@ export class Worksheet { ); } + getScrollLeftTopFromSnapshot() { + return { + scrollLeft: this._snapshot.scrollLeft, + scrollTop: this._snapshot.scrollTop, + }; + } + /** * Return WorkSheetZoomRatio * @return zoomRatio diff --git a/packages/engine-render/src/components/sheets/spreadsheet.ts b/packages/engine-render/src/components/sheets/spreadsheet.ts index 4f75e44cab9..5205a293ded 100644 --- a/packages/engine-render/src/components/sheets/spreadsheet.ts +++ b/packages/engine-render/src/components/sheets/spreadsheet.ts @@ -224,7 +224,9 @@ export class Spreadsheet extends SheetComponent { } /** + * Since multiple controllers, not just the sheet-render.controller, invoke spreadsheet.makeDirty() — for instance, the cf.render-controller — it's essential to also call viewport.markDirty() whenever spreadsheet.makeDirty() is triggered. * @param state + * @returns */ override makeDirty(state: boolean = true) { (this.getParent() as Scene)?.getViewports().forEach((vp) => vp.markDirty(state)); diff --git a/packages/engine-render/src/scene.ts b/packages/engine-render/src/scene.ts index 28b0f8e4ccb..9e2002a8a00 100644 --- a/packages/engine-render/src/scene.ts +++ b/packages/engine-render/src/scene.ts @@ -230,8 +230,19 @@ export class Scene extends ThinScene { return this; } + setScaleValue(scaleX: number, scaleY: number) { + if (scaleX !== undefined) { + this.scaleX = scaleX; + } + + if (scaleY !== undefined) { + this.scaleY = scaleY; + } + } + /** * scale to value, absolute + * setTransform ---> viewport._updateScrollBarPosByViewportScroll ---> scrollTo */ scale(scaleX?: number, scaleY?: number) { const preScaleX = this.scaleX; @@ -284,6 +295,13 @@ export class Scene extends ThinScene { return this; } + /** + * This sequence will initiate a series of updates: + * scene._setTransForm --> viewport@resetCanvasSizeAndUpdateScrollBar ---> scrollTo ---> limitedScroll ---> onScrollBeforeObserver ---> setScrollInfo + * scrollInfo needs accurate scene width & height, limitedScroll depends on scene & engine's width & height + * @param state + * @returns + */ transformByState(state: ISceneTransformState) { const optionKeys = Object.keys(state); const preKeys: IObjectFullState = {}; diff --git a/packages/engine-render/src/viewport.ts b/packages/engine-render/src/viewport.ts index a022d59b6e5..50d726a55cf 100644 --- a/packages/engine-render/src/viewport.ts +++ b/packages/engine-render/src/viewport.ts @@ -108,6 +108,12 @@ export class Viewport { private _deltaViewportScrollX: number = 0; private _deltaViewportScrollY: number = 0; + /** + * physcal scene size (scene width * scale) + */ + private _physicalSceneWidth: number = 0; + private _physicalSceneHeight: number = 0; + onMouseWheelObserver = new Observable(); onScrollAfterObserver = new Observable(); @@ -517,6 +523,9 @@ export class Viewport { * _currentSkeleton$ ---> selection.render-controller ---> formula@_autoScroll ---> viewport.resize ---> get scrollXY by viewportScrollXY ---> scrollTo * _currentSkeleton$ ---> selection.render-controller ---> setCurrentSelection ---> formula@_autoScroll ---> scrollTo * _currentSkeleton$ ---> freeze.render-controller@_refreshFreeze --> viewport.resize ---> scrollTo ---> _scroll + * + * TODO: @lumix many side effects in scrollTo, it would update scrollXY & viewportScrollXY, and notify listeners of scrollInfo$ + * * Debug * window.scene.getViewports()[0].scrollTo({x: 14.2, y: 1.8}, true) */ @@ -1156,12 +1165,22 @@ export class Viewport { this.markForceDirty(true); } + /** + * Call this method when the viewport has resized. + */ private _updateScrollBarPosByViewportScroll() { + // zoom.render-controller ---> scene._setTransform --> _updateScrollBarPosByViewportScroll + // he width of scene's parent (engine) is zero at this time. + // viewport width is negative when canvas container has not been set to engine. + if (!this.width || this.width < 0) return; + if (!this.height || this.height < 0) return; const viewportScrollX = this.viewportScrollX; const viewportScrollY = this.viewportScrollY; const { width, height } = this._getViewPortSize(); const contentWidth = (this._scene.width - this._paddingEndX) * this._scene.scaleX; const contentHeight = (this._scene.height - this._paddingEndY) * this._scene.scaleY; + this._physicalSceneWidth = contentWidth; + this._physicalSceneHeight = contentHeight; if (this._scrollBar) { this._scrollBar.resize(width, height, contentWidth, contentHeight); @@ -1200,11 +1219,11 @@ export class Viewport { } else { height = (this._heightOrigin || 0) * scaleY; } - width = Math.max(0, width); - height = Math.max(0, height); + // width = Math.max(0, width); + // height = Math.max(0, height); - this._width = width; - this._height = height; + this.width = width; + this.height = height; // if (!forceCalculate && this._widthOrigin != null) { // width = this._widthOrigin; @@ -1245,7 +1264,7 @@ export class Viewport { y: number; }, scollBarX?: number, - scrollBarY?: number, + scrollBarY?: number ) { clearTimeout(this._scrollStopNum); this._scrollStopNum = setTimeout(() => { @@ -1259,7 +1278,7 @@ export class Viewport { viewportScrollY: scroll.y, limitX: this._scrollBar?.limitX, limitY: this._scrollBar?.limitY, - isTrigger: false + isTrigger: false, }); }, 2); } @@ -1324,9 +1343,9 @@ export class Viewport { this.viewportScrollX = clampedViewportScroll.x; this.viewportScrollY = clampedViewportScroll.y; - // scroll.render-controller@onScrollAfterObserver ---> setScrollInfo but no notify // calc startRow & offset by viewportScrollXY, then update scrollInfo // other viewports, rowHeader & colHeader depend on this notify + // scroll.render-controller@onScrollAfterObserver ---> setScrollInfo but no notify this.onScrollAfterObserver.notifyObservers({ isTrigger, viewport: this, diff --git a/packages/sheets-ui/src/controllers/render-controllers/header-resize.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/header-resize.render-controller.ts index b99b0c5d4a9..b814fa4cb33 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/header-resize.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/header-resize.render-controller.ts @@ -34,7 +34,7 @@ import type { import { DeltaColumnWidthCommand, DeltaRowHeightCommand, SetWorksheetRowIsAutoHeightCommand } from '@univerjs/sheets'; import { Inject } from '@wendellhu/redi'; -import { SHEET_COMPONENT_HEADER_LAYER_INDEX, SHEET_VIEW_KEY, SHEET_VIEWPORT_KEY } from '../../common/keys'; +import { SHEET_COMPONENT_HEADER_LAYER_INDEX, SHEET_VIEW_KEY } from '../../common/keys'; import { IEditorBridgeService } from '../../services/editor-bridge.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import { diff --git a/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts index 28f7b9810bd..5f346c5d5c4 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts @@ -165,7 +165,7 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); this.disposeWithMe( toDisposable( - // set scrollInfo, event triggered in viewport@_scrollToScrollbarPos + // set scrollInfo, the event is triggered in viewport@_scrollToScrollbarPos viewportMain?.onScrollAfterObserver.add((param: IScrollObserverParam) => { const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; if (skeleton == null || param.isTrigger === false) { @@ -185,9 +185,9 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM viewportScrollY ); - // update scroll infos in scrollManagerService again! - // because raw param from scroll-command offsetX may be negative or over max value. - // by the way, there is no need to set viewportScrollXY in lastestScrollInfo, _scrollManagerService._setScrollInfo would do this process. + // Refresh the scroll details in the scroll manager service. + // The raw offsetX parameter from the scroll command might be out of bounds, being either negative or exceeding the maximum value. + // Additionally, there's no need to manually update viewportScrollXY in the latest scroll info; the _scrollManagerService's _setScrollInfo(setScrollInfoToCurrSheetWithoutNotify) method takes care of this. const lastestScrollInfo: IScrollManagerParam = { sheetViewStartRow: row, sheetViewStartColumn: column, @@ -195,7 +195,7 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM offsetY: rowOffset, }; this._scrollManagerService.setScrollInfoToCurrSheetWithoutNotify(lastestScrollInfo); - this._scrollManagerService.setScrollInfoToSnapshot({...lastestScrollInfo, viewportScrollX, viewportScrollY}); + this._scrollManagerService.setScrollInfoToSnapshot({ ...lastestScrollInfo, viewportScrollX, viewportScrollY }); }) ) ); @@ -282,22 +282,27 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM if (param == null) { return; } - - // const { unitId } = this._context; - // const { sheetId } = param; - - // this._scrollManagerService.setSearchParam(param as unknown as ISheetSkeletonManagerParam); + this._scrollManagerService.setSearchParam(param as unknown as ISheetSkeletonManagerParam); const sheetObject = this._getSheetObject(); if (!sheetObject) return; const scene = sheetObject.scene; const viewportMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); const currScrollInfo = this._scrollManagerService.getScrollInfoByParam(param as unknown as IScrollManagerSearchParam); - if (viewportMain && currScrollInfo) { - viewportMain.viewportScrollX = currScrollInfo.viewportScrollX || 0; - viewportMain.viewportScrollY = currScrollInfo.viewportScrollY || 0; + + const workbook = this._context.unit; + const worksheet = workbook.getActiveSheet(); + + if (viewportMain) { + if (currScrollInfo) { + viewportMain.viewportScrollX = currScrollInfo.viewportScrollX || 0; + viewportMain.viewportScrollY = currScrollInfo.viewportScrollY || 0; + } else { + const { scrollLeft, scrollTop } = worksheet.getScrollLeftTopFromSnapshot(); + viewportMain.viewportScrollX = scrollLeft || 0; + viewportMain.viewportScrollY = scrollTop || 0; + } + this._updateSceneSize(param as unknown as ISheetSkeletonManagerParam); } - // this function would call setSearchParam - this._updateSceneSize(param as unknown as ISheetSkeletonManagerParam); }))); } @@ -316,9 +321,10 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM const { rowTotalHeight, columnTotalWidth, rowHeaderWidthAndMarginLeft, columnHeaderHeightAndMarginTop } = skeleton; - this._scrollManagerService.setSearchParam(param); - - // would cause viewport.resetSizeAndScrollBar + const workbook = this._context.unit; + const worksheet = workbook.getActiveSheet(); + const zoomRatio = worksheet.getZoomRatio() || 1; + scene?.setScaleValue(zoomRatio, zoomRatio); scene?.transformByState({ width: rowHeaderWidthAndMarginLeft + columnTotalWidth, height: columnHeaderHeightAndMarginTop + rowTotalHeight, @@ -481,53 +487,4 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM offsetY: startSheetViewRow === undefined ? offsetY : 0, }); } - - private _getViewports() { - const sheetObject = this._getSheetObject(); - if (sheetObject == null) { - return; - } - const { scene } = sheetObject; - - const viewColumnLeft = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_COLUMN_LEFT); - const viewColumnRight = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_COLUMN_RIGHT); - - // row header - const viewRowTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_ROW_TOP); - const viewRowBottom = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_ROW_BOTTOM); - - const viewLeftTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_LEFT_TOP); - - // skeleton - const viewMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN); - const viewMainLeftTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT_TOP); - const viewMainLeft = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_LEFT); - const viewMainTop = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN_TOP); - - if ( - viewColumnLeft == null || - viewColumnRight == null || - viewRowTop == null || - viewRowBottom == null || - viewLeftTop == null || - viewMain == null || - viewMainLeftTop == null || - viewMainLeft == null || - viewMainTop == null - ) { - return; - } - - return { - viewMain, - viewMainLeftTop, - viewMainLeft, - viewMainTop, - viewColumnLeft, - viewColumnRight, - viewRowTop, - viewRowBottom, - viewLeftTop, - }; - } } diff --git a/packages/sheets-ui/src/controllers/render-controllers/selection.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/selection.render-controller.ts index 93e2ea72c4b..67d35df7ea1 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/selection.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/selection.render-controller.ts @@ -42,7 +42,6 @@ import { Inject } from '@wendellhu/redi'; import { deserializeRangeWithSheet, IDefinedNamesService, isReferenceStrings, operatorToken } from '@univerjs/engine-formula'; import type { ISetZoomRatioOperationParams } from '../../commands/operations/set-zoom-ratio.operation'; import { SetZoomRatioOperation } from '../../commands/operations/set-zoom-ratio.operation'; -import { SHEET_VIEWPORT_KEY } from '../../common/keys'; import { ISelectionRenderService } from '../../services/selection/selection-render.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import type { ISheetObjectParam } from '../utils/component-tools'; diff --git a/packages/sheets-ui/src/controllers/render-controllers/zoom.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/zoom.render-controller.ts index d9d1fa3de53..37efcb1d959 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/zoom.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/zoom.render-controller.ts @@ -91,6 +91,7 @@ export class SheetsZoomRenderController extends Disposable implements IRenderMod const workbook = this._context.unit; const worksheet = workbook.getActiveSheet(); const zoomRatio = worksheet.getZoomRatio() || 1; + // viewport.resize --> setScrollInfo this._updateViewZoom(zoomRatio); })); } diff --git a/packages/sheets-ui/src/controllers/sheet-render.controller.ts b/packages/sheets-ui/src/controllers/sheet-render.controller.ts new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/packages/sheets-ui/src/controllers/sheet-render.controller.ts @@ -0,0 +1 @@ + diff --git a/packages/sheets-ui/src/services/scroll-manager.service.ts b/packages/sheets-ui/src/services/scroll-manager.service.ts index d95f2fe3a8c..3822b88c671 100644 --- a/packages/sheets-ui/src/services/scroll-manager.service.ts +++ b/packages/sheets-ui/src/services/scroll-manager.service.ts @@ -55,6 +55,7 @@ export class ScrollManagerService { @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService ) { + // init } dispose(): void { diff --git a/packages/sheets-ui/src/sheets-ui-plugin.ts b/packages/sheets-ui/src/sheets-ui-plugin.ts index a9c6adb7e81..1d4c143ea77 100644 --- a/packages/sheets-ui/src/sheets-ui-plugin.ts +++ b/packages/sheets-ui/src/sheets-ui-plugin.ts @@ -200,6 +200,8 @@ export class UniverSheetsUIPlugin extends Plugin { HeaderFreezeRenderController, HeaderUnhideRenderController, HeaderResizeRenderController, + // Caution: ScrollRenderController should placed before ZoomRenderController + // because ZoomRenderController ---> viewport.resize --> setScrollInfo, but ScrollRenderController needs scrollInfo SheetsScrollRenderController, SheetsZoomRenderController, FormatPainterRenderController, From 4d7082bca733a4d4e17249b339c9fc08f904ca86 Mon Sep 17 00:00:00 2001 From: lumixraku Date: Thu, 6 Jun 2024 18:18:31 +0800 Subject: [PATCH 3/3] test: should use sheetSkService from cur render --- packages/engine-render/src/viewport.ts | 20 +++++----- .../create-selection-command-test-bed.ts | 4 +- .../freeze.render-controller.ts | 40 +++++++++---------- .../scroll.render-controller.ts | 4 +- .../controllers/sheet-render.controller.ts | 1 - .../src/services/drag-manager.service.ts | 3 +- .../src/services/scroll-manager.service.ts | 11 +++-- .../sheet-skeleton-manager.service.ts | 7 +--- 8 files changed, 44 insertions(+), 46 deletions(-) delete mode 100644 packages/sheets-ui/src/controllers/sheet-render.controller.ts diff --git a/packages/engine-render/src/viewport.ts b/packages/engine-render/src/viewport.ts index 50d726a55cf..8f4ba89ebed 100644 --- a/packages/engine-render/src/viewport.ts +++ b/packages/engine-render/src/viewport.ts @@ -446,7 +446,8 @@ export class Viewport { } /** - * call when canvas element size change + * invoked when canvas element size change + * engineResizeObserver --> engine.resizeBySize --> scene._setTransForm */ resetCanvasSizeAndUpdateScrollBar() { this._resizeCacheCanvas(); @@ -463,15 +464,16 @@ export class Viewport { } /** - * 和 resetCanvasSizeAndScrollbar 不同 - * 此方法是调整冻结行列设置时 & 初始化时触发, resize window 时并不会触发 + * NOT same as resetCanvasSizeAndScrollbar + * This method is triggered when adjusting the frozen row & col settings, and during initialization, + * it is not triggered when resizing the window. * - * 注意参数 position 不一定有 height & width 对于 viewMain 只有 left top bottom right - * this.width this.height 也有可能是 undefined - * 因此应通过 _getViewPortSize 获取宽高 + * Note that the 'position' parameter may not always have 'height' and 'width' properties. For the 'viewMain' element, it only has 'left', 'top', 'bottom', and 'right' properties. + * Additionally, 'this.width' and 'this.height' may also be 'undefined'. + * Therefore, you should use the '_getViewPortSize' method to retrieve the width and height. * @param position */ - resize(position: IViewPosition) { + resizeWhenFreezeChange(position: IViewPosition) { const positionKeys = Object.keys(position); if (positionKeys.length === 0) { return; @@ -1039,7 +1041,6 @@ export class Viewport { this._scene.makeDirty(true); } - // 自己是否被选中 isHit(coord: Vector2) { if (this.isActive === false) { return; @@ -1166,11 +1167,10 @@ export class Viewport { } /** - * Call this method when the viewport has resized. + * This method will be invoked whenever the viewport is resized. */ private _updateScrollBarPosByViewportScroll() { // zoom.render-controller ---> scene._setTransform --> _updateScrollBarPosByViewportScroll - // he width of scene's parent (engine) is zero at this time. // viewport width is negative when canvas container has not been set to engine. if (!this.width || this.width < 0) return; if (!this.height || this.height < 0) return; diff --git a/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts b/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts index afb19dc78f3..9ce2c1a4bcc 100644 --- a/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts +++ b/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts @@ -19,8 +19,8 @@ import { ICommandService, LocaleType } from '@univerjs/core'; import { SetFrozenMutation, SetSelectionsOperation } from '@univerjs/sheets'; // FIXME: should not import from the inside of the package +import { IRenderManagerService, RenderManagerService } from '@univerjs/engine-render'; import { ScrollManagerService } from '../../../services/scroll-manager.service'; -import { SheetSkeletonManagerService } from '../../../services/sheet-skeleton-manager.service'; import { ShortcutExperienceService } from '../../../services/shortcut-experience.service'; import { CancelFrozenCommand, @@ -52,7 +52,7 @@ export function createFrozenCommandTestBed(workbookData?: IWorkbookData) { const { univer, get, sheet } = createCommandTestBed(workbookData || SIMPLE_SELECTION_WORKBOOK_DATA, [ [ShortcutExperienceService], [ScrollManagerService], - [SheetSkeletonManagerService], + [IRenderManagerService, { useClass: RenderManagerService }], ]); const commandService = get(ICommandService); diff --git a/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts index 2239df51256..620c64eddec 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts @@ -758,21 +758,21 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewLeftTop, } = viewports; - viewColumnRight.resize({ + viewColumnRight.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: 0, height: columnHeaderHeightAndMarginTop, right: 0, }); - viewRowBottom.resize({ + viewRowBottom.resizeWhenFreezeChange({ left: 0, top: columnHeaderHeightAndMarginTop, bottom: 0, width: rowHeaderWidthAndMarginLeft, }); - viewLeftTop.resize({ + viewLeftTop.resizeWhenFreezeChange({ left: 0, top: 0, width: rowHeaderWidthAndMarginLeft, @@ -812,7 +812,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM // cancel freeze if (isTopView === false && isLeftView === false) { - viewMain.resize({ + viewMain.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: columnHeaderHeightAndMarginTop, bottom: 0, @@ -822,7 +822,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM } else if (isTopView === true && isLeftView === false) { // freeze row const topGap = endSheetView.startY - startSheetView.startY; - viewMain.resize({ + viewMain.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: columnHeaderHeightAndMarginTop + topGap, bottom: 0, @@ -842,7 +842,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); } - viewMainTop.resize({ + viewMainTop.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: columnHeaderHeightAndMarginTop, height: topGap, @@ -854,7 +854,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM x: viewMain.scrollX, viewportScrollX: viewMain.viewportScrollX, }); - viewRowTop.resize({ + viewRowTop.resizeWhenFreezeChange({ left: 0, top: columnHeaderHeightAndMarginTop, width: rowHeaderWidthAndMarginLeft, @@ -864,7 +864,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM .updateScroll({ viewportScrollY: startSheetView.startY, }); - viewRowBottom.resize({ + viewRowBottom.resizeWhenFreezeChange({ left: 0, top: columnHeaderHeightAndMarginTop + topGap, bottom: 0, @@ -876,7 +876,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM } else if (isTopView === false && isLeftView === true) { // freeze column const leftGap = endSheetView.startX - startSheetView.startX; - viewMain.resize({ + viewMain.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft + leftGap, top: columnHeaderHeightAndMarginTop, bottom: 0, @@ -896,7 +896,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); } - viewMainLeft.resize({ + viewMainLeft.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: columnHeaderHeightAndMarginTop, width: leftGap, @@ -909,7 +909,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM y: viewMain.scrollY, viewportScrollY: viewMain.viewportScrollY, }); - viewColumnLeft.resize({ + viewColumnLeft.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: 0, width: leftGap, @@ -919,7 +919,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM .updateScroll({ viewportScrollX: startSheetView.startX, }); - viewColumnRight.resize({ + viewColumnRight.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft + leftGap, top: 0, height: columnHeaderHeightAndMarginTop, @@ -931,7 +931,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM } else { const leftGap = endSheetView.startX - startSheetView.startX; const topGap = endSheetView.startY - startSheetView.startY; - viewMain.resize({ + viewMain.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft + leftGap, top: columnHeaderHeightAndMarginTop + topGap, bottom: 0, @@ -961,7 +961,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM }); } - viewMainLeft.resize({ + viewMainLeft.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: columnHeaderHeightAndMarginTop + topGap, width: leftGap, @@ -973,7 +973,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM y: viewMain.scrollY, viewportScrollY: viewMain.viewportScrollY, }); - viewMainTop.resize({ + viewMainTop.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft + leftGap, top: columnHeaderHeightAndMarginTop, height: topGap, @@ -985,7 +985,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM x: viewMain.scrollX, viewportScrollX: viewMain.viewportScrollX, }); - viewMainLeftTop.resize({ + viewMainLeftTop.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: columnHeaderHeightAndMarginTop, width: leftGap, @@ -998,7 +998,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewportScrollY: startSheetView.startY, }); - viewRowTop.resize({ + viewRowTop.resizeWhenFreezeChange({ left: 0, top: columnHeaderHeightAndMarginTop, width: rowHeaderWidthAndMarginLeft, @@ -1010,14 +1010,14 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewportScrollY: startSheetView.startY, }); - viewRowBottom.resize({ + viewRowBottom.resizeWhenFreezeChange({ left: 0, top: columnHeaderHeightAndMarginTop + topGap, bottom: 0, width: rowHeaderWidthAndMarginLeft, }); - viewColumnLeft.resize({ + viewColumnLeft.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft, top: 0, width: leftGap, @@ -1029,7 +1029,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM viewportScrollX: startSheetView.startX, }); - viewColumnRight.resize({ + viewColumnRight.resizeWhenFreezeChange({ left: rowHeaderWidthAndMarginLeft + leftGap, top: 0, height: columnHeaderHeightAndMarginTop, diff --git a/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts index 5f346c5d5c4..206937a2827 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts @@ -22,7 +22,7 @@ import { RANGE_TYPE, toDisposable, } from '@univerjs/core'; -import type { IRenderContext, IRenderModule } from '@univerjs/engine-render'; +import type { IRenderContext, IRenderModule, IScrollObserverParam } from '@univerjs/engine-render'; import { IRenderManagerService, SHEET_VIEWPORT_KEY } from '@univerjs/engine-render'; import { ScrollToCellOperation, SelectionManagerService } from '@univerjs/sheets'; import { Inject } from '@wendellhu/redi'; @@ -282,7 +282,7 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM if (param == null) { return; } - this._scrollManagerService.setSearchParam(param as unknown as ISheetSkeletonManagerParam); + this._scrollManagerService.setSearchParam(param as unknown as IScrollManagerSearchParam); const sheetObject = this._getSheetObject(); if (!sheetObject) return; const scene = sheetObject.scene; diff --git a/packages/sheets-ui/src/controllers/sheet-render.controller.ts b/packages/sheets-ui/src/controllers/sheet-render.controller.ts deleted file mode 100644 index 8b137891791..00000000000 --- a/packages/sheets-ui/src/controllers/sheet-render.controller.ts +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/sheets-ui/src/services/drag-manager.service.ts b/packages/sheets-ui/src/services/drag-manager.service.ts index f22bb86333d..934cce752e7 100644 --- a/packages/sheets-ui/src/services/drag-manager.service.ts +++ b/packages/sheets-ui/src/services/drag-manager.service.ts @@ -75,9 +75,10 @@ export class DragManagerService extends Disposable { } const worksheet = workbook.getActiveSheet(); + // const skeletonParam = this._sheetSkeletonManagerService.getCurrent(); const currentRender = this._renderManagerService.getRenderById(workbook.getUnitId()); const skeletonParam = currentRender?.with(SheetSkeletonManagerService)?.getCurrent(); - + const scrollInfo = this._scrollManagerService.getCurrentScrollInfo(); if (!skeletonParam || !scrollInfo || !currentRender) return; diff --git a/packages/sheets-ui/src/services/scroll-manager.service.ts b/packages/sheets-ui/src/services/scroll-manager.service.ts index 3822b88c671..c7793630979 100644 --- a/packages/sheets-ui/src/services/scroll-manager.service.ts +++ b/packages/sheets-ui/src/services/scroll-manager.service.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { IUniverInstanceService, type Nullable } from '@univerjs/core'; +import { IUniverInstanceService, type Nullable, UniverInstanceType } from '@univerjs/core'; import { BehaviorSubject } from 'rxjs'; -import { Inject } from '@wendellhu/redi'; +import { IRenderManagerService } from '@univerjs/engine-render'; import { SheetSkeletonManagerService } from './sheet-skeleton-manager.service'; export interface IScrollManagerParam { @@ -53,7 +53,8 @@ export class ScrollManagerService { constructor( @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService + // @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService, + @IRenderManagerService private readonly _renderManagerService: IRenderManagerService ) { // init } @@ -163,7 +164,9 @@ export class ScrollManagerService { let { sheetViewStartColumn, sheetViewStartRow, offsetX, offsetY } = scrollInfo; sheetViewStartRow = sheetViewStartRow || 0; offsetY = offsetY || 0; - const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; + + // const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; + const skeleton = this._renderManagerService.withCurrentTypeOfUnit(UniverInstanceType.UNIVER_SHEET, SheetSkeletonManagerService)?.getCurrentSkeleton(); const rowAcc = skeleton?.rowHeightAccumulation[sheetViewStartRow - 1] || 0; const colAcc = skeleton?.columnWidthAccumulation[sheetViewStartColumn - 1] || 0; const viewportScrollX = colAcc + offsetX; diff --git a/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts b/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts index 311dbfbe601..7ecb89e9791 100644 --- a/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts +++ b/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts @@ -43,9 +43,8 @@ export interface ISheetSkeletonManagerSearch { * The viewModel is also a temporary storage variable, which does not need to be persisted, * so it is managed uniformly through the service. */ -export class SheetSkeletonManagerService implements IDisposable { +export class SheetSkeletonManagerService implements IDisposable, IRenderModule { private _currentSkeletonSearchParam: ISheetSkeletonManagerSearch = { - unitId: '', sheetId: '', }; @@ -133,10 +132,6 @@ export class SheetSkeletonManagerService implements IDisposable { param.skeleton.calculate(); } - makeDirtyCurrent(state: boolean = true) { - this.makeDirty(this._currentSkeletonSearchParam, state); - } - makeDirty(searchParm: ISheetSkeletonManagerSearch, state: boolean = true) { const param = this._getSkeleton(searchParm); if (param == null) {