From 6c7b8febbf9bbbc21cc5988f8470844a2dd8e434 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Mon, 17 Jun 2024 17:18:49 +0300 Subject: [PATCH] Improve edge scrolling (#3950) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR: - moves the edge scrolling logic into a manager - adds a new Editor option for `edgeScrollDelay` - adds a new Editor option for `edgeScrollEaseDuration` When in a state that would trigger an edge scroll, a delay is added before the scrolling starts. When scrolling does start, it is eased in by a certain duration. ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `improvement` — Improving existing features ### Test Plan 1. Drag shapes, resize, or drag select to the edge of the screen 2. The screen should move - [x] Unit Tests ### Release Notes - Add a delay and easing to edge scrolling. --------- Co-authored-by: Mitja Bezenšek --- packages/editor/api-report.md | 20 ++- packages/editor/src/index.ts | 2 +- packages/editor/src/lib/editor/Editor.ts | 9 ++ .../lib/editor/managers/EdgeScrollManager.ts | 128 ++++++++++++++++++ packages/editor/src/lib/options.ts | 6 +- .../editor/src/lib/utils/edgeScrolling.ts | 69 ---------- .../tools/SelectTool/childStates/Brushing.ts | 7 +- .../tools/SelectTool/childStates/Resizing.ts | 7 +- .../SelectTool/childStates/Translating.ts | 7 +- .../src/test/commands/setCamera.test.ts | 18 ++- .../tldraw/src/test/selection-omnibus.test.ts | 92 ++++++++++++- packages/tldraw/src/test/translating.test.ts | 26 ++-- 12 files changed, 294 insertions(+), 97 deletions(-) create mode 100644 packages/editor/src/lib/editor/managers/EdgeScrollManager.ts delete mode 100644 packages/editor/src/lib/utils/edgeScrolling.ts diff --git a/packages/editor/api-report.md b/packages/editor/api-report.md index 2ac364f10..9c9efeef1 100644 --- a/packages/editor/api-report.md +++ b/packages/editor/api-report.md @@ -679,8 +679,10 @@ export const defaultTldrawOptions: { readonly defaultSvgPadding: 32; readonly doubleClickDurationMs: 450; readonly dragDistanceSquared: 16; + readonly edgeScrollDelay: 200; readonly edgeScrollDistance: 8; - readonly edgeScrollSpeed: 20; + readonly edgeScrollEaseDuration: 200; + readonly edgeScrollSpeed: 25; readonly flattenImageBoundsExpand: 64; readonly flattenImageBoundsPadding: 16; readonly followChaseViewportSnap: 2; @@ -780,6 +782,14 @@ export class Edge2d extends Geometry2d { ul: number; } +// @public (undocumented) +export class EdgeScrollManager { + constructor(editor: Editor); + // (undocumented) + editor: Editor; + updateEdgeScrolling(elapsed: number): void; +} + // @public (undocumented) export class Editor extends EventEmitter { constructor({ store, user, shapeUtils, bindingUtils, tools, getContainer, cameraOptions, assetOptions, initialState, autoFocus, inferDarkMode, options, }: TLEditorOptions); @@ -883,6 +893,7 @@ export class Editor extends EventEmitter { distributeShapes(shapes: TLShape[] | TLShapeId[], operation: 'horizontal' | 'vertical'): this; duplicatePage(page: TLPage | TLPageId, createId?: TLPageId): this; duplicateShapes(shapes: TLShape[] | TLShapeId[], offset?: VecLike): this; + edgeScrollManager: EdgeScrollManager; readonly environment: EnvironmentManager; // @internal (undocumented) externalAssetContentHandlers: { @@ -1754,9 +1765,6 @@ export interface MatModel { f: number; } -// @public -export function moveCameraWhenCloseToEdge(editor: Editor): void; - // @internal (undocumented) export function normalizeWheel(event: React.WheelEvent | WheelEvent): { x: number; @@ -2573,8 +2581,12 @@ export interface TldrawOptions { // (undocumented) readonly dragDistanceSquared: number; // (undocumented) + readonly edgeScrollDelay: number; + // (undocumented) readonly edgeScrollDistance: number; // (undocumented) + readonly edgeScrollEaseDuration: number; + // (undocumented) readonly edgeScrollSpeed: number; // (undocumented) readonly flattenImageBoundsExpand: number; diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 8b77d470b..49183b250 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -136,6 +136,7 @@ export { type TLBindingUtilConstructor, } from './lib/editor/bindings/BindingUtil' export { ClickManager, type TLClickState } from './lib/editor/managers/ClickManager' +export { EdgeScrollManager } from './lib/editor/managers/EdgeScrollManager' export { EnvironmentManager } from './lib/editor/managers/EnvironmentManager' export { HistoryManager } from './lib/editor/managers/HistoryManager' export { ScribbleManager, type ScribbleItem } from './lib/editor/managers/ScribbleManager' @@ -361,7 +362,6 @@ export { setPointerCapture, stopEventPropagation, } from './lib/utils/dom' -export { moveCameraWhenCloseToEdge } from './lib/utils/edgeScrolling' export { getIncrementedName } from './lib/utils/getIncrementedName' export { getPointerInfo } from './lib/utils/getPointerInfo' export { getSvgPathFromPoints } from './lib/utils/getSvgPathFromPoints' diff --git a/packages/editor/src/lib/editor/Editor.ts b/packages/editor/src/lib/editor/Editor.ts index ba43f6ada..d95f7949e 100644 --- a/packages/editor/src/lib/editor/Editor.ts +++ b/packages/editor/src/lib/editor/Editor.ts @@ -125,6 +125,7 @@ import { parentsToChildren } from './derivations/parentsToChildren' import { deriveShapeIdsInCurrentPage } from './derivations/shapeIdsInCurrentPage' import { getSvgJsx } from './getSvgJsx' import { ClickManager } from './managers/ClickManager' +import { EdgeScrollManager } from './managers/EdgeScrollManager' import { EnvironmentManager } from './managers/EnvironmentManager' import { FocusManager } from './managers/FocusManager' import { HistoryManager } from './managers/HistoryManager' @@ -692,6 +693,7 @@ export class Editor extends EventEmitter { this.root.enter(undefined, 'initial') + this.edgeScrollManager = new EdgeScrollManager(this) this.focusManager = new FocusManager(this, autoFocus) this.disposables.add(this.focusManager.dispose.bind(this.focusManager)) @@ -791,6 +793,13 @@ export class Editor extends EventEmitter { */ readonly sideEffects: StoreSideEffects + /** + * A manager for moving the camera when the mouse is at the edge of the screen. + * + * @public + */ + edgeScrollManager: EdgeScrollManager + /** * A manager for ensuring correct focus. See FocusManager for details. * diff --git a/packages/editor/src/lib/editor/managers/EdgeScrollManager.ts b/packages/editor/src/lib/editor/managers/EdgeScrollManager.ts new file mode 100644 index 000000000..7d0a3733c --- /dev/null +++ b/packages/editor/src/lib/editor/managers/EdgeScrollManager.ts @@ -0,0 +1,128 @@ +import { Vec } from '../../primitives/Vec' +import { EASINGS } from '../../primitives/easings' +import { Editor } from '../Editor' + +/** @public */ +export class EdgeScrollManager { + constructor(public editor: Editor) {} + + private _isEdgeScrolling = false + private _edgeScrollDuration = -1 + + /** + * Update the camera position when the mouse is close to the edge of the screen. + * Run this on every tick when in a state where edge scrolling is enabled. + * + * @public + */ + updateEdgeScrolling(elapsed: number) { + const { editor } = this + const edgeScrollProximityFactor = this.getEdgeScroll() + if (edgeScrollProximityFactor.x === 0 && edgeScrollProximityFactor.y === 0) { + if (this._isEdgeScrolling) { + this._isEdgeScrolling = false + this._edgeScrollDuration = 0 + } + } else { + if (!this._isEdgeScrolling) { + this._isEdgeScrolling = true + this._edgeScrollDuration = 0 + } + this._edgeScrollDuration += elapsed + if (this._edgeScrollDuration > editor.options.edgeScrollDelay) { + const eased = + editor.options.edgeScrollEaseDuration > 0 + ? EASINGS.easeInCubic( + Math.min( + 1, + this._edgeScrollDuration / + (editor.options.edgeScrollDelay + editor.options.edgeScrollEaseDuration) + ) + ) + : 1 + this.moveCameraWhenCloseToEdge({ + x: edgeScrollProximityFactor.x * eased, + y: edgeScrollProximityFactor.y * eased, + }) + } + } + } + + /** + * Helper function to get the scroll proximity factor for a given position. + * @param position - The mouse position on the axis. + * @param dimension - The component dimension on the axis. + * @internal + */ + private getEdgeProximityFactors( + position: number, + dimension: number, + isCoarse: boolean, + insetStart: boolean, + insetEnd: boolean + ) { + const { editor } = this + const dist = editor.options.edgeScrollDistance + const pw = isCoarse ? editor.options.coarsePointerWidth : 0 // pointer width + const pMin = position - pw + const pMax = position + pw + const min = insetStart ? 0 : dist + const max = insetEnd ? dimension : dimension - dist + if (pMin < min) { + return Math.min(1, (min - pMin) / dist) + } else if (pMax > max) { + return -Math.min(1, (pMax - max) / dist) + } + return 0 + } + + private getEdgeScroll() { + const { editor } = this + const { + inputs: { + currentScreenPoint: { x, y }, + }, + } = editor + const screenBounds = editor.getViewportScreenBounds() + + const { + isCoarsePointer, + insets: [t, r, b, l], + } = editor.getInstanceState() + const proximityFactorX = this.getEdgeProximityFactors(x, screenBounds.w, isCoarsePointer, l, r) + const proximityFactorY = this.getEdgeProximityFactors(y, screenBounds.h, isCoarsePointer, t, b) + + return { + x: proximityFactorX, + y: proximityFactorY, + } + } + + /** + * Moves the camera when the mouse is close to the edge of the screen. + * @public + */ + private moveCameraWhenCloseToEdge(proximityFactor: { x: number; y: number }) { + const { editor } = this + if (!editor.inputs.isDragging || editor.inputs.isPanning || editor.getCameraOptions().isLocked) + return + + if (proximityFactor.x === 0 && proximityFactor.y === 0) return + + const screenBounds = editor.getViewportScreenBounds() + + // Determines how much the speed is affected by the screen size + const screenSizeFactorX = screenBounds.w < 1000 ? 0.612 : 1 + const screenSizeFactorY = screenBounds.h < 1000 ? 0.612 : 1 + + // Determines the base speed of the scroll + const zoomLevel = editor.getZoomLevel() + const pxSpeed = editor.user.getEdgeScrollSpeed() * editor.options.edgeScrollSpeed + const scrollDeltaX = (pxSpeed * proximityFactor.x * screenSizeFactorX) / zoomLevel + const scrollDeltaY = (pxSpeed * proximityFactor.y * screenSizeFactorY) / zoomLevel + + // update the camera + const { x, y, z } = editor.getCamera() + editor.setCamera(new Vec(x + scrollDeltaX, y + scrollDeltaY, z)) + } +} diff --git a/packages/editor/src/lib/options.ts b/packages/editor/src/lib/options.ts index 971ba8670..e239e6aa7 100644 --- a/packages/editor/src/lib/options.ts +++ b/packages/editor/src/lib/options.ts @@ -37,6 +37,8 @@ export interface TldrawOptions { readonly collaboratorCheckIntervalMs: number readonly cameraMovingTimeoutMs: number readonly hitTestMargin: number + readonly edgeScrollDelay: number + readonly edgeScrollEaseDuration: number readonly edgeScrollSpeed: number readonly edgeScrollDistance: number readonly coarsePointerWidth: number @@ -73,7 +75,9 @@ export const defaultTldrawOptions = { collaboratorCheckIntervalMs: 1200, cameraMovingTimeoutMs: 64, hitTestMargin: 8, - edgeScrollSpeed: 20, + edgeScrollDelay: 200, + edgeScrollEaseDuration: 200, + edgeScrollSpeed: 25, edgeScrollDistance: 8, coarsePointerWidth: 12, coarseHandleRadius: 20, diff --git a/packages/editor/src/lib/utils/edgeScrolling.ts b/packages/editor/src/lib/utils/edgeScrolling.ts deleted file mode 100644 index 1a0419b11..000000000 --- a/packages/editor/src/lib/utils/edgeScrolling.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Editor } from '../editor/Editor' -import { Vec } from '../primitives/Vec' - -/** - * Helper function to get the scroll proximity factor for a given position. - * @param position - The mouse position on the axis. - * @param dimension - The component dimension on the axis. - * @internal - */ -function getEdgeProximityFactor( - editor: Editor, - position: number, - dimension: number, - isCoarse: boolean, - insetStart: boolean, - insetEnd: boolean -) { - const dist = editor.options.edgeScrollDistance - const pw = isCoarse ? editor.options.coarsePointerWidth : 0 // pointer width - const pMin = position - pw - const pMax = position + pw - const min = insetStart ? 0 : dist - const max = insetEnd ? dimension : dimension - dist - if (pMin < min) { - return Math.min(1, (min - pMin) / dist) - } else if (pMax > max) { - return -Math.min(1, (pMax - max) / dist) - } - return 0 -} - -/** - * Moves the camera when the mouse is close to the edge of the screen. - * @public - */ -export function moveCameraWhenCloseToEdge(editor: Editor) { - if (!editor.inputs.isDragging || editor.inputs.isPanning || editor.getCameraOptions().isLocked) - return - - const { - inputs: { - currentScreenPoint: { x, y }, - }, - } = editor - const zoomLevel = editor.getZoomLevel() - const screenBounds = editor.getViewportScreenBounds() - - // Determines how much the speed is affected by the screen size - const screenSizeFactorX = screenBounds.w < 1000 ? 0.612 : 1 - const screenSizeFactorY = screenBounds.h < 1000 ? 0.612 : 1 - - const { - isCoarsePointer, - insets: [t, r, b, l], - } = editor.getInstanceState() - const proximityFactorX = getEdgeProximityFactor(editor, x, screenBounds.w, isCoarsePointer, l, r) - const proximityFactorY = getEdgeProximityFactor(editor, y, screenBounds.h, isCoarsePointer, t, b) - - if (proximityFactorX === 0 && proximityFactorY === 0) return - - // Determines the base speed of the scroll - const pxSpeed = editor.user.getEdgeScrollSpeed() * editor.options.edgeScrollSpeed - const scrollDeltaX = (pxSpeed * proximityFactorX * screenSizeFactorX) / zoomLevel - const scrollDeltaY = (pxSpeed * proximityFactorY * screenSizeFactorY) / zoomLevel - - const camera = editor.getCamera() - - editor.setCamera(new Vec(camera.x + scrollDeltaX, camera.y + scrollDeltaY, camera.z)) -} diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts index d44e2186e..527b535ac 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts @@ -12,8 +12,8 @@ import { TLPointerEventInfo, TLShape, TLShapeId, + TLTickEventInfo, Vec, - moveCameraWhenCloseToEdge, pointInPolygon, polygonsIntersect, } from '@tldraw/editor' @@ -62,8 +62,9 @@ export class Brushing extends StateNode { this.editor.updateInstanceState({ brush: null }) } - override onTick = () => { - moveCameraWhenCloseToEdge(this.editor) + override onTick = ({ elapsed }: TLTickEventInfo) => { + const { editor } = this + editor.edgeScrollManager.updateEdgeScrolling(elapsed) } override onPointerMove = () => { diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Resizing.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Resizing.ts index d03207ccc..07667ac77 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Resizing.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Resizing.ts @@ -14,11 +14,11 @@ import { TLShapeId, TLShapePartial, TLTextShape, + TLTickEventInfo, Vec, VecLike, areAnglesCompatible, compact, - moveCameraWhenCloseToEdge, } from '@tldraw/editor' import { kickoutOccludedShapes } from '../selectHelpers' @@ -72,8 +72,9 @@ export class Resizing extends StateNode { this.updateShapes() } - override onTick = () => { - moveCameraWhenCloseToEdge(this.editor) + override onTick = ({ elapsed }: TLTickEventInfo) => { + const { editor } = this + editor.edgeScrollManager.updateEdgeScrolling(elapsed) } override onPointerMove: TLEventHandlers['onPointerMove'] = () => { diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts index 6c4951725..f9a9a2d34 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts @@ -10,10 +10,10 @@ import { TLPointerEventInfo, TLShape, TLShapePartial, + TLTickEventInfo, Vec, compact, isPageId, - moveCameraWhenCloseToEdge, } from '@tldraw/editor' import { NOTE_ADJACENT_POSITION_SNAP_RADIUS, @@ -101,12 +101,13 @@ export class Translating extends StateNode { this.dragAndDropManager.clear() } - override onTick = () => { + override onTick = ({ elapsed }: TLTickEventInfo) => { + const { editor } = this this.dragAndDropManager.updateDroppingNode( this.snapshot.movingShapes, this.updateParentTransforms ) - moveCameraWhenCloseToEdge(this.editor) + editor.edgeScrollManager.updateEdgeScrolling(elapsed) } override onPointerMove = () => { diff --git a/packages/tldraw/src/test/commands/setCamera.test.ts b/packages/tldraw/src/test/commands/setCamera.test.ts index eb8de55c5..746190717 100644 --- a/packages/tldraw/src/test/commands/setCamera.test.ts +++ b/packages/tldraw/src/test/commands/setCamera.test.ts @@ -4,7 +4,12 @@ import { TestEditor } from '../TestEditor' let editor: TestEditor beforeEach(() => { - editor = new TestEditor() + editor = new TestEditor({ + options: { + edgeScrollDelay: 0, + edgeScrollEaseDuration: 0, + }, + }) editor.updateViewportScreenBounds(new Box(0, 0, 1600, 900)) }) @@ -227,11 +232,13 @@ describe('CameraOptions.panSpeed', () => { .forceTick() expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1.01 }) // 1 + 1 }) + it('Does not effect hand tool panning', () => { editor.setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, panSpeed: 2 }) editor.setCurrentTool('hand').pointerDown(0, 0).pointerMove(5, 10).forceTick() expect(editor.getCamera()).toMatchObject({ x: 5, y: 10, z: 1 }) }) + it('Effects spacebar panning (2x)', () => { editor.setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, panSpeed: 2 }) editor @@ -241,6 +248,7 @@ describe('CameraOptions.panSpeed', () => { .forceTick() expect(editor.getCamera()).toMatchObject({ x: 10, y: 20, z: 1 }) }) + it('Effects spacebar panning (0.5x)', () => { editor.setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, panSpeed: 0.5 }) editor @@ -250,6 +258,7 @@ describe('CameraOptions.panSpeed', () => { .forceTick() expect(editor.getCamera()).toMatchObject({ x: 2.5, y: 5, z: 1 }) }) + it('Does not effect edge scroll panning', () => { const shapeId = createShapeId() const viewportScreenBounds = editor.getViewportScreenBounds() @@ -261,11 +270,12 @@ describe('CameraOptions.panSpeed', () => { const shape = editor.getSelectedShapes()[0] editor.selectNone() // Move shape far beyond bounds to trigger edge scrolling at maximum speed - editor.pointerDown(shape.x, shape.y).pointerMove(-5000, -5000).forceTick() + expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1 }) + editor.pointerDown(shape.x, shape.y).pointerMove(-5000, -5000) // At maximum speed and a zoom level of 1, the camera should move by 40px per tick if the screen // is wider than 1000 pixels, or by 40 * 0.612px if it is smaller. - const newX = viewportScreenBounds.w < 1000 ? 40 * 0.612 : 40 - const newY = viewportScreenBounds.h < 1000 ? 40 * 0.612 : 40 + const newX = viewportScreenBounds.w < 1000 ? 25 * 0.612 : 25 + const newY = viewportScreenBounds.h < 1000 ? 25 * 0.612 : 25 expect(editor.getCamera()).toMatchObject({ x: newX, y: newY, z: 1 }) }) }) diff --git a/packages/tldraw/src/test/selection-omnibus.test.ts b/packages/tldraw/src/test/selection-omnibus.test.ts index e25915a0a..aa50b0ef1 100644 --- a/packages/tldraw/src/test/selection-omnibus.test.ts +++ b/packages/tldraw/src/test/selection-omnibus.test.ts @@ -16,7 +16,12 @@ const ids = { } beforeEach(() => { - editor = new TestEditor() + editor = new TestEditor({ + options: { + edgeScrollDelay: 0, + edgeScrollEaseDuration: 0, + }, + }) editor.setScreenBounds({ w: 3000, h: 3000, x: 0, y: 0 }) }) @@ -1951,3 +1956,88 @@ it('Ignores locked shapes when hovering', () => { editor.rightClick() expect(editor.getSelectedShapeIds()).toEqual([b.id]) }) + +describe('Edge scrolling', () => { + it('moves the camera correctly when delay and duration are zero', () => { + editor = new TestEditor({ + options: { + edgeScrollDelay: 0, + edgeScrollEaseDuration: 0, + }, + }) + editor.setScreenBounds({ w: 3000, h: 3000, x: 0, y: 0 }) + editor.user.updateUserPreferences({ edgeScrollSpeed: 1 }) + + editor.pointerMove(300, 300) + editor.pointerDown() + editor.pointerMove(0, 0) + + expect(editor.getCamera()).toMatchObject({ + x: editor.options.edgeScrollSpeed, + y: editor.options.edgeScrollSpeed, + }) + + editor.forceTick() + + expect(editor.getCamera()).toMatchObject({ + x: editor.options.edgeScrollSpeed * 2, + y: editor.options.edgeScrollSpeed * 2, + }) + }) + + it('moves the camera correctly when delay is 16 and duration are zero', () => { + editor = new TestEditor({ + options: { + edgeScrollDelay: 16, + edgeScrollEaseDuration: 0, + }, + }) + editor.setScreenBounds({ w: 3000, h: 3000, x: 0, y: 0 }) + editor.user.updateUserPreferences({ edgeScrollSpeed: 1 }) + + editor.pointerMove(300, 300) + editor.pointerDown() + editor.pointerMove(0, 0) + + // one tick's length of delay + expect(editor.getCamera()).toMatchObject({ + x: 0, + y: 0, + }) + + editor.forceTick() + + expect(editor.getCamera()).toMatchObject({ + x: editor.options.edgeScrollSpeed, + y: editor.options.edgeScrollSpeed, + }) + }) + + it('moves the camera correctly when delay is 0 and duration is 32', () => { + editor = new TestEditor({ + options: { + edgeScrollDelay: 0, + edgeScrollEaseDuration: 32, + }, + }) + editor.setScreenBounds({ w: 3000, h: 3000, x: 0, y: 0 }) + editor.user.updateUserPreferences({ edgeScrollSpeed: 1 }) + + editor.pointerMove(300, 300) + editor.pointerDown() + editor.pointerMove(0, 0) + + // one tick's length of delay + expect(editor.getCamera()).toMatchObject({ + x: editor.options.edgeScrollSpeed * 0.125, + y: editor.options.edgeScrollSpeed * 0.125, + }) + + editor.forceTick() + + expect(editor.getCamera()).toMatchObject({ + x: editor.options.edgeScrollSpeed * 1.125, + y: editor.options.edgeScrollSpeed * 1.125, + }) + }) +}) diff --git a/packages/tldraw/src/test/translating.test.ts b/packages/tldraw/src/test/translating.test.ts index 4464d560d..916a45416 100644 --- a/packages/tldraw/src/test/translating.test.ts +++ b/packages/tldraw/src/test/translating.test.ts @@ -40,7 +40,12 @@ const ids = { beforeEach(() => { console.error = jest.fn() - editor = new TestEditor() + editor = new TestEditor({ + options: { + edgeScrollDelay: 0, + edgeScrollEaseDuration: 0, + }, + }) }) const getNumSnapPoints = (snap: SnapIndicator): number => { @@ -139,10 +144,10 @@ describe('When translating...', () => { const before = editor.getShape(ids.box1)! - jest.advanceTimersByTime(100) + editor.forceTick() editor // The change is bigger than expected because the camera moves - .expectShapeToMatch({ id: ids.box1, x: -160, y: 10 }) + .expectShapeToMatch({ id: ids.box1, x: -65, y: 10 }) // We'll continue moving in the x postion, but now we'll also move in the y position. // The speed in the y position is smaller since we are further away from the edge. .pointerMove(0, 25) @@ -161,16 +166,21 @@ describe('When translating...', () => { editor.user.updateUserPreferences({ edgeScrollSpeed: 1 }) editor.pointerDown(50, 50, ids.box1).pointerMove(1080, 50) - jest.advanceTimersByTime(100) + editor.forceTick() + editor.forceTick() + editor.forceTick() editor // The change is bigger than expected because the camera moves - .expectShapeToMatch({ id: ids.box1, x: 1160, y: 10 }) + .expectShapeToMatch({ id: ids.box1, x: 1115, y: 10 }) .pointerMove(1080, 800) - jest.advanceTimersByTime(100) + + editor.forceTick() + editor.forceTick() + editor.forceTick() editor - .expectShapeToMatch({ id: ids.box1, x: 1320, y: 845.68 }) + .expectShapeToMatch({ id: ids.box1, x: 1215, y: 805.9 }) .pointerUp() - .expectShapeToMatch({ id: ids.box1, x: 1340, y: 857.92 }) + .expectShapeToMatch({ id: ids.box1, x: 1240, y: 821.2 }) }) it('translates multiple shapes', () => {