Zooming funktioniert nicht

rernanded

Erfahrenes Mitglied
Hallo,
habe dieses Script doch das gewünschte Zooming an der jeweils im Bild angeklickten Stelle in den Grössenstufen im Radius von 10px, 20px, 30px funktioniert nicht.
MONI
HTML:
<!DOCTYPE html>
<html>
<head>
    <title>Interactive Pixel Zoom</title>
    <style>
        .container {
            display: flex;
            gap: 20px;
            padding: 20px;
        }
     
        #mainCanvas {
            border: 1px solid #ccc;
            cursor: pointer;
            position: relative;
        }
     
        .controls {
            margin-bottom: 10px;
        }
     
        button {
            margin-right: 10px;
            padding: 5px 10px;
        }
     
        .zoom-overlay {
            position: absolute;
            pointer-events: none;
            box-shadow: 0 0 10px rgba(255,0,0,0.5);
        }
    </style>
</head>
<body>
    <div class="container">
        <div>
            <input type="file" id="imageUpload" accept="image/*">
            <div class="controls">
                <button onclick="zoomIn()">Zoom In</button>
                <button onclick="zoomOut()">Zoom Out</button>
                <span id="currentZoom">Current Zoom: 1x</span>
            </div>
            <canvas id="mainCanvas"></canvas>
        </div>
    </div>

    <script>
        const mainCanvas = document.getElementById('mainCanvas');
        const mainCtx = mainCanvas.getContext('2d');
     
        let currentImage = null;
        let zoomLevel = 1;
        let lastClickX = 0;
        let lastClickY = 0;
     
        document.getElementById('imageUpload').addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (!file) return;
         
            const reader = new FileReader();
            reader.onload = function(event) {
                const img = new Image();
                img.onload = function() {
                    currentImage = img;
                    mainCanvas.width = img.width;
                    mainCanvas.height = img.height;
                    drawImage();
                };
                img.src = event.target.result;
            };
            reader.readAsDataURL(file);
        });
     
        function drawImage() {
            mainCtx.clearRect(0, 0, mainCanvas.width, mainCanvas.height);
            if (currentImage) {
                mainCtx.drawImage(currentImage, 0, 0);
            }
        }
     
        mainCanvas.addEventListener('click', function(event) {
            const rect = mainCanvas.getBoundingClientRect();
            const x = event.clientX - rect.left;
            const y = event.clientY - rect.top;
         
            console.log(`Clicked at (${x}, ${y})`);
         
            lastClickX = x;
            lastClickY = y;
         
            drawImage();
            drawZoomedSection(x, y);
        });
     
        function drawZoomedSection(x, y) {
            const size = 10 * zoomLevel;
            const radius = size / 2;
         
            // Calculate source circle area
            const srcX = Math.max(0, Math.min(x - radius, currentImage.width - size));
            const srcY = Math.max(0, Math.min(y - radius, currentImage.height - size));
         
            // Draw circular overlay
            mainCtx.save();
            mainCtx.beginPath();
            mainCtx.arc(srcX + radius, srcY + radius, radius, 0, Math.PI * 2);
            mainCtx.strokeStyle = 'red';
            mainCtx.lineWidth = 2;
            mainCtx.stroke();
         
            // Draw zoomed area
            mainCtx.globalCompositeOperation = 'destination-over';
            mainCtx.beginPath();
            mainCtx.arc(x, y, radius * zoomLevel, 0, Math.PI * 2);
            mainCtx.clip();
         
            // Draw zoomed section
            mainCtx.drawImage(
                currentImage,
                srcX, srcY, size, size,
                x - radius * zoomLevel, y - radius * zoomLevel,
                size * zoomLevel, size * zoomLevel
            );
         
            mainCtx.restore();
        }
     
        function zoomIn() {
            if (zoomLevel < 3) {
                zoomLevel++;
                document.getElementById('currentZoom').textContent =
                    `Current Zoom: ${zoomLevel * 10}px`;
             
                if (lastClickX && lastClickY) {
                    drawImage();
                    drawZoomedSection(lastClickX, lastClickY);
                }
            }
        }
     
        function zoomOut() {
            if (zoomLevel > 1) {
                zoomLevel--;
                document.getElementById('currentZoom').textContent =
                    `Current Zoom: ${zoomLevel * 10}px`;
             
                if (lastClickX && lastClickY) {
                    drawImage();
                    drawZoomedSection(lastClickX, lastClickY);
                }
            }
        }
    </script>
