<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script type="module">
import PhotoSwipeLightbox from 'https://cdn.jsdelivr.net/npm/photoswipe@5.3.8/dist/photoswipe-lightbox.esm.js'
import PhotoSwipe from 'https://cdn.jsdelivr.net/npm/photoswipe@5.3.8/dist/photoswipe.esm.js'
const lightbox = new PhotoSwipeLightbox({
gallery: `body`,
children: 'a[id^="gallery-img"]',
pswpModule: PhotoSwipe
});
lightbox.init();
document.addEventListener('DOMContentLoaded', function () {
const magnifierContainer = document.querySelector('.magnifier-container');
const magOriginal = document.getElementById('mag-original');
const magDiff = document.getElementById('mag-diff');
const magSecond = document.getElementById('mag-second');
let ZOOM_LEVEL = 3.5;
const MIN_ZOOM = 3;
const MAX_ZOOM = 25;
const ZOOM_STEP = 0.5;
let isImagesSwapped = false;
let activePreviewImg = null;
let activeOriginalUrl = null;
let activeDiffUrl = null;
let activeRunAComment = null;
let activeRunBComment = null;
let magState = null;
function setMagnifierSrc(img, url) {
if (img._trackedUrl === url) return;
img._trackedUrl = url;
img._loadState = 'loading';
img.onload = () => {
if (img._trackedUrl === url) {
img._loadState = 'loaded';
if (magnifierContainer.style.display === 'flex') {
renderMagnifierImages();
}
}
};
img.onerror = () => {
if (img._trackedUrl === url) {
img._loadState = 'error';
if (magnifierContainer.style.display === 'flex') {
renderMagnifierImages();
}
}
};
img.src = url;
if (img.complete) {
img._loadState = img.naturalWidth > 0 ? 'loaded' : 'error';
}
}
function renderMagnifierImages() {
if (!magState) return;
const { xPercent, yPercent, rect, originalUrl, original2Url, diffUrl } = magState;
[magOriginal, magDiff, magSecond].forEach((img, idx) => {
let url;
if (idx === 0) {
url = isImagesSwapped ? original2Url : originalUrl;
} else if (idx === 1) {
url = diffUrl;
} else {
url = isImagesSwapped ? originalUrl : original2Url;
}
setMagnifierSrc(img, url);
const zoomedWidth = rect.width * ZOOM_LEVEL;
const zoomedHeight = rect.height * ZOOM_LEVEL;
img.style.width = zoomedWidth + 'px';
img.style.height = zoomedHeight + 'px';
const magnifierView = img.closest('.magnifier-view');
const containerWidth = magnifierView.clientWidth;
const containerHeight = magnifierView.clientHeight;
img.style.left = `${Math.min(0, Math.max(-(zoomedWidth - containerWidth), containerWidth / 2 - xPercent * zoomedWidth))}px`;
img.style.top = `${Math.min(0, Math.max(-(zoomedHeight - containerHeight), containerHeight / 2 - yPercent * zoomedHeight))}px`;
const state = img._loadState || 'loading';
img.style.visibility = (state === 'loaded') ? 'visible' : 'hidden';
const label = magnifierView.querySelector('.magnifier-label');
let baseText;
if (idx === 0) {
baseText = isImagesSwapped ? `Run B${activeRunBComment ? ` - ${activeRunBComment}` : ''}` : `Run A${activeRunAComment ? ` - ${activeRunAComment}` : ''}`;
} else if (idx === 1) {
baseText = 'Diff';
} else {
baseText = isImagesSwapped ? `Run A${activeRunAComment ? ` - ${activeRunAComment}` : ''}` : `Run B${activeRunBComment ? ` - ${activeRunBComment}` : ''}`;
}
if (state === 'loading') {
label.textContent = `${baseText} - Loading...`;
} else if (state === 'error') {
label.textContent = `${baseText} - Load failed`;
} else {
label.textContent = `${baseText} - ${ZOOM_LEVEL}x`;
}
});
}
function updateMagnifier(e, container, originalUrl, original2Url, diffUrl) {
const rect = container.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
magnifierContainer.style.display = 'flex';
magState = {
xPercent: x / rect.width,
yPercent: y / rect.height,
rect,
originalUrl,
original2Url,
diffUrl,
};
renderMagnifierImages();
}
function handleZoom(e) {
if (e.ctrlKey) {
e.preventDefault(); const delta = Math.sign(e.deltaY) * -ZOOM_STEP;
const newZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, ZOOM_LEVEL + delta));
if (newZoom !== ZOOM_LEVEL) {
ZOOM_LEVEL = newZoom;
const mousemoveEvent = new MouseEvent('mousemove', {
clientX: e.clientX,
clientY: e.clientY,
bubbles: true
});
e.target.dispatchEvent(mousemoveEvent);
}
}
}
document.querySelectorAll('[id^="capture-"]').forEach(container => {
const originalUrl = container.dataset.original;
const original2Url = container.dataset.original2;
const diffUrl = container.dataset.diff;
const runAComment = container.dataset.runAComment;
const runBComment = container.dataset.runBComment;
if (originalUrl && diffUrl != "None") {
container.querySelectorAll('.preview-image').forEach(previewImg => {
previewImg.addEventListener('mousemove', (e) => {
activePreviewImg = previewImg;
activeOriginalUrl = originalUrl;
activeDiffUrl = diffUrl;
activeRunAComment = runAComment;
activeRunBComment = runBComment;
updateMagnifier(e, previewImg, originalUrl, original2Url, diffUrl);
});
previewImg.addEventListener('wheel', handleZoom);
previewImg.addEventListener('mouseleave', () => {
magnifierContainer.style.display = 'none';
activePreviewImg = null;
activeOriginalUrl = null;
activeDiffUrl = null;
activeRunAComment = null;
activeRunBComment = null;
});
});
}
});
document.addEventListener('keydown', (e) => {
if (e.code === 'Space' && magnifierContainer.style.display === 'flex' && activePreviewImg) {
e.preventDefault(); isImagesSwapped = !isImagesSwapped;
renderMagnifierImages();
}
});
});
</script>