diff --git a/harnesses/gtauri/frontend/dist/index.html b/harnesses/gtauri/frontend/dist/index.html index a82a890..1750e0b 100644 --- a/harnesses/gtauri/frontend/dist/index.html +++ b/harnesses/gtauri/frontend/dist/index.html @@ -269,7 +269,21 @@ requestAnimationFrame(frTick); let vScale = 1, vTx = 0, vTy = 0; const base = { w: 0, h: 0 }; +function fitScale() { + return Math.min(innerWidth / base.w, innerHeight / base.h); +} + function vApply() { + // Clamp: never zoom out past fit, and pan is limited to the image + // edges — the image can never be dragged off-screen leaving blank + // space around it. On a letterboxed axis (image smaller than the + // viewport in that dimension) panning is locked to centered. + const s = fitScale(); + if (vScale < s) vScale = s; + const mx = Math.max(0, (base.w * vScale - innerWidth) / 2); + const my = Math.max(0, (base.h * vScale - innerHeight) / 2); + if (vTx > mx) vTx = mx; else if (vTx < -mx) vTx = -mx; + if (vTy > my) vTy = my; else if (vTy < -my) vTy = -my; vimg.style.transform = "translate(" + (vTx - base.w * vScale / 2) + "px," + (vTy - base.h * vScale / 2) + "px) scale(" + vScale + ")"; } @@ -370,7 +384,7 @@ viewer.addEventListener("pointermove", (e) => { p.x = e.clientX; p.y = e.clientY; const [a, b] = [...pts.values()]; const d = Math.hypot(a.x - b.x, a.y - b.y); - if (pinchD0 > 0) vScale = Math.max(0.05, pinchS0 * d / pinchD0); + if (pinchD0 > 0) vScale = Math.max(fitScale(), pinchS0 * d / pinchD0); vApply(); } }); @@ -378,7 +392,7 @@ const endPt = (e) => { pts.delete(e.pointerId); }; viewer.addEventListener("pointerup", endPt); viewer.addEventListener("pointercancel", endPt); viewer.addEventListener("dblclick", () => { - vScale = Math.min(innerWidth / base.w, innerHeight / base.h); + vScale = fitScale(); vTx = 0; vTy = 0; vApply(); });