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 { env } from '$env/dynamic/public';
// Svelte 5 Runes for Reactivity
// Svelte 5 Runes for Core Reactivity
let photos = $state([]);
let nextToken = $state(null);
let loading = $state(false);
@@ -10,18 +10,20 @@
let activePhoto = $state(null);
let observerTarget;
// Lightbox Pan & Zoom Matrix State
// Lightbox Control Flags
let isZoomed = $state(false);
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
let panX = $state(0);
let panY = $state(0);
// Coordinate Vector Matrix (using raw numbers to bypass Svelte state loops on fast cycles)
let currentX = 0;
let currentY = 0;
let startX = 0;
let startY = 0;
let ticking = false;
// Touch tracking coordinates for mobile swipes
// Touch tracking coordinates for layout pagination swipes
let touchStartX = 0;
let touchEndX = 0;
@@ -75,8 +77,11 @@
function resetZoom() {
isZoomed = false;
isDragging = false;
panX = 0;
panY = 0;
currentX = 0;
currentY = 0;
if (imageMatrixWrapper) {
imageMatrixWrapper.style.transform = `translate3d(0px, 0px, 0px)`;
}
}
function nextPhoto() {
@@ -100,11 +105,11 @@
activePhoto = null;
}
if (e.key === 'ArrowRight' && !isZoomed) {
e.preventDefault(); // 👈 Stops the underlying grid buttons from changing focus
e.preventDefault();
nextPhoto();
}
if (e.key === 'ArrowLeft' && !isZoomed) {
e.preventDefault(); // 👈 Stops the underlying grid buttons from changing focus
e.preventDefault();
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) {
if (!isZoomed) return;
if (target.tagName === 'BUTTON' || target.closest('button')) return;
isDragging = true;
startX = clientX - panX;
startY = clientY - panY;
startX = clientX - currentX;
startY = clientY - currentY;
}
function pointerMove(clientX, clientY, preventDefaultFunc) {
function pointerMove(clientX, clientY) {
if (!isDragging) return;
if (typeof preventDefaultFunc === 'function') preventDefaultFunc();
panX = clientX - startX;
panY = clientY - startY;
currentX = clientX - startX;
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() {
isDragging = false;
}
// Desktop Mouse Adapters
// Desktop Mouse Interface Subscriptions
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 Panning Adapters
// Mobile Touch Interface Subscriptions
function handleTouchStart(e) {
if (isZoomed) {
const touch = e.touches[0];
@@ -156,9 +173,10 @@
}
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];
pointerMove(touch.clientX, touch.clientY, () => e.preventDefault());
pointerMove(touch.clientX, touch.clientY);
}
}
@@ -315,16 +333,17 @@
{/if}
<div
class="max-w-full max-h-full flex items-center justify-center p-2 transition-transform duration-300 ease-out"
style="transform: translate3d({panX}px, {panY}px, 0px);"
bind:this={imageMatrixWrapper}
class="max-w-full max-h-full flex items-center justify-center p-2 ease-out will-change-transform"
>
<img
src={activePhoto.fullUrl}
alt="Gallery Content Visual"
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});"
/> </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">