pinch to zoom

This commit is contained in:
lelo 2025-03-23 18:07:56 +01:00
parent f6676d7d27
commit 0e50f519ff
3 changed files with 81 additions and 15 deletions

View File

@ -40,7 +40,7 @@
font-size: 24px; font-size: 24px;
color: #fff; color: #fff;
cursor: pointer; cursor: pointer;
z-index: 10; z-index: 100;
background: transparent; background: transparent;
border: none; border: none;
padding: 0; padding: 0;

View File

@ -1,3 +1,9 @@
let isPinching = false;
let pinchZoomOccurred = false;
let initialPinchDistance = null;
let initialScale = 1;
let currentScale = 1;
// Assume that currentGalleryImages is already declared in app.js. // Assume that currentGalleryImages is already declared in app.js.
// Only declare currentGalleryIndex if it isn't defined already. // Only declare currentGalleryIndex if it isn't defined already.
if (typeof currentGalleryIndex === "undefined") { if (typeof currentGalleryIndex === "undefined") {
@ -47,6 +53,19 @@ function showGalleryImage(relUrl) {
newImage.style.opacity = 0; // Start fully transparent newImage.style.opacity = 0; // Start fully transparent
newImage.id = 'gallery-modal-content'; newImage.id = 'gallery-modal-content';
// Add pinch-to-zoom event listeners
newImage.addEventListener('touchstart', handlePinchStart, { passive: false });
newImage.addEventListener('touchmove', handlePinchMove, { passive: false });
newImage.addEventListener('touchend', handlePinchEnd, { passive: false });
newImage.addEventListener('click', handleGalleryImageClick);
// Reset pinch variables for the new image
initialPinchDistance = null;
initialScale = 1;
currentScale = 1;
pinchZoomOccurred = false;
// Append new image on top of existing ones // Append new image on top of existing ones
modal.appendChild(newImage); modal.appendChild(newImage);
@ -100,8 +119,15 @@ function closeGalleryModal() {
} }
function handleGalleryImageClick(e) { function handleGalleryImageClick(e) {
// If a pinch zoom occurred, don't change the image.
if (pinchZoomOccurred) {
pinchZoomOccurred = false; // Reset the flag for the next gesture.
e.stopPropagation();
return;
}
if (e.target.classList.contains('gallery-next') || e.target.classList.contains('gallery-prev')) { if (e.target.classList.contains('gallery-next') || e.target.classList.contains('gallery-prev')) {
return; // Prevent conflict return; // Prevent conflict with navigation buttons.
} }
const imgRect = this.getBoundingClientRect(); const imgRect = this.getBoundingClientRect();
@ -127,10 +153,18 @@ function initGallerySwipe() {
const galleryModal = document.getElementById('gallery-modal'); const galleryModal = document.getElementById('gallery-modal');
galleryModal.addEventListener('touchstart', function(e) { galleryModal.addEventListener('touchstart', function(e) {
// If more than one finger is on screen, ignore swipe tracking.
if (e.touches.length > 1) {
return;
}
touchStartX = e.changedTouches[0].screenX; touchStartX = e.changedTouches[0].screenX;
}, false); }, false);
galleryModal.addEventListener('touchend', function(e) { galleryModal.addEventListener('touchend', function(e) {
// If the event was part of a multi-touch (pinch) gesture or a pinch was detected, skip swipe.
if (e.changedTouches.length > 1 || isPinching || pinchZoomOccurred) {
return;
}
touchEndX = e.changedTouches[0].screenX; touchEndX = e.changedTouches[0].screenX;
handleSwipe(); handleSwipe();
}, false); }, false);
@ -153,6 +187,41 @@ function initGallerySwipe() {
} }
} }
function handlePinchStart(e) {
if (e.touches.length === 2) {
e.preventDefault();
isPinching = true;
pinchZoomOccurred = false; // Reset at the start of a pinch gesture.
const dx = e.touches[0].pageX - e.touches[1].pageX;
const dy = e.touches[0].pageY - e.touches[1].pageY;
initialPinchDistance = Math.sqrt(dx * dx + dy * dy);
}
}
function handlePinchMove(e) {
if (e.touches.length === 2 && initialPinchDistance) {
e.preventDefault();
const dx = e.touches[0].pageX - e.touches[1].pageX;
const dy = e.touches[0].pageY - e.touches[1].pageY;
const currentDistance = Math.sqrt(dx * dx + dy * dy);
let scale = currentDistance / initialPinchDistance;
scale = Math.max(0.5, Math.min(scale * initialScale, 3));
// If the scale has changed enough, mark that a pinch zoom occurred.
if (Math.abs(scale - initialScale) > 0.05) {
pinchZoomOccurred = true;
}
currentScale = scale;
e.currentTarget.style.transform = `translate(-50%, -50%) scale(${scale})`;
}
}
function handlePinchEnd(e) {
if (e.touches.length < 2) {
initialScale = currentScale;
initialPinchDistance = null;
isPinching = false;
}
}
@ -186,10 +255,7 @@ function initGalleryControls() {
function initGallery() { function initGallery() {
const galleryImage = document.getElementById('gallery-modal-content');
if (galleryImage) {
galleryImage.addEventListener('click', handleGalleryImageClick);
}
initGallerySwipe(); initGallerySwipe();
initGalleryControls(); initGalleryControls();

View File

@ -90,10 +90,10 @@
<!-- Gallery Modal for Images --> <!-- Gallery Modal for Images -->
<div id="gallery-modal" style="display: none;"> <div id="gallery-modal" style="display: none;">
<button id="gallery-close">x</button>
<img id="gallery-modal-content" src="" /> <img id="gallery-modal-content" src="" />
<button class="gallery-nav gallery-prev"></button> <button class="gallery-nav gallery-prev"></button>
<button class="gallery-nav gallery-next"></button> <button class="gallery-nav gallery-next"></button>
<button id="gallery-close">x</button>
</div> </div>
<div id="loader-container" style="display: none;"> <div id="loader-container" style="display: none;">