gtauri: clamp viewer pan/zoom to image edges
Pan is now limited to the image bounds (|offset| <= (rendered - viewport)/2 per axis), so the image can never be dragged off-screen leaving blank space around it; on a letterboxed axis panning is locked to centered. Pinch can no longer zoom out past fit. Clamping lives in vApply() so pan, pinch and reset all share it; still compositor-only (transform only).
This commit is contained in:
parent
d990627200
commit
8f700e7f66
18
harnesses/gtauri/frontend/dist/index.html
vendored
18
harnesses/gtauri/frontend/dist/index.html
vendored
|
|
@ -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();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user