From 23cf8729bc5b98811affb456af55049fac49d2fe Mon Sep 17 00:00:00 2001 From: Taha <98838967+Taha-Hassan-Git@users.noreply.github.com> Date: Tue, 4 Jun 2024 08:59:14 +0100 Subject: [PATCH] Taha/more constraints tests (#3863) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a test each for 'contain' behaviour and mixed x and y values. 1. Contain behaviour test: Lots of complicated maths that I put together from hunting around in the editor code. I wasn't really sure how to calculate the final state of the camera, so the test just checks that the camera changes at all. 2. Mixed values test: different values for bounds and padding are tested implicitly elsewhere in the file. This checks that different values can be set for behaviour and origin. ### Change Type - [ ] `sdk` — Changes the tldraw SDK - [ ] `dotcom` — Changes the tldraw.com web app - [ ] `docs` — Changes to the documentation, examples, or templates. - [ ] `vs code` — Changes to the vscode plugin - [x] `internal` — Does not affect user-facing stuff - [ ] `bugfix` — Bug fix - [ ] `feature` — New feature - [ ] `improvement` — Improving existing features - [ ] `chore` — Updating dependencies, other boring stuff - [ ] `galaxy brain` — Architectural changes - [x] `tests` — Changes to any test code - [ ] `tools` — Changes to infrastructure, CI, internal scripts, debugging tools, etc. - [ ] `dunno` — I don't know ### Test Plan ### Release Notes - Adds more tests for the camera constraints API --- .../src/test/commands/setCamera.test.ts | 96 +++++++++++++++++-- 1 file changed, 88 insertions(+), 8 deletions(-) diff --git a/packages/tldraw/src/test/commands/setCamera.test.ts b/packages/tldraw/src/test/commands/setCamera.test.ts index bd64e4fb0..eb8de55c5 100644 --- a/packages/tldraw/src/test/commands/setCamera.test.ts +++ b/packages/tldraw/src/test/commands/setCamera.test.ts @@ -863,9 +863,49 @@ describe('Padding', () => { }) describe('Contain behavior', () => { - it.todo( - 'Locks axis until the bounds are bigger than the padded viewport, then allows "inside" panning' - ) + it('Locks axis until the bounds are smaller than the padded viewport, then allows "inside" panning', () => { + const boundsW = 1600 + const boundsH = 900 + const padding = 100 + editor.setCameraOptions({ + ...DEFAULT_CAMERA_OPTIONS, + constraints: { + ...DEFAULT_CONSTRAINTS, + bounds: { x: 0, y: 0, w: boundsW, h: boundsH }, + behavior: 'contain', + origin: { x: 0.5, y: 0.5 }, + padding: { x: padding, y: padding }, + initialZoom: 'fit-max', + baseZoom: 'fit-max', + }, + }) + + editor.setCamera(editor.getCamera(), { reset: true }) + + const baseZoom = 700 / 900 + const x = padding / baseZoom - boundsW + (boundsW - padding * 2) / baseZoom - padding + const y = padding / baseZoom - boundsH + (boundsH - padding * 2) / baseZoom + expect(editor.getCamera()).toCloselyMatchObject({ x, y, z: baseZoom }, 5) + // We should not be able to pan + editor.pan(new Vec(-10000, -10000)) + expect(editor.getCamera()).toCloselyMatchObject({ x, y, z: baseZoom }, 5) + // But we can zoom + editor.zoomOut() + const newZoom = 0.5 * baseZoom + const newX = + padding / newZoom - boundsW + (boundsW - padding * 2) / newZoom - boundsW / 2 - padding * 2 + const newY = padding / newZoom - boundsH + (boundsH - padding * 2) / newZoom - boundsH / 2 + const newCamera = { x: newX, y: newY, z: newZoom } + expect(editor.getCamera()).toCloselyMatchObject(newCamera, 5) + // Panning is still locked + editor.pan(new Vec(-10000, -10000)) + expect(editor.getCamera()).toCloselyMatchObject(newCamera, 5) + // Zooming to within bounds will allow us to pan + editor.zoomIn().zoomIn() + const camera = editor.getCamera() + editor.pan(new Vec(-10000, -10000)) + expect(editor.getCamera()).not.toMatchObject(camera) + }) }) describe('Inside behavior', () => { @@ -886,12 +926,12 @@ describe('Inside behavior', () => { expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1 }) // panning far outside of the bounds editor.pan(new Vec(-10000, -10000)) - jest.advanceTimersByTime(300) + // should be clamped to the bounds + padding expect(editor.getCamera()).toMatchObject({ x: -100, y: -100, z: 1 }) // panning to the opposite direction, far outside of the bounds editor.pan(new Vec(10000, 10000)) - jest.advanceTimersByTime(300) + // should be clamped to the bounds + padding expect(editor.getCamera()).toMatchObject({ x: 100, y: 100, z: 1 }) }) @@ -915,19 +955,59 @@ describe('Outside behavior', () => { expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1 }) // panning far outside of the bounds editor.pan(new Vec(-10000, -10000)) - jest.advanceTimersByTime(300) + // should be clamped so that the far edge of the bounds is adjacent to the viewport + padding expect(editor.getCamera()).toMatchObject({ x: -bounds.w + 100, y: -bounds.h + 100, z: 1 }) // panning to the opposite direction, far outside of the bounds editor.pan(new Vec(10000, 10000)) - jest.advanceTimersByTime(300) + // should be clamped so that the far edge of the bounds is adjacent to the viewport + padding expect(editor.getCamera()).toMatchObject({ x: bounds.w - 100, y: bounds.h - 100, z: 1 }) }) }) describe('Allows mixed values for x and y', () => { - it.todo('Allows different values to be set for x and y axes') + it('Allows different values to be set for x and y behaviour', () => { + editor.setCameraOptions({ + ...DEFAULT_CAMERA_OPTIONS, + constraints: { + ...DEFAULT_CONSTRAINTS, + behavior: { x: 'inside', y: 'outside' }, + initialZoom: 'fit-x', + baseZoom: 'fit-x', + }, + }) + editor.setCamera(editor.getCamera(), { reset: true }) + const camera = editor.getCamera() + editor.pan(new Vec(-100, 0)) + + // no change when panning on x axis because it's set to inside + expect(editor.getCamera()).toMatchObject(camera) + editor.pan(new Vec(0, -100)) + + // change when panning on y axis because it's set to outside + expect(editor.getCamera()).toMatchObject({ ...camera, y: camera.y - 100 / camera.z }) + editor.pan(new Vec(0, -1000000)) + + // clamped to the bounds + expect(editor.getCamera()).toMatchObject({ ...camera, y: -800 }) + }) + it('Allows different values to be set for x and y origin', () => { + editor.setCameraOptions({ + ...DEFAULT_CAMERA_OPTIONS, + constraints: { + ...DEFAULT_CONSTRAINTS, + behavior: 'contain', + origin: { x: 0, y: 1 }, + initialZoom: 'default', + }, + }) + editor.setCamera(editor.getCamera(), { reset: true }) + const camera = editor.getCamera() + editor.zoomOut() + // zooms out and keeps the bounds in the bottom left of the viewport, so no change on x axis + expect(editor.getCamera()).toMatchObject({ x: 0, y: camera.y + 900, z: 0.5 }) + }) }) test('it animated towards the constrained viewport rather than the given viewport', () => {