From 19e0656ccb822e2b68b79d2b7654534fac49ec3d Mon Sep 17 00:00:00 2001 From: mike Date: Sun, 28 Jun 2026 00:23:48 +0200 Subject: [PATCH] reorder --- tour-comfy/car.html | 95 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/tour-comfy/car.html b/tour-comfy/car.html index aa2f546..9048f31 100644 --- a/tour-comfy/car.html +++ b/tour-comfy/car.html @@ -2227,6 +2227,7 @@ // --- HYDRATION_START --- const PRELOADED_IMAGES = [ + "20260628_001216_pad_20260626_035101_pad_20260626_034830_jb.nobg.png", "20260627_232502_pad_20260626_035101_pad_20260626_034830_jb.nobg.png", "20260627_232843_pad_20260626_035101_pad_20260626_034830_jb.nobg.png", "20260627_232526_pad_20260626_035101_pad_20260626_034830_jb.nobg.png", @@ -6923,16 +6924,24 @@ function getImageDisplayRect(img) { if (!img || !img.naturalWidth) return null; + + // If the image is zoomed, getBoundingClientRect() returns the SCALED dimensions. + // We need to account for this to find the actual visible image area. + const isZoomed = img.classList.contains('zoomed'); + const scale = isZoomed ? 2.2 : 1.0; + const rect = img.getBoundingClientRect(); const container = img.parentElement; const crect = container.getBoundingClientRect(); + // The natural aspect ratio const iw = img.naturalWidth; const ih = img.naturalHeight; - const cw = rect.width; - const ch = rect.height; - const aspect = iw / ih; + + // The container dimensions for the image (before scaling) + const cw = rect.width / scale; + const ch = rect.height / scale; const caspect = cw / ch; let dw, dh, dl, dt; @@ -6948,10 +6957,41 @@ dl = (cw - dw) / 2; } - // Adjust relative to container if needed, but since img is a flex item - // centered in .studio-viewer, its rect.left/top might already be offset. - // Actually, dl and dt above are relative to the img element's box. - // We want coordinates relative to .studio-viewer. + // Adjust for scale: the visual center stays the same, + // but the width/height and offsets from the top-left change. + if (isZoomed) { + const centerRelX = cw / 2; + const centerRelY = ch / 2; + + // dw, dh are unscaled visual dimensions of the content. + // dl, dt are unscaled offsets within the img element's box. + + // We want the scaled versions. + dw *= scale; + dh *= scale; + + // The top-left of the content relative to the center of the img element: + const contentRelCenterX = dl - centerRelX; + const contentRelCenterY = dt - centerRelY; + + // The top-left of the content relative to the center of the img element (scaled): + const contentRelCenterXScaled = contentRelCenterX * scale; + const contentRelCenterYScaled = contentRelCenterY * scale; + + // The new offsets relative to the top-left of the scaled img element: + // Actually, rect.left/top are already for the scaled element's bounding box. + // We just need to find where the content starts within that bounding box. + const finalDl = contentRelCenterXScaled + (rect.width / 2); + const finalDt = contentRelCenterYScaled + (rect.height / 2); + + return { + left: rect.left - crect.left + finalDl, + top: rect.top - crect.top + finalDt, + width: dw, + height: dh + }; + } + const finalLeft = rect.left - crect.left + dl; const finalTop = rect.top - crect.top + dt; @@ -7125,23 +7165,20 @@ const fname = lbNames[lbIdx]; if (document.getElementById('poseCanvas')) _removePoseOverlay(); // skeleton is per-image document.getElementById('poseResults')?.remove(); - _fsModelFilename = fname; // keep faceswap/scenery/segment in sync - const isVid = isVideo(fname) || fileContentType[fname] === 'video'; + const lbImgEl = document.getElementById('lbImg'); const lbVideoEl = document.getElementById('lbVideo'); - + lbImgEl.onload = () => { const dimEl = document.getElementById('lbImgDims'); if (dimEl) dimEl.textContent = `${lbImgEl.naturalWidth} x ${lbImgEl.naturalHeight}`; - // Use requestAnimationFrame to ensure layout has updated before measuring for checkerboard/previews - requestAnimationFrame(() => { - updatePadPreview(); - const cb = document.getElementById('sbCheckerboard'); - if (cb && cb.checked) toggleCheckerboard(true); - }); + // Overlay re-sync is now handled by ResizeObserver }; + _fsModelFilename = fname; // keep faceswap/scenery/segment in sync + const isVid = isVideo(fname) || fileContentType[fname] === 'video'; + // Show image dimensions const dimEl = document.getElementById('lbImgDims'); if (dimEl) { @@ -7163,6 +7200,10 @@ lbImgEl.style.display = ''; lbImgEl.classList.remove('zoomed'); lbImgEl.src = lbUrls[lbIdx]; + // If it's already in cache, onload might not fire or already fired + if (lbImgEl.complete && lbImgEl.naturalWidth) { + lbImgEl.onload(); + } } const backBtn = document.getElementById('lbBackBtn'); @@ -9878,6 +9919,20 @@ // Initialize document.addEventListener('DOMContentLoaded', () => { + const img = document.getElementById('lbImg'); + if (img) { + const ro = new ResizeObserver(() => { + if (_isStudioOpen()) { + requestAnimationFrame(() => { + updatePadPreview(); + const cb = document.getElementById('sbCheckerboard'); + if (cb && cb.checked) toggleCheckerboard(true); + }); + } + }); + ro.observe(img); + } + window.addEventListener('resize', () => { if (_isStudioOpen()) { requestAnimationFrame(() => { @@ -10134,7 +10189,11 @@ } function toggleImageZoom() { - document.getElementById('lbImg')?.classList.toggle('zoomed'); + const img = document.getElementById('lbImg'); + if (img) { + img.classList.toggle('zoomed'); + // The ResizeObserver will handle the follow-up logic automatically. + } } // ---- sidebar panels ---- @@ -11731,7 +11790,7 @@ if (btn) btn.disabled = false; } - function toggleCheckerboard(on) { + function toggleCheckerboard(on, isRetry=false) { const viewer = document.getElementById('studioViewer'); const cbLayer = document.getElementById('studioCheckerboard'); const img = document.getElementById('lbImg');