diff --git a/packages/editor/src/lib/constants.ts b/packages/editor/src/lib/constants.ts index e291420c9..d1a66a1ab 100644 --- a/packages/editor/src/lib/constants.ts +++ b/packages/editor/src/lib/constants.ts @@ -95,3 +95,6 @@ export const HIT_TEST_MARGIN = 8 /** @internal */ export const EDGE_SCROLL_SPEED = 20 + +/** @internal */ +export const EDGE_SCROLL_DISTANCE = 32 diff --git a/packages/editor/src/lib/utils/edgeScrolling.ts b/packages/editor/src/lib/utils/edgeScrolling.ts index f0670b2c2..02a978eae 100644 --- a/packages/editor/src/lib/utils/edgeScrolling.ts +++ b/packages/editor/src/lib/utils/edgeScrolling.ts @@ -1,24 +1,21 @@ -import { EDGE_SCROLL_SPEED } from '../constants' +import { EDGE_SCROLL_DISTANCE, EDGE_SCROLL_SPEED } from '../constants' import { Editor } from '../editor/Editor' /** - * Helper function to get the scroll offset for a given position. - * The closer the mouse is to the edge of the screen the faster we scroll. - * We also adjust the speed and the start offset based on the screen size and zoom level. - * - * @param editor - The mouse position on the screen in pixels - * @returns How much we should scroll in pixels + * 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 */ -export function getEdgeProximityFactor(position: number, scrollOffset: number, extreme: number) { +export function getEdgeProximityFactor(position: number, dimension: number) { if (position < 0) { return 1 - } else if (position > extreme) { + } else if (position > dimension) { return -1 - } else if (position < scrollOffset) { - return (scrollOffset - position) / scrollOffset - } else if (position > extreme - scrollOffset) { - return -(scrollOffset - extreme + position) / scrollOffset + } else if (position < EDGE_SCROLL_DISTANCE) { + return (EDGE_SCROLL_DISTANCE - position) / EDGE_SCROLL_DISTANCE + } else if (position > dimension - EDGE_SCROLL_DISTANCE) { + return -(EDGE_SCROLL_DISTANCE - dimension + position) / EDGE_SCROLL_DISTANCE } return 0 } @@ -38,22 +35,17 @@ export function moveCameraWhenCloseToEdge(editor: Editor) { const zoomLevel = editor.getZoomLevel() const screenBounds = editor.getViewportScreenBounds() - // Determines how far from the edges we start the scroll behaviour - const insetX = screenBounds.w < 1000 ? 40 : 32 - const insetY = screenBounds.h < 1000 ? 40 : 32 - // 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 pxSpeed = editor.user.getEdgeScrollSpeed() * EDGE_SCROLL_SPEED - - const proximityFactorX = getEdgeProximityFactor(x, insetX, screenBounds.w) - const proximityFactorY = getEdgeProximityFactor(y, insetY, screenBounds.h) + const proximityFactorX = getEdgeProximityFactor(x, screenBounds.w) + const proximityFactorY = getEdgeProximityFactor(y, screenBounds.h) if (proximityFactorX === 0 && proximityFactorY === 0) return + // Determines the base speed of the scroll + const pxSpeed = editor.user.getEdgeScrollSpeed() * EDGE_SCROLL_SPEED const scrollDeltaX = (pxSpeed * proximityFactorX * screenSizeFactorX) / zoomLevel const scrollDeltaY = (pxSpeed * proximityFactorY * screenSizeFactorY) / zoomLevel diff --git a/packages/tldraw/src/test/resizing.test.ts b/packages/tldraw/src/test/resizing.test.ts index dc61ef9d6..81d95dab5 100644 --- a/packages/tldraw/src/test/resizing.test.ts +++ b/packages/tldraw/src/test/resizing.test.ts @@ -5,6 +5,7 @@ import { PI2, PointsSnapLine, RotateCorner, + TLGeoShape, TLSelectionHandle, TLShapeId, TLShapePartial, @@ -3903,6 +3904,7 @@ describe('Resizing text from the right edge', () => { describe('When resizing near the edges of the screen', () => { it('resizes past the edge of the screen', () => { editor.user.updateUserPreferences({ edgeScrollSpeed: 1 }) + const before = editor.getShape(ids.boxA)! editor .select(ids.boxA) .pointerDown(10, 10, { @@ -3910,14 +3912,12 @@ describe('When resizing near the edges of the screen', () => { target: 'selection', handle: 'top_left', }) - .expectShapeToMatch({ id: ids.boxA, x: 10, y: 10, props: { w: 100, h: 100 } }) .pointerMove(10, 25) jest.advanceTimersByTime(1000) - editor.expectShapeToMatch({ - id: ids.boxA, - x: -842.5, - y: -259.58, - props: { w: 952.5, h: 369.58 }, - }) + const after = editor.getShape(ids.boxA)! + expect(after.x).toBeLessThan(before.x) + expect(after.y).toBeLessThan(before.y) + expect(after.props.w).toBeGreaterThan(before.props.w) + expect(after.props.h).toBeGreaterThan(before.props.h) }) }) diff --git a/packages/tldraw/src/test/translating.test.ts b/packages/tldraw/src/test/translating.test.ts index 08f8a7089..d21341a0e 100644 --- a/packages/tldraw/src/test/translating.test.ts +++ b/packages/tldraw/src/test/translating.test.ts @@ -3,6 +3,7 @@ import { PointsSnapLine, SnapLine, TLArrowShape, + TLGeoShape, TLShapeId, TLShapePartial, Vec2d, @@ -131,6 +132,8 @@ describe('When translating...', () => { editor.user.updateUserPreferences({ edgeScrollSpeed: 1 }) editor.pointerDown(50, 50, ids.box1).pointerMove(0, 50) // [-50, 0] + const before = editor.getShape(ids.box1)! + jest.advanceTimersByTime(100) editor // The change is bigger than expected because the camera moves @@ -139,10 +142,14 @@ describe('When translating...', () => { // The speed in the y position is smaller since we are further away from the edge. .pointerMove(0, 25) jest.advanceTimersByTime(100) - editor - .expectShapeToMatch({ id: ids.box1, x: -280, y: -42.54 }) - .pointerUp() - .expectShapeToMatch({ id: ids.box1, x: -280, y: -42.54 }) + editor.pointerUp() + + const after = editor.getShape(ids.box1)! + + expect(after.x).toBeLessThan(before.x) + expect(after.y).toBeLessThan(before.y) + expect(after.props.w).toEqual(before.props.w) + expect(after.props.h).toEqual(before.props.h) }) it('translates a single shape near the bottom right edge', () => {