Performance fix

This commit is contained in:
Alex Rennie-Lis
2026-06-29 01:12:38 +01:00
parent d3466d766f
commit daa8598dc8

View File

@@ -2,7 +2,7 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { env } from '$env/dynamic/public'; import { env } from '$env/dynamic/public';
// Svelte 5 Runes for Reactivity // Svelte 5 Runes for Core Reactivity
let photos = $state([]); let photos = $state([]);
let nextToken = $state(null); let nextToken = $state(null);
let loading = $state(false); let loading = $state(false);
@@ -10,18 +10,20 @@
let activePhoto = $state(null); let activePhoto = $state(null);
let observerTarget; let observerTarget;
// Lightbox Pan & Zoom Matrix State // Lightbox Control Flags
let isZoomed = $state(false); let isZoomed = $state(false);
let lightboxContainer = $state(null); let lightboxContainer = $state(null);
let isDragging = $state(false); let imageMatrixWrapper = $state(null); // Explicit ref to bypass reactive state lag
let isDragging = false; // Internal mutable flag (not a reactive rune)
// Coordinate state vectors for custom 2D transform panning // Coordinate Vector Matrix (using raw numbers to bypass Svelte state loops on fast cycles)
let panX = $state(0); let currentX = 0;
let panY = $state(0); let currentY = 0;
let startX = 0; let startX = 0;
let startY = 0; let startY = 0;
let ticking = false;
// Touch tracking coordinates for mobile swipes // Touch tracking coordinates for layout pagination swipes
let touchStartX = 0; let touchStartX = 0;
let touchEndX = 0; let touchEndX = 0;
@@ -75,8 +77,11 @@
function resetZoom() { function resetZoom() {
isZoomed = false; isZoomed = false;
isDragging = false; isDragging = false;
panX = 0; currentX = 0;
panY = 0; currentY = 0;
if (imageMatrixWrapper) {
imageMatrixWrapper.style.transform = `translate3d(0px, 0px, 0px)`;
}
} }
function nextPhoto() { function nextPhoto() {
@@ -100,11 +105,11 @@
activePhoto = null; activePhoto = null;
} }
if (e.key === 'ArrowRight' && !isZoomed) { if (e.key === 'ArrowRight' && !isZoomed) {
e.preventDefault(); // 👈 Stops the underlying grid buttons from changing focus e.preventDefault();
nextPhoto(); nextPhoto();
} }
if (e.key === 'ArrowLeft' && !isZoomed) { if (e.key === 'ArrowLeft' && !isZoomed) {
e.preventDefault(); // 👈 Stops the underlying grid buttons from changing focus e.preventDefault();
prevPhoto(); prevPhoto();
} }
} }
@@ -118,34 +123,46 @@
} }
} }
// Dynamic Pointer Interface Input Routing (Desktop Mouse & Mobile Touch Dragging) // HIGH PERFORMANCE NATIVE INTERFACE PIPELINE (60FPS Engine)
function pointerDown(clientX, clientY, target) { function pointerDown(clientX, clientY, target) {
if (!isZoomed) return; if (!isZoomed) return;
if (target.tagName === 'BUTTON' || target.closest('button')) return; if (target.tagName === 'BUTTON' || target.closest('button')) return;
isDragging = true; isDragging = true;
startX = clientX - panX; startX = clientX - currentX;
startY = clientY - panY; startY = clientY - currentY;
} }
function pointerMove(clientX, clientY, preventDefaultFunc) { function pointerMove(clientX, clientY) {
if (!isDragging) return; if (!isDragging) return;
if (typeof preventDefaultFunc === 'function') preventDefaultFunc();
panX = clientX - startX; currentX = clientX - startX;
panY = clientY - startY; currentY = clientY - startY;
// requestAnimationFrame schedules updates with the browser screen refresh cycle
if (!ticking) {
window.requestAnimationFrame(() => {
if (imageMatrixWrapper) {
imageMatrixWrapper.style.transform = `translate3d(${currentX}px, ${currentY}px, 0px)`;
}
ticking = false;
});
ticking = true;
}
} }
function pointerUp() { function pointerUp() {
isDragging = false; isDragging = false;
} }
// Desktop Mouse Adapters // Desktop Mouse Interface Subscriptions
function handleMouseDown(e) { pointerDown(e.clientX, e.clientY, e.target); } function handleMouseDown(e) { pointerDown(e.clientX, e.clientY, e.target); }
function handleMouseMove(e) { pointerMove(e.clientX, e.clientY, () => e.preventDefault()); } function handleMouseMove(e) {
if(isDragging) e.preventDefault();
pointerMove(e.clientX, e.clientY);
}
// Mobile Touch Panning Adapters // Mobile Touch Interface Subscriptions
// Mobile Touch Panning Adapters
function handleTouchStart(e) { function handleTouchStart(e) {
if (isZoomed) { if (isZoomed) {
const touch = e.touches[0]; const touch = e.touches[0];
@@ -156,9 +173,10 @@
} }
function handleTouchMove(e) { function handleTouchMove(e) {
if (isZoomed && e.touches.length === 1) { // 👈 Ensures single finger panning behaves correctly if (isZoomed && e.touches.length === 1) {
e.preventDefault(); // Kill native momentum bouncing
const touch = e.touches[0]; const touch = e.touches[0];
pointerMove(touch.clientX, touch.clientY, () => e.preventDefault()); pointerMove(touch.clientX, touch.clientY);
} }
} }
@@ -315,16 +333,17 @@
{/if} {/if}
<div <div
class="max-w-full max-h-full flex items-center justify-center p-2 transition-transform duration-300 ease-out" bind:this={imageMatrixWrapper}
style="transform: translate3d({panX}px, {panY}px, 0px);" class="max-w-full max-h-full flex items-center justify-center p-2 ease-out will-change-transform"
> >
<img <img
src={activePhoto.fullUrl} src={activePhoto.fullUrl}
alt="Gallery Content Visual" alt="Gallery Content Visual"
draggable="false" draggable="false"
class="max-h-[70vh] max-w-full rounded shadow-2xl select-none pointer-events-none transition-transform duration-300 will-change-transform" class="max-h-[70vh] max-w-full rounded shadow-2xl select-none pointer-events-none transition-transform duration-200 ease-out will-change-transform"
style="transform: scale({isZoomed ? 3.8 : 1});" style="transform: scale({isZoomed ? 3.8 : 1});"
/> </div> />
</div>
</div> </div>
<div class="w-full max-w-4xl mx-auto z-40 bg-zinc-950/90 border border-zinc-900 px-4 py-3 rounded-xl backdrop-blur-md pointer-events-auto"> <div class="w-full max-w-4xl mx-auto z-40 bg-zinc-950/90 border border-zinc-900 px-4 py-3 rounded-xl backdrop-blur-md pointer-events-auto">