import { describe, it, expect } from 'vitest' import { usePanZoom } from '../src/composables/usePanZoom.js' // A 1400x1300 canvas. The strip is 3600x24000, fitted to 195x1300. const STRIP = { cw: 1400, ch: 1300, iw: 195, ih: 1300, nw: 3600 } const PHOTO = { cw: 1400, ch: 1300, iw: 1200, ih: 900, nw: 4000 } const RECT = { left: 0, top: 0, width: 1400, height: 1300 } const target = { getBoundingClientRect: () => RECT, setPointerCapture() {}, releasePointerCapture() {} } const at = (x, y, extra = {}) => ({ clientX: x, clientY: y, currentTarget: target, button: 0, pointerId: 1, preventDefault() {}, ...extra }) describe('usePanZoom', () => { it('opens a long strip at the canvas width, keeping the clicked point under the cursor', () => { const pz = usePanZoom(() => STRIP) pz.handlers.onClick(at(700, 650 - 300)) expect(pz.state.scale).toBeCloseTo(1400 / 195) expect(pz.state.x).toBe(0) // The picture point that was 300px above centre (picture y = -300 at // scale 1) is still 300px above centre: y + scale * -300 === -300. expect(pz.state.y + pz.state.scale * -300).toBeCloseTo(-300) }) it('doubles an ordinary picture', () => { const pz = usePanZoom(() => PHOTO) pz.handlers.onClick(at(700, 650)) expect(pz.state.scale).toBe(2) }) it('does not unzoom on the click that ends a drag', () => { const pz = usePanZoom(() => STRIP) pz.handlers.onClick(at(700, 650)) pz.handlers.onPointerDown(at(700, 650)) pz.handlers.onPointerMove(at(700, 450)) pz.handlers.onPointerUp(at(700, 450)) expect(pz.endedDrag()).toBe(true) expect(pz.state.y).toBe(-200) // A plain click afterwards is a click again. pz.handlers.onPointerDown(at(700, 450)) pz.handlers.onPointerUp(at(700, 450)) expect(pz.endedDrag()).toBe(false) }) it('scrolls a zoomed picture with the wheel and stops at its ends', () => { const pz = usePanZoom(() => STRIP) pz.handlers.onClick(at(700, 650)) const scale = pz.state.scale pz.handlers.onWheel(at(700, 650, { deltaY: 100, deltaX: 0, deltaMode: 0 })) expect(pz.state.scale).toBe(scale) expect(pz.state.y).toBe(-100) pz.handlers.onWheel(at(700, 650, { deltaY: 1e6, deltaX: 0, deltaMode: 0 })) expect(pz.state.y).toBeCloseTo(-(1300 * scale - 1300) / 2) }) it('leaves the fitted view alone on a plain wheel and zooms with ctrl held', () => { const pz = usePanZoom(() => PHOTO) pz.handlers.onWheel(at(700, 650, { deltaY: 100, deltaX: 0, deltaMode: 0 })) expect(pz.state.scale).toBe(1) pz.handlers.onWheel(at(700, 650, { deltaY: -100, deltaX: 0, deltaMode: 0, ctrlKey: true })) expect(pz.state.scale).toBeGreaterThan(1) }) it('steps with the buttons and never goes past full size twice over', () => { const pz = usePanZoom(() => PHOTO) pz.zoomBy(1) expect(pz.state.scale).toBeCloseTo(1.25) pz.zoomBy(100) expect(pz.state.scale).toBeCloseTo(pz.maxScale()) expect(pz.maxScale()).toBeCloseTo((4000 / 1200) * 2) pz.zoomBy(-100) expect(pz.state.scale).toBe(1) expect([pz.state.x, pz.state.y]).toEqual([0, 0]) }) })