mya/www/src/zoom.js
Fabio 82ccd023df
Some checks are pending
Build Android APK / build (push) Waiting to run
first commit
2026-01-21 15:08:14 +01:00

90 lines
3.2 KiB
JavaScript

// src/zoom.js
import { state } from './state.js';
function computeDynamicMaxZoom() {
return Math.min(window.innerWidth / 85, 4.0);
}
function loadInitialZoom() {
const v = parseFloat(localStorage.getItem('zoomLevel'));
if (!isFinite(v) || v <= 0) return 1;
return Math.min(Math.max(v, 0.5), computeDynamicMaxZoom());
}
function applyZoom(z) {
state.zoomLevel = (!isFinite(z) || z <= 0) ? 1 : z;
document.documentElement.style.setProperty('--zoom', state.zoomLevel);
localStorage.setItem('zoomLevel', String(state.zoomLevel));
}
function getPinchDistance(touches) {
const [a, b] = touches;
return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);
}
function elasticEase(x) {
return Math.sin(x * Math.PI * 0.5) * 1.05;
}
export function initZoomHandlers() {
state.zoomMax = computeDynamicMaxZoom();
state.zoomLevel = loadInitialZoom();
applyZoom(state.zoomLevel);
// Evita di bloccare lo scroll quando non in wiggle mode
document.addEventListener('touchmove', e => {
if (!state.editMode) return;
if (e.touches.length === 2) e.preventDefault();
}, { passive: false });
document.addEventListener('touchstart', e => {
if (!state.editMode) return;
if (e.touches.length === 2) {
state.initialPinchDistance = getPinchDistance(e.touches);
}
});
document.addEventListener('touchmove', e => {
if (!state.editMode) return;
if (e.touches.length === 2 && state.initialPinchDistance) {
const newDist = getPinchDistance(e.touches);
const scale = newDist / state.initialPinchDistance;
let newZoom = state.zoomLevel * scale;
state.zoomMax = computeDynamicMaxZoom();
if (newZoom > state.zoomMax) newZoom = state.zoomMax + (newZoom - state.zoomMax) * 0.25;
if (newZoom < 0.5) newZoom = 0.5 - (0.5 - newZoom) * 0.25;
applyZoom(newZoom);
state.initialPinchDistance = newDist;
e.preventDefault();
}
}, { passive: false });
document.addEventListener('touchend', e => {
if (!state.editMode) return;
if (e.touches.length < 2 && state.initialPinchDistance) {
state.initialPinchDistance = null;
state.zoomMax = computeDynamicMaxZoom();
const target = Math.min(Math.max(state.zoomLevel, 0.5), state.zoomMax);
const start = state.zoomLevel;
const duration = 250;
const startTime = performance.now();
function animate(t) {
const p = Math.min((t - startTime) / duration, 1);
const eased = start + (target - start) * elasticEase(p);
applyZoom(eased);
if (p < 1) requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
}
});
document.addEventListener('wheel', e => {
if (!state.editMode) return;
e.preventDefault();
state.zoomMax = computeDynamicMaxZoom();
const direction = e.deltaY < 0 ? 1 : -1;
const factor = 1 + direction * 0.1;
let newZoom = state.zoomLevel * factor;
if (newZoom > state.zoomMax) newZoom = state.zoomMax + (newZoom - state.zoomMax) * 0.25;
if (newZoom < 0.5) newZoom = 0.5 - (0.5 - newZoom) * 0.25;
applyZoom(newZoom);
}, { passive: false });
}
``