// 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 }); } ``