I have a script to zoom/full screen an image. But it has a big problem

42 Views Asked by At

I'm an astronomer, and I'm trying to build a small website for family/friends/myself to store and display my different night sky pictures.

Right now, I have some JavaScript that handles zooming, de-zooming, reset and displaying a single image in full screen. But the way it works from what I get (I'm not really good with JS, and since to my knowledge php / CSS won't do the deal, I'm stuck with it), it have a flaw: if I place two same image container (which I'll be forced to do on the same page), it doesn't "know" which image to zoom in.

Basically, here's my HTML:

<div class="image-group">
    <div class="image-container">
        <img class="image" src="/Uploads/Images/IMG_7342_pipp_top_100r__651_regedited-2.jpg" alt="">
    </div>
    <div class="fullscreenImageContainer" onclick="closeFullscreen()">
        <span class="closeButton">X</span>
        <img class="fullscreenImage" src="/Uploads/Images/IMG_7342_pipp_top_100r__651_regedited-2.jpg" alt="">
    </div>
    <div class="zoombuttons">
        <button onclick="zoomIn(this)">Zoom +</button>
        <button onclick="zoomOut(this)">Zoom -</button>
        <button onclick="resetZoom(this)">Réinitialiser</button>
        <button onclick="openFullscreen(this)">Plein écran</button>
    </div>
</div>

And my JS:

<script>
const image = document.getElementById('image');
    const container = document.getElementById('image-container');
let scale = 1;
let isDragging = false;
let startX, startY;
let posX = 0, posY = 0;

function zoomIn() {
    scale *= 1.1;
    updateImageTransform();
}

function zoomOut() {
    const initialScale = 1; // échelle initiale de l'image
    if (scale > initialScale) {
        scale = Math.max(initialScale, scale / 1.1); // Empêche le zoom d'aller en dessous de l'échelle initiale
        constrainPosition();
        updateImageTransform();
    }
}

function resetZoom() {
    scale = 1;
    posX = posY = 0;
    updateImageTransform();
}

function updateImageTransform() {
    image.style.transform = `translate(${posX}px, ${posY}px) scale(${scale})`;
}

function constrainPosition() {
    const imageRect = image.getBoundingClientRect();
    const containerRect = image.parentElement.getBoundingClientRect();

    const maxPosX = (imageRect.width - containerRect.width) / 2;
    const maxPosY = (imageRect.height - containerRect.height) / 2;

    posX = Math.min(Math.max(posX, -maxPosX), maxPosX);
    posY = Math.min(Math.max(posY, -maxPosY), maxPosY);
}

image.addEventListener('mousedown', (e) => {
    e.preventDefault();
    isDragging = true;
    startX = e.clientX;
    startY = e.clientY;
});

window.addEventListener('mousemove', (e) => {
    if (!isDragging) return;
    const dx = e.clientX - startX;
    const dy = e.clientY - startY;
    startX = e.clientX;
    startY = e.clientY;
    posX += dx;
    posY += dy;
    constrainPosition();
    updateImageTransform();
});

window.addEventListener('mouseup', () => {
    isDragging = false;
});

image.addEventListener('touchstart', (e) => {
    if (e.touches.length === 1) {
        startX = e.touches[0].clientX;
        startY = e.touches[0].clientY;
    }
    if (e.touches.length === 2) {
        const touch1 = e.touches[0];
        const touch2 = e.touches[1];
        initialDistance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY);
        initialScale = scale;
    }
});

image.addEventListener('touchmove', (e) => {
    e.preventDefault();
    if (e.touches.length === 1) {
        const dx = e.touches[0].clientX - startX;
        const dy = e.touches[0].clientY - startY;
        startX = e.touches[0].clientX;
        startY = e.touches[0].clientY;
        posX += dx;
        posY += dy;
        constrainPosition();
        updateImageTransform();
    }
    if (e.touches.length === 2) {
        const touch1 = e.touches[0];
        const touch2 = e.touches[1];
        const currentDistance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY);
        const delta = currentDistance - initialDistance;
        scale = Math.max(1, initialScale + delta * 0.01); // Ajustez le facteur de zoom
        constrainPosition();
        updateImageTransform();
    }
});

