From 35e4011f540d3f5c83a015637e2df7615d33aa87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E7=86=B1?= Date: Wed, 6 Aug 2025 12:40:01 +0800 Subject: [PATCH] refactor: revert "fix: no need disable event in scrollbar and selection" (#5650) --- examples/src/sheets/main.ts | 49 +- packages/engine-render/src/base-object.ts | 1 - .../engine-render/src/scene.input-manager.ts | 10 - packages/engine-render/src/scene.ts | 18 +- .../engine-render/src/shape/scroll-bar.ts | 760 ++++++++---------- packages/engine-render/src/shape/shape.ts | 3 +- .../ref-selections.render-service.ts | 2 +- .../base-selection-render.service.ts | 3 - .../selection/selection-render.service.ts | 4 +- .../selection/selection-shape-extension.ts | 6 +- 10 files changed, 399 insertions(+), 457 deletions(-) diff --git a/examples/src/sheets/main.ts b/examples/src/sheets/main.ts index e732762c7f..b112b42c21 100644 --- a/examples/src/sheets/main.ts +++ b/examples/src/sheets/main.ts @@ -21,7 +21,6 @@ import { UniverDocsPlugin } from '@univerjs/docs'; import { UniverDocsUIPlugin } from '@univerjs/docs-ui'; import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'; import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; -import { DEFAULT_WORKBOOK_DATA_DEMO } from '@univerjs/mockdata'; import zhCN from '@univerjs/mockdata/locales/zh-CN'; import { UniverNetworkPlugin } from '@univerjs/network'; import { UniverRPCMainThreadPlugin } from '@univerjs/rpc'; @@ -144,7 +143,53 @@ function createNewInstance() { // create univer sheet instance if (!IS_E2E) { - univer.createUnit(UniverInstanceType.UNIVER_SHEET, DEFAULT_WORKBOOK_DATA_DEMO); + univer.createUnit(UniverInstanceType.UNIVER_SHEET, { + id: 'fbpG8l', + sheetOrder: [ + 'xeyZKmZIRXwhSzwbec9-c', + ], + sheets: { + 'xeyZKmZIRXwhSzwbec9-c': { + id: 'xeyZKmZIRXwhSzwbec9-c', + name: 'Sheet1', + tabColor: '', + hidden: 0, + rowCount: 1000, + columnCount: 20, + zoomRatio: 1, + freeze: { + xSplit: 0, + ySplit: 0, + startRow: -1, + startColumn: -1, + }, + scrollTop: 0, + scrollLeft: 0, + defaultColumnWidth: 88, + defaultRowHeight: 24, + mergeData: [], + cellData: {}, + rowData: {}, + columnData: {}, + showGridlines: 1, + rowHeader: { + width: 46, + hidden: 0, + }, + columnHeader: { + height: 20, + hidden: 0, + }, + rightToLeft: 0, + }, + }, + resources: [ + { + name: 'SHEET_DATA_VALIDATION_PLUGIN', + data: '{"xeyZKmZIRXwhSzwbec9-c":[{"uid":"VvFh9x","type":"date","operator":"greaterThan","formula1":"2020-11-11","ranges":[{"startRow":0,"startColumn":0,"endRow":0,"endColumn":0,"rangeType":0}],"formula2":""},{"uid":"K2P_rg","type":"date","operator":"greaterThanOrEqual","formula1":"2025-11-12","ranges":[{"startRow":0,"startColumn":1,"endRow":0,"endColumn":1,"rangeType":0,"unitId":"fbpG8l","sheetId":"xeyZKmZIRXwhSzwbec9-c"}],"formula2":"","bizInfo":{"showTime":true}}]}', + }, + ], + }); } setTimeout(() => { diff --git a/packages/engine-render/src/base-object.ts b/packages/engine-render/src/base-object.ts index 3abe6ee965..3e723a2222 100644 --- a/packages/engine-render/src/base-object.ts +++ b/packages/engine-render/src/base-object.ts @@ -543,7 +543,6 @@ export abstract class BaseObject extends Disposable { } /** - * Similar to setProps, but only props in BASE_OBJECT_ARRAY_Set * this[pKey] = option[pKey] * @param option */ diff --git a/packages/engine-render/src/scene.input-manager.ts b/packages/engine-render/src/scene.input-manager.ts index ef3c358dbd..e8f6e6e308 100644 --- a/packages/engine-render/src/scene.input-manager.ts +++ b/packages/engine-render/src/scene.input-manager.ts @@ -429,9 +429,6 @@ export class InputManager extends Disposable { * @param offsetY */ private _getObjectAtPos(offsetX: number, offsetY: number) { - if (!this._scene.objectsEvented) { - return null; - } return this._scene?.pick(Vector2.FromArray([offsetX, offsetY])); } @@ -463,13 +460,6 @@ export class InputManager extends Disposable { // } - /** - * If return true, the event will be dispatched to Scene - * Even Scene is not a object, but scene could handle event. - * currentObject is null, return true - * @param currentObject - * @returns boolean - */ private _shouldDispatchEventToScene(currentObject: Nullable): boolean { // 1. Check for empty object if (currentObject == null) { diff --git a/packages/engine-render/src/scene.ts b/packages/engine-render/src/scene.ts index 9fb4da3336..e57b1a6755 100644 --- a/packages/engine-render/src/scene.ts +++ b/packages/engine-render/src/scene.ts @@ -480,11 +480,6 @@ export class Scene extends Disposable { return this._layers; } - /** - * Get layer by zIndex. - * This method would create a new Layer if Layer is not exist. - * @param zIndex - */ getLayer(zIndex: number = 1): Layer { for (const layer of this._layers) { if (layer.zIndex === zIndex) { @@ -521,8 +516,7 @@ export class Scene extends Disposable { } /** - * Add objects to Layer( Layer is specified by zIndex) - * This method would create a new Layer if Layer is not exist. + * Add objects to Layer( Layer is specfied by zIndex) * If object is a group, insert all its children and group itself to _objects[]. * @param objects * @param zIndex @@ -536,8 +530,7 @@ export class Scene extends Disposable { /** * Add object to Layer (Layer is specified by zIndex). - * This method would create a new Layer if Layer is not exist. - * And if object is a group, insert all its children and group itself to _objects[]. + * If object is a group, insert all its children and group itself to _objects[]. * @param o * @param zIndex layer index * @returns {Scene} scene @@ -995,9 +988,7 @@ export class Scene extends Disposable { const scrollBarRect = pickedViewport.pickScrollBar(coord); if (scrollBarRect) { - if (scrollBarRect.evented) { - return scrollBarRect; - } + return scrollBarRect; } const vecFromSheetContent = pickedViewport.transformVector2SceneCoord(coord); @@ -1267,9 +1258,8 @@ export class Scene extends Disposable { } /** - * Disable scene.event * If scene.event is disabled, scene.pick(cursor Pos) return null. - * After disableObjectsEvent, only the scene itself can respond to pointer events; objects beneath the scene will not. + * Then only scene itself can response to pointer event, all objects under the scene would not. * see sceneInputManager@_onPointerMove */ // 禁用对象事件 diff --git a/packages/engine-render/src/shape/scroll-bar.ts b/packages/engine-render/src/shape/scroll-bar.ts index d6d1b9b499..d6a21324e6 100644 --- a/packages/engine-render/src/shape/scroll-bar.ts +++ b/packages/engine-render/src/shape/scroll-bar.ts @@ -62,64 +62,56 @@ const DEFAULT_THUMB_MARGIN = 2; const HOVER_THUMB_MARGIN = 1; export class ScrollBar extends Disposable { - private _enableHorizontal: boolean = true; - private _enableVertical: boolean = true; + _enableHorizontal: boolean = true; + _enableVertical: boolean = true; - private _horizontalMetrics = { - thumbSize: 0, - minusMiniThumb: 0, - trackWidth: 0, - }; + horizontalThumbSize: number = 0; + horizontalMinusMiniThumb: number = 0; + horizontalTrackWidth: number = 0; + horizonScrollTrack: Nullable; + horizonThumbRect: Nullable; - private _verticalMetrics = { - thumbSize: 0, - minusMiniThumb: 0, - trackHeight: 0, - }; + verticalThumbSize: number = 0; + verticalTrackHeight: number = 0; + verticalMinusMiniThumb: number = 0; + verticalScrollTrack: Nullable; + verticalThumbRect: Nullable; - private _scrollElements = { - horizonTrack: null as Nullable, - horizonThumb: null as Nullable, - verticalTrack: null as Nullable, - verticalThumb: null as Nullable, - placeholder: null as Nullable, - }; + placeholderBarRect: Nullable; protected _viewport!: Viewport; private _mainScene: Nullable; - private _pointerState = { - lastX: -1, - lastY: -1, - isHorizonMove: false, - isVerticalMove: false, - }; + private _lastX: number = -1; + private _lastY: number = -1; - private _subscriptions = { - horizonMove: null as Nullable, - horizonUp: null as Nullable, - verticalMove: null as Nullable, - verticalUp: null as Nullable, - }; + private _isHorizonMove = false; + private _isVerticalMove = false; - private _colors = { - thumbDefault: 'rgba(24, 28, 42, 0.20)', - thumbHover: 'rgba(24, 28, 42, 0.30)', - thumbActive: 'rgba(24, 28, 42, 0.40)', - trackBackground: 'rgba(255,255,255,0.5)', - trackBorder: 'rgba(255,255,255,0.7)', - }; + private _horizonPointerMoveSub: Nullable; + private _horizonPointerUpSub: Nullable; + private _verticalPointerMoveSub: Nullable; + private _verticalPointerUpSub: Nullable; + + private _thumbDefaultBackgroundColor = 'rgba(24, 28, 42, 0.20)'; + private _thumbHoverBackgroundColor = 'rgba(24, 28, 42, 0.30)'; + private _thumbActiveBackgroundColor = 'rgba(24, 28, 42, 0.40)'; + private _trackBackgroundColor = 'rgba(255,255,255,0.5)'; + private _trackBorderColor = 'rgba(255,255,255,0.7)'; /** * The thickness of a scrolling track * ThumbSize = trackSize - thumbMargin * 2 */ private _trackThickness: number = DEFAULT_TRACK_SIZE; + // private _hTrackThickness: number = DEFAULT_TRACK_SIZE; + // private _vTrackThickness: number = DEFAULT_TRACK_SIZE; /** * The margin between thumb and bar. * ThumbSize = barSize - thumbMargin * 2 */ + // private _thumbMargin = DEFAULT_THUMB_MARGIN; private _vThumbMargin = DEFAULT_THUMB_MARGIN; private _hThumbMargin = DEFAULT_THUMB_MARGIN; @@ -145,10 +137,9 @@ export class ScrollBar extends Disposable { } this.setProps(props); this._viewport = view; - this._mainScene = view.scene; this._initialScrollRect(); - this._initialHorizontalEvent(); this._initialVerticalEvent(); + this._initialHorizontalEvent(); this._viewport.setScrollBar(this); } @@ -169,7 +160,7 @@ export class ScrollBar extends Disposable { }); if (Tools.isDefine(props.thumbBackgroundColor)) { - this._colors.thumbDefault = props.thumbBackgroundColor; + this._thumbDefaultBackgroundColor = props.thumbBackgroundColor; } if (Tools.isDefine(props.barSize)) { @@ -186,14 +177,6 @@ export class ScrollBar extends Disposable { } } - get verticalScrollTrack() { - return this._scrollElements.verticalTrack; - } - - get horizonScrollTrack() { - return this._scrollElements.horizonTrack; - } - get enableHorizontal() { return this._enableHorizontal; } @@ -211,89 +194,97 @@ export class ScrollBar extends Disposable { } get limitX() { - if (!this._scrollElements.horizonThumb?.visible) { + if (!this.horizonThumbRect?.visible) { return 0; } return this.horizontalTrackWidth - this.horizontalThumbSize; } get limitY() { - if (!this._scrollElements.verticalThumb?.visible) { + if (!this.verticalThumbRect?.visible) { return 0; } return this.verticalTrackHeight - this.verticalThumbSize; } - get ratioScrollX() { - if (!this._enableHorizontal) return 1; - const { thumbSize, minusMiniThumb, trackWidth } = this._horizontalMetrics; - if (thumbSize === undefined || trackWidth === undefined) return 0; - return thumbSize / (trackWidth - minusMiniThumb); + get ratioScrollX(): number { + if ( + this._enableHorizontal === false || + this.horizontalThumbSize === undefined || + this.horizontalTrackWidth === undefined + ) { + return 1; + } + + const ratio = ( + ((this.horizontalThumbSize - this.horizontalMinusMiniThumb) * this.miniThumbRatioX) / + this.horizontalTrackWidth + ); + + if (Number.isNaN(ratio)) { + return 1; + } else { + return ratio; + } } - get ratioScrollY() { - if (!this._enableVertical) return 1; - const { thumbSize, minusMiniThumb, trackHeight } = this._verticalMetrics; - if (thumbSize === undefined || trackHeight === undefined) return 0; - return thumbSize / (trackHeight - minusMiniThumb); + get ratioScrollY(): number { + if ( + this._enableVertical === false || + this.verticalThumbSize === undefined || + this.verticalTrackHeight === undefined + ) { + return 1; + } + const ratio = ( + ((this.verticalThumbSize - this.verticalMinusMiniThumb) * this.miniThumbRatioY) / this.verticalTrackHeight + ); + + if (Number.isNaN(ratio)) { + return 1; + } else { + return ratio; + } } - // get ratioX() { - // if (!this._enableHorizontal) return 0; - // const { thumbSize, minusMiniThumb, trackWidth } = this._horizontalMetrics; - // const { horizonThumb } = this._scrollElements; - // if (!horizonThumb?.getState()) return 0; - // return horizonThumb.getState().left / (trackWidth - minusMiniThumb); - // } - - // get ratioY() { - // if (!this._enableVertical) return 0; - // const { thumbSize, minusMiniThumb, trackHeight } = this._verticalMetrics; - // const { verticalThumb } = this._scrollElements; - // if (!verticalThumb?.getState()) return 0; - // return verticalThumb.getState().top / (trackHeight - minusMiniThumb); - // } - get miniThumbRatioX() { - if (!this._enableHorizontal) return 0; - const { thumbSize, minusMiniThumb, trackWidth } = this._horizontalMetrics; - if (thumbSize === undefined || trackWidth === undefined) return 0; - return (thumbSize - minusMiniThumb) / trackWidth; + const limit = this.horizontalTrackWidth - this.horizontalThumbSize; + + if (limit === 0) { + return 0; + } + + const actual = this.horizontalTrackWidth - (this.horizontalThumbSize - this.horizontalMinusMiniThumb); + + if (actual === 0) { + return 0; + } + + return limit / actual; } get miniThumbRatioY() { - if (!this._enableVertical) return 0; - const { thumbSize, minusMiniThumb, trackHeight } = this._verticalMetrics; - if (thumbSize === undefined || trackHeight === undefined) return 0; - return (thumbSize - minusMiniThumb) / trackHeight; - } + const limit = this.verticalTrackHeight - this.verticalThumbSize; - get horizontalTrackWidth() { - if (!this._enableHorizontal) return 0; - return this._viewportW - this._trackThickness; - } + if (limit === 0) { + return 0; + } - get horizontalThumbSize() { - if (!this._enableHorizontal) return 0; - return Math.max(MIN_THUMB_SIZE, this._viewportW * (this._viewportW / this._contentW)); - } + const actual = this.verticalTrackHeight - (this.verticalThumbSize - this.verticalMinusMiniThumb); - get verticalTrackHeight() { - if (!this._enableVertical) return 0; - return this._viewportH - this._trackThickness; - } + if (actual === 0) { + return 0; + } - get verticalThumbSize() { - if (!this._enableVertical) return 0; - return Math.max(MIN_THUMB_SIZE, this._viewportH * (this._viewportH / this._contentH)); + return limit / actual; } hasHorizonThumb() { - return this._scrollElements.horizonThumb?.visible || false; + return this.horizonThumbRect?.visible || false; } hasVerticalThumb() { - return this._scrollElements.verticalThumb?.visible || false; + return this.verticalThumbRect?.visible || false; } get scrollHorizonThumbThickness() { @@ -326,184 +317,164 @@ export class ScrollBar extends Disposable { override dispose() { super.dispose(); - const { horizonTrack, horizonThumb, verticalTrack, verticalThumb, placeholder } = this._scrollElements; - const { horizonMove, horizonUp, verticalMove, verticalUp } = this._subscriptions; + this.horizonScrollTrack?.dispose(); + this.horizonThumbRect?.dispose(); + this.verticalScrollTrack?.dispose(); + this.verticalThumbRect?.dispose(); + this.placeholderBarRect?.dispose(); - // Dispose scroll elements - horizonTrack?.dispose(); - horizonThumb?.dispose(); - verticalTrack?.dispose(); - verticalThumb?.dispose(); - placeholder?.dispose(); + this.horizonScrollTrack = null; + this.horizonThumbRect = null; + this.verticalScrollTrack = null; + this.verticalThumbRect = null; + this.placeholderBarRect = null; - // Clear references - this._scrollElements = { - horizonTrack: null, - horizonThumb: null, - verticalTrack: null, - verticalThumb: null, - placeholder: null, - }; - - // Cleanup subscriptions - horizonMove?.unsubscribe(); - horizonUp?.unsubscribe(); - verticalMove?.unsubscribe(); - verticalUp?.unsubscribe(); + this._horizonPointerMoveSub?.unsubscribe(); + this._horizonPointerUpSub?.unsubscribe(); + this._verticalPointerMoveSub?.unsubscribe(); + this._verticalPointerUpSub?.unsubscribe(); this._eventSub.unsubscribe(); - this._mainScene = null; this._viewport.removeScrollBar(); } render(ctx: UniverRenderingContext, left: number = 0, top: number = 0) { const { scrollX, scrollY } = this._viewport; - const { horizonTrack, horizonThumb, verticalTrack, verticalThumb, placeholder } = this._scrollElements; - ctx.save(); const transform = new Transform([1, 0, 0, 1, left, top]); const m = transform.getMatrix(); ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - - if (this._enableHorizontal && horizonTrack && horizonThumb) { - horizonTrack.render(ctx); - horizonThumb.translate(scrollX).render(ctx); + if (this._enableHorizontal) { + this.horizonScrollTrack!.render(ctx); + this.horizonThumbRect!.translate(scrollX).render(ctx); } - if (this._enableVertical && verticalTrack && verticalThumb) { - verticalTrack.render(ctx); - verticalThumb.translate(undefined, scrollY).render(ctx); + if (this._enableVertical) { + this.verticalScrollTrack!.render(ctx); + this.verticalThumbRect!.translate(undefined, scrollY).render(ctx); } - if (this._enableHorizontal && this._enableVertical && placeholder) { - placeholder.render(ctx); + if (this._enableHorizontal && this._enableVertical) { + this.placeholderBarRect!.render(ctx); } ctx.restore(); } private _resizeHorizontal() { - if (!this._enableHorizontal) return; - - const { horizonTrack, horizonThumb } = this._scrollElements; const viewportH = this._viewportH; const viewportW = this._viewportW; const contentWidth = this._contentW; - // Reset metrics - this._horizontalMetrics.minusMiniThumb = 0; - this._horizontalMetrics.trackWidth = viewportW - - (this._enableVertical ? this._trackThickness : 0) - - this._trackBorderThickness; - - // Calculate thumb size - this._horizontalMetrics.thumbSize = - ((this._horizontalMetrics.trackWidth * - (this._horizontalMetrics.trackWidth - this._trackBorderThickness)) / contentWidth) * - this._thumbLengthRatio; - - // Enforce minimum thumb size - if (this._horizontalMetrics.thumbSize < this._minThumbSizeH) { - this._horizontalMetrics.minusMiniThumb = this._minThumbSizeH - this._horizontalMetrics.thumbSize; - this._horizontalMetrics.thumbSize = this._minThumbSizeH; + // ratioScrollY = 内容可视区高度/内容实际区高度= 滑动条的高度/滑道高度=滚动条的顶部距离/实际内容区域顶部距离; + if (!this._enableHorizontal) { + return; } - // Update track position and size - horizonTrack?.transformByState({ + this.horizontalMinusMiniThumb = 0; + this.horizontalTrackWidth = viewportW - (this._enableVertical ? this._trackThickness : 0) - this._trackBorderThickness; + + this.horizontalThumbSize = + ((this.horizontalTrackWidth * (this.horizontalTrackWidth - this._trackBorderThickness)) / contentWidth) * + this._thumbLengthRatio; + + // this._horizontalThumbWidth = this._horizontalThumbWidth < MINI_THUMB_SIZE ? MINI_THUMB_SIZE : this._horizontalThumbWidth; + if (this.horizontalThumbSize < this._minThumbSizeH) { + this.horizontalMinusMiniThumb = this._minThumbSizeH - this.horizontalThumbSize; + this.horizontalThumbSize = this._minThumbSizeH; + } + + this.horizonScrollTrack?.transformByState({ left: 0, top: viewportH - this._trackThickness, - width: this._horizontalMetrics.trackWidth, + width: this.horizontalTrackWidth, height: Math.max(0, this._trackThickness - this._trackBorderThickness), }); - // Handle thumb visibility and position - if (this._horizontalMetrics.thumbSize >= viewportW - (this._trackThickness + 2)) { - horizonThumb?.setProps({ visible: false }); + // content is smaller than viewport size + if (this.horizontalThumbSize >= viewportW - (this._trackThickness + 2)) { + this.horizonThumbRect?.setProps({ + visible: false, + }); } else { - if (!horizonThumb?.visible) { - horizonThumb?.setProps({ visible: true }); + if (!this.horizonThumbRect?.visible) { + this.horizonThumbRect?.setProps({ + visible: true, + }); } - horizonThumb?.transformByState({ + this.horizonThumbRect?.transformByState({ left: this._viewport.scrollX, top: viewportH - this._trackThickness + this._hThumbMargin, - width: this._horizontalMetrics.thumbSize, + width: this.horizontalThumbSize, height: this.scrollHorizonThumbThickness, }); } } private _resizeVertical() { - if (!this._enableVertical) return; - - const { verticalTrack, verticalThumb } = this._scrollElements; const viewportH = this._viewportH; const viewportW = this._viewportW; const contentHeight = this._contentH; - // Reset metrics - this._verticalMetrics.minusMiniThumb = 0; - this._verticalMetrics.trackHeight = viewportH - - (this._enableHorizontal ? this._trackThickness : 0) - - this._trackBorderThickness; - - // Calculate thumb size - this._verticalMetrics.thumbSize = - ((this._verticalMetrics.trackHeight * - this._verticalMetrics.trackHeight) / contentHeight) * - this._thumbLengthRatio; - - // Enforce minimum thumb size - if (this._verticalMetrics.thumbSize < this._minThumbSizeV) { - this._verticalMetrics.minusMiniThumb = this._minThumbSizeV - this._verticalMetrics.thumbSize; - this._verticalMetrics.thumbSize = this._minThumbSizeV; + if (!this._enableVertical) { + return; } - // Update track position and size - verticalTrack?.transformByState({ + this.verticalMinusMiniThumb = 0; + this.verticalTrackHeight = viewportH - (this._enableHorizontal ? this._trackThickness : 0) - this._trackBorderThickness; + this.verticalThumbSize = + ((this.verticalTrackHeight * this.verticalTrackHeight) / contentHeight) * this._thumbLengthRatio; + // this._verticalThumbHeight = this._verticalThumbHeight < MINI_THUMB_SIZE ? MINI_THUMB_SIZE : this._verticalThumbHeight; + if (this.verticalThumbSize < this._minThumbSizeV) { + this.verticalMinusMiniThumb = this._minThumbSizeV - this.verticalThumbSize; + this.verticalThumbSize = this._minThumbSizeV; + } + + this.verticalScrollTrack?.transformByState({ left: viewportW - this._trackThickness, top: 0, width: Math.max(0, this._trackThickness - this._trackBorderThickness), - height: this._verticalMetrics.trackHeight, + height: this.verticalTrackHeight, }); - // Handle thumb visibility and position - if (this._verticalMetrics.thumbSize >= viewportH - this._trackThickness) { - verticalThumb?.setProps({ visible: false }); + // content is smaller than viewport size + if (this.verticalThumbSize >= viewportH - this._trackThickness) { + this.verticalThumbRect?.setProps({ + visible: false, + }); } else { - if (!verticalThumb?.visible) { - verticalThumb?.setProps({ visible: true }); + if (!this.verticalThumbRect?.visible) { + this.verticalThumbRect?.setProps({ + visible: true, + }); } - verticalThumb?.transformByState({ + this.verticalThumbRect?.transformByState({ left: viewportW - this._trackThickness + this._vThumbMargin, top: this._viewport.scrollY, width: this.scrollVerticalThumbThickness, - height: this._verticalMetrics.thumbSize, + height: this.verticalThumbSize, }); } } private _resizeRightBottomCorner() { - if (!this._enableHorizontal || !this._enableVertical) return; - - const { placeholder } = this._scrollElements; const viewportH = this._viewportH; const viewportW = this._viewportW; - const thickness = Math.max(0, this._trackThickness - this._trackBorderThickness); - - placeholder?.transformByState({ - left: viewportW - this._trackThickness, - top: viewportH - this._trackThickness, - width: thickness, - height: thickness, - }); + if (this._enableHorizontal && this._enableVertical) { + this.placeholderBarRect?.transformByState({ + left: viewportW - this._trackThickness, + top: viewportH - this._trackThickness, + width: Math.max(0, this._trackThickness - this._trackBorderThickness), + height: Math.max(0, this._trackThickness - this._trackBorderThickness), + }); + } } private _viewportH = 0; private _viewportW = 0; private _contentW = 0; private _contentH = 0; - /** * Adjust scroll track & thumb size based on the viewport size. * @param viewportWidth @@ -532,13 +503,11 @@ export class ScrollBar extends Disposable { } makeDirty(state: boolean) { - const { horizonTrack, horizonThumb, verticalTrack, verticalThumb, placeholder } = this._scrollElements; - - horizonTrack?.makeDirty(state); - horizonThumb?.makeDirty(state); - verticalTrack?.makeDirty(state); - verticalThumb?.makeDirty(state); - placeholder?.makeDirty(state); + this.horizonScrollTrack?.makeDirty(state); + this.horizonThumbRect?.makeDirty(state); + this.verticalScrollTrack?.makeDirty(state); + this.verticalThumbRect?.makeDirty(state); + this.placeholderBarRect?.makeDirty(state); this.makeViewDirty(state); } @@ -549,290 +518,245 @@ export class ScrollBar extends Disposable { } pick(coord: Vector2) { - if (this._scrollElements.horizonThumb?.isHit(coord)) { - return this._scrollElements.horizonThumb; + if (this.horizonThumbRect?.isHit(coord)) { + return this.horizonThumbRect; } - if (this._scrollElements.verticalThumb?.isHit(coord)) { - return this._scrollElements.verticalThumb; + if (this.verticalThumbRect?.isHit(coord)) { + return this.verticalThumbRect; } - if (this._scrollElements.horizonTrack?.isHit(coord)) { - return this._scrollElements.horizonTrack; + if (this.horizonScrollTrack?.isHit(coord)) { + return this.horizonScrollTrack; } - if (this._scrollElements.verticalTrack?.isHit(coord)) { - return this._scrollElements.verticalTrack; - } - - if (this._scrollElements.verticalThumb?.isHit(coord)) { - return this._scrollElements.verticalThumb; - } - - if (this._scrollElements.horizonTrack?.isHit(coord)) { - return this._scrollElements.horizonTrack; - } - - if (this._scrollElements.verticalTrack?.isHit(coord)) { - return this._scrollElements.verticalTrack; + if (this.verticalScrollTrack?.isHit(coord)) { + return this.verticalScrollTrack; } return null; } private _initialScrollRect() { - const { thumbDefault, trackBackground, trackBorder } = this._colors; - - const trackConfig = { - fill: trackBackground, - strokeWidth: this._trackBorderThickness, - stroke: trackBorder, - }; - - const thumbConfig = { - fill: thumbDefault, - strokeWidth: 0, - }; - if (this._enableHorizontal) { - const horizonTrack = new Rect('__horizonBarRect__', { - ...trackConfig, - width: this._viewportW, - height: this._trackThickness, - left: 0, - top: this._viewportH - this._trackThickness, + this.horizonScrollTrack = new Rect('__horizonBarRect__', { + fill: this._trackBackgroundColor!, + strokeWidth: this._trackBorderThickness, + stroke: this._trackBorderColor!, }); - const horizonThumb = new Rect('__horizonThumbRect__', { - ...thumbConfig, + this.horizonThumbRect = new Rect('__horizonThumbRect__', { radius: 6, - width: this.horizontalThumbSize, - height: this.scrollHorizonThumbThickness, - left: 0, - top: this._viewportH - this._trackThickness + this._hThumbMargin, + fill: this._thumbDefaultBackgroundColor!, }); - - this._scrollElements.horizonTrack = horizonTrack; - this._scrollElements.horizonThumb = horizonThumb; } if (this._enableVertical) { - const verticalTrack = new Rect('__verticalBarRect__', { - ...trackConfig, - width: this._trackThickness, - height: this._viewportH, - left: this._viewportW - this._trackThickness, - top: 0, + this.verticalScrollTrack = new Rect('__verticalBarRect__', { + fill: this._trackBackgroundColor!, + strokeWidth: this._trackBorderThickness, + stroke: this._trackBorderColor!, }); - const verticalThumb = new Rect('__verticalThumbRect__', { - ...thumbConfig, + this.verticalThumbRect = new Rect('__verticalThumbRect__', { radius: 6, - width: this.scrollVerticalThumbThickness, - height: this.verticalThumbSize, - left: this._viewportW - this._trackThickness + this._vThumbMargin, - top: 0, + fill: this._thumbDefaultBackgroundColor!, }); + } - this._scrollElements.verticalTrack = verticalTrack; - this._scrollElements.verticalThumb = verticalThumb; + if (this._enableHorizontal && this._enableVertical) { + this.placeholderBarRect = new Rect('__placeholderBarRect__', { + fill: this._trackBackgroundColor!, + strokeWidth: this._trackBorderThickness, + stroke: this._trackBorderColor!, + }); } } - private _setHorizonEvented(evented: boolean) { - this._scrollElements.horizonThumb && (this._scrollElements.horizonThumb.evented = evented); - this._scrollElements.horizonTrack && (this._scrollElements.horizonTrack.evented = evented); - } - - private _setVerticalEvented(evented: boolean) { - this._scrollElements.verticalThumb && (this._scrollElements.verticalThumb.evented = evented); - this._scrollElements.verticalTrack && (this._scrollElements.verticalTrack.evented = evented); - } - private _initialVerticalEvent() { + if (!this._enableVertical) { + return; + } + const mainScene = this._mainScene || this._viewport.scene; - const { thumbDefault, thumbHover, thumbActive } = this._colors; + + if (this.verticalThumbRect) { + this._eventSub.add(this.verticalThumbRect.onPointerEnter$.subscribeEvent((evt: unknown, state: EventState) => { + this._verticalHoverFunc(this._thumbHoverBackgroundColor!, evt, state); + })); + } + if (this.verticalThumbRect) { + this._eventSub.add(this.verticalThumbRect.onPointerLeave$.subscribeEvent((evt: unknown, state: EventState) => { + this._verticalHoverLeaveFunc(this._thumbDefaultBackgroundColor!, evt, state); + })); + } + + // events for pointerdown at scroll track + if (this.verticalScrollTrack) { + this._eventSub.add(this.verticalScrollTrack.onPointerDown$.subscribeEvent((evt: unknown, state: EventState) => { + const e = evt as IPointerEvent | IMouseEvent; + this._viewport.scrollToBarPos({ + y: e.offsetY - this._viewport.top - this.verticalThumbSize / 2, + }); + + state.stopPropagation(); + })); + } // drag events for vertical scrollbar // scene.input-manager@_onPointerDown --> base-object@triggerPointerDown! - if (this._scrollElements.verticalThumb) { - const verticalThumb = this._scrollElements.verticalThumb; - - // Pointer enter event - this._eventSub.add(verticalThumb.onPointerEnter$.subscribeEvent((evt: unknown, state: EventState) => { - this._verticalHoverFunc(thumbHover, evt, state); - })); - - // Pointer leave event - this._eventSub.add(verticalThumb.onPointerLeave$.subscribeEvent((evt: unknown, state: EventState) => { - if (verticalThumb.evented) { - this._verticalHoverLeaveFunc(thumbDefault, evt, state); - } - })); - - // Pointer down event - this._eventSub.add(verticalThumb.onPointerDown$.subscribeEvent((evt: unknown, state: EventState) => { + if (this.verticalThumbRect) { + this._eventSub.add(this.verticalThumbRect.onPointerDown$.subscribeEvent((evt: unknown, state: EventState) => { const e = evt as IPointerEvent | IMouseEvent; - this._pointerState.isVerticalMove = true; - this._pointerState.lastX = e.offsetX; - this._pointerState.lastY = e.offsetY; - - verticalThumb.setProps({ fill: thumbActive }); - this._setVerticalEvented(false); - mainScene.setCaptureObject(verticalThumb); + const srcElement = this.verticalThumbRect; + this._isVerticalMove = true; + this._lastX = e.offsetX; + this._lastY = e.offsetY; + // srcElement.fill = this._thumbHoverBackgroundColor!; + srcElement?.setProps({ + fill: this._thumbActiveBackgroundColor!, + }); + mainScene.setCaptureObject(this.verticalThumbRect!); + mainScene.disableObjectsEvent(); this.makeViewDirty(true); state.stopPropagation(); })); } - // Handle pointer move events - this._subscriptions.verticalMove = mainScene.onPointerMove$.subscribeEvent((evt: unknown, _state: EventState) => { - const e = evt as IPointerEvent | IMouseEvent; - if (!this._pointerState.isVerticalMove) return; - - this._viewport.scrollByBarDeltaValue({ - y: e.offsetY - this._pointerState.lastY, - }); - - this._pointerState.lastY = e.offsetY; - mainScene.getEngine()?.setCapture(); - }); - - // Handle pointer up events - this._subscriptions.verticalUp = mainScene.onPointerUp$.subscribeEvent((evt: unknown, state: EventState) => { - const { verticalThumb } = this._scrollElements; - const { thumbHover } = this._colors; - - this._pointerState.isVerticalMove = false; - this._verticalHoverLeaveFunc(thumbDefault, evt, state); - mainScene.releaseCapturedObject(); - mainScene.enableObjectsEvent(); - if (verticalThumb) { - verticalThumb.setProps({ fill: thumbHover }); - this._setVerticalEvented(true); - } - this.makeViewDirty(true); - }); - } - - private _initialHorizontalEvent() { - if (!this._enableHorizontal) return; - - const mainScene = this._mainScene || this._viewport.scene; - const { horizonThumb, horizonTrack } = this._scrollElements; - const { thumbHover, thumbDefault, thumbActive } = this._colors; - - // Thumb hover events - if (horizonThumb) { - this._eventSub.add( - horizonThumb.onPointerEnter$.subscribeEvent((evt: unknown, state: EventState) => { - this._horizonHoverFunc(thumbHover, evt, state); - }) - ); - - this._eventSub.add( - horizonThumb.onPointerLeave$.subscribeEvent((evt: unknown, state: EventState) => { - if (horizonThumb.evented) { - this._horizonHoverLeaveFunc(thumbDefault, evt, state); - } - }) - ); - } - - // Track click events - if (horizonTrack) { - this._eventSub.add( - horizonTrack.onPointerDown$.subscribeEvent((evt: unknown, state: EventState) => { - const e = evt as IPointerEvent | IMouseEvent; - this._viewport.scrollToBarPos({ - x: e.offsetX - this._viewport.left - this._horizontalMetrics.thumbSize / 2, - }); - state.stopPropagation(); - }) - ); - } - - // Thumb drag events - if (horizonThumb) { - this._eventSub.add( - horizonThumb.onPointerDown$.subscribeEvent((evt: unknown, state: EventState) => { - const e = evt as IPointerEvent | IMouseEvent; - this._pointerState.isHorizonMove = true; - this._pointerState.lastX = e.offsetX; - this._pointerState.lastY = e.offsetY; - - horizonThumb.setProps({ fill: thumbActive }); - this._setHorizonEvented(false); - mainScene.setCaptureObject(horizonThumb); - // mainScene.disableObjectsEvent(); - this.makeViewDirty(true); - state.stopPropagation(); - }) - ); - } // pointer down then move on scrollbar - this._subscriptions.horizonMove = mainScene.onPointerMove$.subscribeEvent((evt: unknown, _state: EventState) => { + this._verticalPointerMoveSub = mainScene.onPointerMove$.subscribeEvent((evt: unknown, _state: EventState) => { const e = evt as IPointerEvent | IMouseEvent; - if (!this._pointerState.isHorizonMove) { + if (!this._isVerticalMove) { return; } this._viewport.scrollByBarDeltaValue({ - x: e.offsetX - this._pointerState.lastX, + y: e.offsetY - this._lastY, }); - this._pointerState.lastX = e.offsetX; + + this._lastY = e.offsetY; mainScene.getEngine()?.setCapture(); }); - this._subscriptions.horizonUp = mainScene.onPointerUp$.subscribeEvent((evt: unknown, state: EventState) => { - this._pointerState.isHorizonMove = false; + + this._verticalPointerUpSub = mainScene.onPointerUp$.subscribeEvent((_evt: unknown, _state: EventState) => { + const srcElement = this.verticalThumbRect; + this._isVerticalMove = false; mainScene.releaseCapturedObject(); mainScene.enableObjectsEvent(); - this._horizonHoverLeaveFunc(thumbDefault, evt, state); - this._scrollElements.horizonThumb?.setProps({ - fill: thumbDefault, + srcElement?.setProps({ + fill: this._thumbHoverBackgroundColor!, }); - this._setHorizonEvented(true); this.makeViewDirty(true); }); } private _horizonHoverFunc(color: string, evt: unknown, state: EventState) { - const { horizonThumb } = this._scrollElements; + // this._trackThickness = HOVER_TRACK_SIZE; this._hThumbMargin = HOVER_THUMB_MARGIN; this._resizeHorizontal(); this._resizeRightBottomCorner(); - this._hoverFunc(color, horizonThumb!)(evt, state); + this._hoverFunc(color, this.horizonThumbRect!)(evt, state); } private _horizonHoverLeaveFunc(color: string, evt: unknown, state: EventState) { - const { horizonThumb } = this._scrollElements; + // this._trackThickness = DEFAULT_TRACK_SIZE; this._hThumbMargin = DEFAULT_THUMB_MARGIN; this._resizeHorizontal(); this._resizeRightBottomCorner(); - this._hoverFunc(color, horizonThumb!)(evt, state); + this._hoverFunc(color, this.horizonThumbRect!)(evt, state); } - private _verticalHoverFunc = (color: string, evt: unknown, state: EventState) => { - const { verticalThumb } = this._scrollElements; + private _verticalHoverFunc(color: string, evt: unknown, state: EventState) { this._vThumbMargin = HOVER_THUMB_MARGIN; this._resizeVertical(); this._resizeRightBottomCorner(); - this._hoverFunc(color, verticalThumb!)(evt, state); - }; + this._hoverFunc(color, this.verticalThumbRect!)(evt, state); + } private _verticalHoverLeaveFunc(color: string, evt: unknown, state: EventState) { - const { verticalThumb } = this._scrollElements; this._vThumbMargin = DEFAULT_THUMB_MARGIN; this._resizeVertical(); this._resizeRightBottomCorner(); - this._hoverFunc(color, verticalThumb!)(evt, state); + this._hoverFunc(color, this.verticalThumbRect!)(evt, state); } private _hoverFunc(color: string, thumb: Rect): (evt: unknown, state: EventState) => void { return (_evt: unknown, _state: EventState) => { - thumb.setProps({ fill: color }); - this._trackThickness = HOVER_TRACK_SIZE; + thumb.setProps({ + fill: color, + }); + // this._trackThickness = HOVER_TRACK_SIZE; this._resizeHorizontal(); this.makeViewDirty(true); }; } + + private _initialHorizontalEvent() { + if (!this._enableHorizontal) { + return; + } + + const mainScene = this._mainScene || this._viewport.scene; + + if (this.horizonThumbRect) { + this._eventSub.add(this.horizonThumbRect.onPointerEnter$.subscribeEvent((evt: unknown, state: EventState) => { + this._horizonHoverFunc(this._thumbHoverBackgroundColor, evt, state); + })); + } + if (this.horizonThumbRect) { + this._eventSub.add(this.horizonThumbRect.onPointerLeave$.subscribeEvent((evt: unknown, state: EventState) => { + this._horizonHoverLeaveFunc(this._thumbDefaultBackgroundColor, evt, state); + })); + } + + // events for pointerdown at scrolltrack + if (this.horizonScrollTrack) { + this._eventSub.add(this.horizonScrollTrack.onPointerDown$.subscribeEvent((evt: unknown, state: EventState) => { + const e = evt as IPointerEvent | IMouseEvent; + this._viewport.scrollToBarPos({ + x: e.offsetX - this._viewport.left - this.horizontalThumbSize / 2, + }); + state.stopPropagation(); + })); + } + + // drag and move event + if (this.horizonThumbRect) { + this._eventSub.add(this.horizonThumbRect.onPointerDown$.subscribeEvent((evt: unknown, state: EventState) => { + const e = evt as IPointerEvent | IMouseEvent; + this._isHorizonMove = true; + this._lastX = e.offsetX; + this._lastY = e.offsetY; + this.horizonThumbRect?.setProps({ + fill: this._thumbActiveBackgroundColor!, + }); + this.makeViewDirty(true); + mainScene.setCaptureObject(this.horizonThumbRect!); + mainScene.disableObjectsEvent(); + state.stopPropagation(); + })); + } + + // pointer down then move on scrollbar + this._horizonPointerMoveSub = mainScene.onPointerMove$.subscribeEvent((evt: unknown, _state: EventState) => { + const e = evt as IPointerEvent | IMouseEvent; + if (!this._isHorizonMove) { + return; + } + this._viewport.scrollByBarDeltaValue({ + x: e.offsetX - this._lastX, + }); + this._lastX = e.offsetX; + mainScene.getEngine()?.setCapture(); + }); + this._horizonPointerUpSub = mainScene.onPointerUp$.subscribeEvent((evt: unknown, state: EventState) => { + ; + this._isHorizonMove = false; + mainScene.releaseCapturedObject(); + mainScene.enableObjectsEvent(); + this.horizonThumbRect?.setProps({ + fill: this._thumbHoverBackgroundColor!, + }); + this.makeViewDirty(true); + }); + } } diff --git a/packages/engine-render/src/shape/shape.ts b/packages/engine-render/src/shape/shape.ts index 04a35305da..843a611202 100644 --- a/packages/engine-render/src/shape/shape.ts +++ b/packages/engine-render/src/shape/shape.ts @@ -346,8 +346,7 @@ export abstract class Shape extends BaseObject { } /** - * if props not in BASE_OBJECT_ARRAY_Set then this[_key] = props[key] - * if props in BASE_OBJECT_ARRAY_Set, You should use transformByState + * if BASE_OBJECT_ARRAY_Set.has(key) not exist, then this[_key] = props[key], * @param props */ setProps(props?: T): Shape { diff --git a/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts b/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts index 9bb938cf97..f61c3cc7c8 100644 --- a/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts +++ b/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts @@ -386,7 +386,7 @@ export class RefSelectionsRenderService extends BaseSelectionRenderService imple this._selectionMoveStart$.next(this.getSelectionDataWithStyle()); - // scene.disableObjectsEvent(); + scene.disableObjectsEvent(); this._clearUpdatingListeners(); this._addEndingListeners(); diff --git a/packages/sheets-ui/src/services/selection/base-selection-render.service.ts b/packages/sheets-ui/src/services/selection/base-selection-render.service.ts index 73a7ce6816..94eda35cc2 100644 --- a/packages/sheets-ui/src/services/selection/base-selection-render.service.ts +++ b/packages/sheets-ui/src/services/selection/base-selection-render.service.ts @@ -751,9 +751,6 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele } } - /** - * Unsubscribe subjects and enable scene event - */ protected _clearUpdatingListeners(): void { const scene = this._scene; scene.enableObjectsEvent(); 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 f8417f97a2..3aa6376f36 100644 --- a/packages/sheets-ui/src/services/selection/selection-render.service.ts +++ b/packages/sheets-ui/src/services/selection/selection-render.service.ts @@ -78,8 +78,6 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl const { spreadsheetRowHeader, spreadsheetColumnHeader, spreadsheet, spreadsheetLeftTopPlaceholder } = sheetObject; const { scene } = this._context; - // pointer down ---> selection start - // but pointer move & pointer up for selection end is bind on scene, not spreadsheet. this.disposeWithMe(spreadsheet?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { if (this.isSelectionDisabled()) return; if (this.inRefSelectionMode()) return; @@ -434,7 +432,7 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl } //#endregion - // scene.disableObjectsEvent(); + scene.disableObjectsEvent(); this._clearUpdatingListeners(); this._addEndingListeners(); scene.getTransformer()?.clearSelectedObjects(); 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 efc31781ac..72db0965a0 100644 --- a/packages/sheets-ui/src/services/selection/selection-shape-extension.ts +++ b/packages/sheets-ui/src/services/selection/selection-shape-extension.ts @@ -351,7 +351,7 @@ export class SelectionShapeExtension { this._scrollTimer = scrollTimer; scrollTimer.startScroll(newEvtOffsetX, newEvtOffsetY, viewMain); - // scene.disableObjectsEvent(); + scene.disableObjectsEvent(); this._scenePointerMoveSub = scene.onPointerMove$.subscribeEvent((moveEvt: IPointerEvent | IMouseEvent) => { if (this._disabled) { @@ -493,7 +493,7 @@ export class SelectionShapeExtension { scrollTimer.startScroll(newEvtOffsetX, newEvtOffsetY, viewMain); this._scrollTimer = scrollTimer; - // scene.disableObjectsEvent(); + scene.disableObjectsEvent(); this._scenePointerMoveSub = scene.onPointerMove$.subscribeEvent((moveEvt: IPointerEvent | IMouseEvent) => { const { offsetX: moveOffsetX, offsetY: moveOffsetY } = moveEvt; @@ -851,7 +851,7 @@ export class SelectionShapeExtension { this._scrollTimer = scrollTimer; - // scene.disableObjectsEvent(); + scene.disableObjectsEvent(); this._controlHandler((o) => { this._fillControlColors.push(o.fill as string);