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);

            }
        });
 
Klappt sehr gut. Danke Dir. Wenn ich drawImage(); inaktiviere kann ich durch Klick in den Zoombereich das gesamte Bild speichern.
HTML:
 // Bild neu zeichnen um den gezoomten Bereich zu löschen:
//  drawImage();


Der gesamte Code sieht nun so aus, wobei ich auch die Zoom-Schritte geändert habe (steht in jeder Zeile dahinter), was aber nicht so ganz funktioniert:

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 = 1 * zoomLevel;                            //geändert
            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 = 3;                            //geändert
            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.globalCompositeOperation = 'source-over';
            mainCtx.drawImage(
                currentImage,
                srcX, srcY, size, size,
                x - radius * zoomLevel, y - radius * zoomLevel,
                size * zoomLevel, size * zoomLevel
            );
           
            mainCtx.restore();
        }
       
        function zoomIn() {
            if (zoomLevel < 30) {                            //geändert
                zoomLevel++;
                document.getElementById('currentZoom').textContent =
                    `Current Zoom: ${zoomLevel * 1}px`;                    //geändert
               
                if (lastClickX && lastClickY) {
                    drawImage();
                    drawZoomedSection(lastClickX, lastClickY);
                }
            }
        }
       
        function zoomOut() {
            if (zoomLevel > 1) {
                zoomLevel--;
                document.getElementById('currentZoom').textContent =
                    `Current Zoom: ${zoomLevel * 1}px`;                    //geändert
               
                if (lastClickX && lastClickY) {
                    drawImage();
                    drawZoomedSection(lastClickX, lastClickY);
                }
            }
        }

//   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU   NEU

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;

            // "Maus ist down" merken
            mouseIsDown = true;

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

   mainCanvas.addEventListener('mouseup', function (event) {
            if (mouseIsDown) {
                // "Maus ist down" canceln
                mouseIsDown = false;
                // Bild neu zeichnen um den gezoomten Bereich zu löschen:
                // drawImage(); // if inactive a left mouse click in the zoomed area is possible to store the whole image    //geändert
            }
        });

        mainCanvas.addEventListener('mousemove', function (event) {
            // nur wenn Maus down 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);

            }
        });
    </script>
</body>
</html>
 
wobei ich auch die Zoom-Schritte geändert habe (steht in jeder Zeile dahinter), was aber nicht so ganz funktioniert
Was genau funktioniert denn nicht? Der Bereich wird gezoomt und bleibt auch erhalten wenn man die Maus los lässt. Vielleicht ist der Zoomfaktor ein wenig zu hoch.

Du wolltest doch diesen Fisheye-Effekt haben. Hast Du schon versucht, das anzupassen?
Ebenfalls Eventlistener für Mouse-down und Mouse-up und beim Bewegen nur zoomen wenn die Maus gedrückt ist.
 

Neue Beiträge

Zurück