90 lines
3.2 KiB
JavaScript
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 });
|
|
}
|
|
``
|