Browse Source

Fix zoom function on PC

Sviluppo_Carrello_Immagini
parent
commit
3ee08f34fe
1 changed files with 78 additions and 1 deletions
  1. +78
    -1
      components/PublicGrid.tsx

+ 78
- 1
components/PublicGrid.tsx View File

@@ -185,8 +185,12 @@ function FullscreenViewer({
}) { }) {
const [current, setCurrent] = useState(startIndex); const [current, setCurrent] = useState(startIndex);
const [playing, setPlaying] = useState<Set<number>>(new Set()); const [playing, setPlaying] = useState<Set<number>>(new Set());
const [zoom, setZoom] = useState(1);
const [pan, setPan] = useState({ x: 0, y: 0 });
const touchStartX = useRef<number | null>(null); const touchStartX = useRef<number | null>(null);
const videoRefs = useRef<Record<number, HTMLVideoElement | null>>({}); const videoRefs = useRef<Record<number, HTMLVideoElement | null>>({});
const containerRef = useRef<HTMLDivElement | null>(null);
const dragRef = useRef<{ sx: number; sy: number; px: number; py: number; moved: boolean } | null>(null);


const markPlaying = (i: number) => setPlaying(p => { const n = new Set(p); n.add(i); return n; }); const markPlaying = (i: number) => setPlaying(p => { const n = new Set(p); n.add(i); return n; });
const markPaused = (i: number) => setPlaying(p => { const n = new Set(p); n.delete(i); return n; }); const markPaused = (i: number) => setPlaying(p => { const n = new Set(p); n.delete(i); return n; });
@@ -207,6 +211,38 @@ function FullscreenViewer({
} }
}; };


const onImgClick = (e: React.MouseEvent<HTMLImageElement>) => {
if (dragRef.current?.moved) {
dragRef.current = null;
return;
}
dragRef.current = null;
if (zoom > 1) {
setZoom(1);
setPan({ x: 0, y: 0 });
} else {
const r = e.currentTarget.getBoundingClientRect();
const ox = e.clientX - r.left - r.width / 2;
const oy = e.clientY - r.top - r.height / 2;
setZoom(2);
setPan({ x: -2 * ox, y: -2 * oy });
}
};

const onImgPointerDown = (e: React.PointerEvent<HTMLImageElement>) => {
if (zoom <= 1) return;
dragRef.current = { sx: e.clientX, sy: e.clientY, px: pan.x, py: pan.y, moved: false };
e.currentTarget.setPointerCapture?.(e.pointerId);
};

const onImgPointerMove = (e: React.PointerEvent<HTMLImageElement>) => {
if (!dragRef.current) return;
const dx = e.clientX - dragRef.current.sx;
const dy = e.clientY - dragRef.current.sy;
if (Math.hypot(dx, dy) > 4) dragRef.current.moved = true;
setPan({ x: dragRef.current.px + dx, y: dragRef.current.py + dy });
};

const prev = useCallback(() => setCurrent(i => (i - 1 + items.length) % items.length), [items.length]); const prev = useCallback(() => setCurrent(i => (i - 1 + items.length) % items.length), [items.length]);
const next = useCallback(() => setCurrent(i => (i + 1) % items.length), [items.length]); const next = useCallback(() => setCurrent(i => (i + 1) % items.length), [items.length]);


@@ -237,8 +273,37 @@ function FullscreenViewer({
}); });
}, [current, items]); }, [current, items]);


const onTouchStart = (e: React.TouchEvent) => { touchStartX.current = e.touches[0].clientX; };
// Reset zoom whenever the active slide changes
useEffect(() => {
setZoom(1);
setPan({ x: 0, y: 0 });
}, [current]);

// Wheel zoom (only on images). preventDefault requires passive: false → manual listener.
useEffect(() => {
const el = containerRef.current;
if (!el) return;
const onWheel = (e: WheelEvent) => {
const item = items[current];
if (!item || isVideoUrl(item.url)) return;
e.preventDefault();
const factor = 1 - e.deltaY * 0.001;
setZoom(prev => {
const next = Math.max(1, Math.min(4, prev * factor));
if (next === 1) setPan({ x: 0, y: 0 });
return next;
});
};
el.addEventListener('wheel', onWheel, { passive: false });
return () => el.removeEventListener('wheel', onWheel);
}, [current, items]);

const onTouchStart = (e: React.TouchEvent) => {
if (zoom > 1) return; // pan via pointer events instead
touchStartX.current = e.touches[0].clientX;
};
const onTouchEnd = (e: React.TouchEvent) => { const onTouchEnd = (e: React.TouchEvent) => {
if (zoom > 1) return;
if (touchStartX.current === null) return; if (touchStartX.current === null) return;
const delta = e.changedTouches[0].clientX - touchStartX.current; const delta = e.changedTouches[0].clientX - touchStartX.current;
if (Math.abs(delta) > 50) delta < 0 ? next() : prev(); if (Math.abs(delta) > 50) delta < 0 ? next() : prev();
@@ -247,6 +312,7 @@ function FullscreenViewer({


return ( return (
<div <div
ref={containerRef}
className="fixed inset-0 z-[100] bg-black/95 flex items-center justify-center select-none animate-in fade-in duration-200" className="fixed inset-0 z-[100] bg-black/95 flex items-center justify-center select-none animate-in fade-in duration-200"
onTouchStart={onTouchStart} onTouchStart={onTouchStart}
onTouchEnd={onTouchEnd} onTouchEnd={onTouchEnd}
@@ -287,6 +353,17 @@ function FullscreenViewer({
src={item.url} src={item.url}
alt="" alt=""
className="max-w-full max-h-full object-contain" className="max-w-full max-h-full object-contain"
draggable={false}
style={isActive ? {
transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
cursor: zoom > 1 ? 'grab' : 'zoom-in',
transition: dragRef.current ? 'none' : 'transform 0.2s',
touchAction: zoom > 1 ? 'none' : 'auto',
willChange: 'transform',
} : undefined}
onClick={isActive ? onImgClick : undefined}
onPointerDown={isActive ? onImgPointerDown : undefined}
onPointerMove={isActive ? onImgPointerMove : undefined}
/> />
)} )}
</div> </div>


Loading…
Cancel
Save