</body>
</html>
 
Hallo Moni,
Du setzt die globalCompositeOperation auf 'destination-over' dadurch werden anschließende Formen hinter das existierende Bild gezeichnet. Das ist für das Zeichnen des Clipping-Bereichs so weit OK aber anschließend wirkt es auch auf das Zeichnen des vergrößerten Bildes.
Lösung einfach, indem Du die globalCompositeOperation wieder auf den Default-Wert zurück setzt:
Code:
            // Draw zoomed area
            mainCtx.globalCompositeOperation = 'destination-over';
            mainCtx.beginPath();
            mainCtx.arc(x, y, radius * zoomLevel, 0, Math.PI * 2);
            mainCtx.clip();

            // Draw zoomed section
            mainCtx.globalCompositeOperation = 'source-over';
            mainCtx.drawImage(
                currentImage,
                srcX, srcY, size, size,
                x - radius * zoomLevel, y - radius * zoomLevel,
                size * zoomLevel, size * zoomLevel
            );

BTW: Noch cooler fände ich es, wenn man den gezoomten Bereich durch Ziehen mit der Maus verschieben könnte statt neu zu klicken.
 
Danke, klappt super. Dein BTW-Vorschlag ist auch gut, wenn Du dazu eine Zeile hast, her damit bitte.

Eigentlich aber liegt mir was anderes mehr am Herzen, denn ich möchte gar nicht, dass sich jeweils der gesamte Bereich im jeweiligen Radius vergrössert, sondern am besten von innen nach aussen sozusagen smooth abnehmend. Nennt man das Fischauge?
Und, dass ich mehr als nur einen Radius gleichzeitig setzen kann.
Zu beidem habe ich überhaupt keine Idee.
MONI
 
dass sich jeweils der gesamte Bereich im jeweiligen Radius vergrössert, sondern am besten von innen nach aussen sozusagen smooth abnehmend.
Ich glaube, ich verstehe, was Du meinst. Und mir scheint, ich habe so etwas früher schon gemacht. Werde mal nachsehen, ob ich es finde.
 
Dein BTW-Vorschlag ist auch gut, wenn Du dazu eine Zeile hast, her damit bitte.
Ist ja schon alles da, wir brauchen nur einige Eventlistener mehr:
Code:
        mainCanvas.addEventListener('mousedown', function (event) {
            const rect = mainCanvas.getBoundingClientRect();
            const x = event.clientX - rect.left;
            const y = event.clientY - rect.top;

            console.log(`Clicked at (${x}, ${y})`);

            lastClickX = x;
            lastClickY = y;

            // Merken, dass die Maus gedrückt ist:
            mouseIsDown = true;

            drawImage();
            drawZoomedSection(x, y);
        });

        mainCanvas.addEventListener('mouseup', function (event) {
            if (mouseIsDown) {
                // Merker "Maus ist gedrückt" löschen:
                mouseIsDown = false;
                // Bild neu zeichnen um den gezoomten Bereich zu löschen:
                drawImage();
            }
        });

        mainCanvas.addEventListener('mousemove', function (event) {
            // Nur wenn die Maus gedrückt ist:
            if (mouseIsDown) {
                const rect = mainCanvas.getBoundingClientRect();
                const x = event.clientX - rect.left;
                const y = event.clientY - rect.top;

                console.log(`Moved to (${x}, ${y})`);

                lastClickX = x;
                lastClickY = y;

                drawImage();
                drawZoomedSection(x, y);

            }
        });
 

Neue Beiträge

Zurück