image.addEventListener('touchend', (e) => {
    // Rien à faire lors de la fin du toucher
});</script>
<script>


window.addEventListener('load', function() {
    function adjustContainerSize() {
        const imageRect = image.getBoundingClientRect();
        const containerHeight = image.parentElement.clientHeight;
        const imageHeight = imageRect.height;
        const imageWidth = imageRect.width;

        const containerWidth = (imageWidth / imageHeight) * containerHeight;
        image.parentElement.style.width = containerWidth + 'px';
    }

    adjustContainerSize();

    window.addEventListener('resize', adjustContainerSize);
});   </script>
 <script>
     // Fonction pour ouvrir l'image en plein écran
    function openFullscreen() {
        const fullscreenImageContainer = document.getElementById('fullscreenImageContainer');
        fullscreenImageContainer.style.display = 'flex';
    }

    // Fonction pour fermer l'image en plein écran
    function closeFullscreen() {
        const fullscreenImageContainer = document.getElementById('fullscreenImageContainer');
        fullscreenImageContainer.style.display = 'none';
    }

    // Gestion de l'événement ESC pour fermer l'image en plein écran
    document.addEventListener('keydown', function(event) {
        if (event.key === 'Escape') {
            closeFullscreen();
        }
    });
ript>
 <script>
     // Fonction pour ouvrir l'image en plein écran
    function openFullscreen() {
        const fullscreenImageContainer = document.getElementById('fullscreenImageContainer');
        fullscreenImageContainer.style.display = 'flex';
    }

    // Fonction pour fermer l'image en plein écran
    function closeFullscreen() {
        const fullscreenImageContainer = document.getElementById('fullscreenImageContainer');
        fullscreenImageContainer.style.display = 'none';
    }

    // Gestion de l'événement ESC pour fermer l'image en plein écran
    document.addEventListener('keydown', function(event) {
        if (event.key === 'Escape') {
            closeFullscreen();
        }
    });
 </script>   


What I would like it to do is to be linked to the <div class="image-group"> the action is happening in. If i have two of them, the actions are happening in the one where the button is clicked, not the other same underneath.

(For demo purpose, you can see how it is integrated here: http://astrostuff.franceserv.com/Ref/Public/Post.php?ID=9D466F87-FC78-31C7-5C05-5AD6A55F6897).

The ideal situation would be to have multiple image-group, like this:

<div class="image-group">
    <div class="image-container">
        <img class="image" src="/Uploads/Images/IMG_7342_pipp_top_100r__651_regedited-2.jpg" alt="">
    </div>
    <div class="fullscreenImageContainer" onclick="closeFullscreen()">
        <span class="closeButton">X</span>
        <img class="fullscreenImage" src="/Uploads/Images/IMG_7342_pipp_top_100r__651_regedited-2.jpg" alt="">
    </div>
    <div class="zoombuttons">
        <button onclick="zoomIn(this)">Zoom +</button>
        <button onclick="zoomOut(this)">Zoom -</button>
        <button onclick="resetZoom(this)">Réinitialiser</button>
        <button onclick="openFullscreen(this)">Plein écran</button>
    </div>
</div>

And another one

And another one

without interaction conflict.

But to be honest, this is not my code, I only have a few basics for simple things in js, and I have no clue of how to get it to work (long story short, I tried a few approaches who were pretty much a disaster).

I deleted the approaches I tried, so sadly I don't have any examples. But basically, I tried an approach similar to this:

    <button onclick="zoomIn(this)">Zoom +</button>
<script>
    function zoomIn(button) {
        const imageGroup = button.closest('.image-group');
        const image = imageGroup.querySelector('.image');
        let scale = parseFloat(image.dataset.scale) || 1;
        scale *= 1.1;
        image.dataset.scale = scale;
        updateImageTransform(image);
    }
</script>

and it didn't work very well (it prevented the top image to interact with the bottom one, but the top image still react to the button of the bottom one).

0

There are 0 best solutions below