Suche…


Erstellen einer Responsive Full Page Canvas

Starter-Code zum Erstellen und Entfernen eines vollständigen Seitenbereichs, der auf die Größenänderung von Ereignissen über Javascript reagiert.

var canvas;    // Global canvas reference
var ctx;       // Global 2D context reference
// Creates a canvas
function createCanvas () {                
    const canvas = document.createElement("canvas"); 
    canvas.style.position = "absolute"; // Set the style 
    canvas.style.left     = "0px";      // Position in top left
    canvas.style.top      = "0px";
    canvas.style.zIndex   = 1;        
    document.body.appendChild(canvas);  // Add to document
    return canvas;
}
// Resizes canvas. Will create a canvas if it does not exist
function sizeCanvas () {                
    if (canvas === undefined) {         // Check for global canvas reference
        canvas = createCanvas();        // Create a new canvas element
        ctx = canvas.getContext("2d");  // Get the 2D context
    }
    canvas.width  = innerWidth;         // Set the canvas resolution to fill the page
    canvas.height = innerHeight;        
}
// Removes the canvas
function removeCanvas () {
    if (canvas !== undefined) {              // Make sure there is something to remove
        removeEventListener("resize", sizeCanvas); // Remove resize event
        document.body.removeChild(canvas);   // Remove the canvas from the DOM
        ctx = undefined;                     // Dereference the context
        canvas = undefined;                  // Dereference the canvas
     }
}

// Add the resize listener
addEventListener("resize", sizeCanvas); 
// Call sizeCanvas to create and set the canvas resolution
sizeCanvas();
// ctx and canvas are now available for use.

Wenn Sie die Leinwand nicht mehr benötigen, können Sie sie entfernen, indem Sie removeCanvas() aufrufen.

Eine Demo dieses Beispiels bei jsfiddle

Mauskoordinaten nach Größenänderung (oder Scrollen)

Canvas-Apps sind häufig stark von der Benutzerinteraktion mit der Maus abhängig, aber wenn die Fenstergröße geändert wird, werden die Mausereigniskoordinaten, auf die sich der Canvas bezieht, wahrscheinlich geändert, da die Größe des Canvas zu einer anderen Position relativ zum Fenster verschoben wird. Daher erfordert das responsive Design, dass die Leinwandversatzposition neu berechnet wird, wenn die Größe des Fensters geändert wird, und auch neu berechnet wird, wenn das Fenster gescrollt wird.

Dieser Code wartet auf die Größenänderung von Fenstern und berechnet die in Mausereignishandlern verwendeten Offsets neu:

// variables holding the current canvas offset position
//    relative to the window
var offsetX,offsetY;

// a function to recalculate the canvas offsets
function reOffset(){
    var BB=canvas.getBoundingClientRect();
    offsetX=BB.left;
    offsetY=BB.top;        
}

// listen for window resizing (and scrolling) events
//     and then recalculate the canvas offsets
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }

// example usage of the offsets in a mouse handler
function handleMouseUp(e){
    // use offsetX & offsetY to get the correct mouse position
    mouseX=parseInt(e.clientX-offsetX);
    mouseY=parseInt(e.clientY-offsetY);
    // ...
}

Responsive Canvas-Animationen ohne Größenänderung von Ereignissen.

Die Fenstergrößenänderungsereignisse können als Reaktion auf die Bewegung des Eingabegeräts des Benutzers ausgelöst werden. Wenn Sie die Größe einer Leinwand ändern, wird sie automatisch gelöscht, und Sie müssen den Inhalt erneut rendern. Für Animationen machen Sie dies für jedes Bild über die von requestAnimationFrame aufgerufene requestAnimationFrame die das Beste tut, um das Rendern mit der Display-Hardware synchron zu halten.

Das Problem mit dem Größenänderungsereignis besteht darin, dass die Ereignisse bei Verwendung der Maus zum Ändern der Fenstergröße um ein Vielfaches schneller als die standardmäßige 60-fps-Rate des Browsers ausgelöst werden können. Wenn das Größenänderungsereignis beendet ist, wird der Canvas-Back-Puffer dem DOM nicht mit dem Anzeigegerät synchron angezeigt, was zu Scherung und anderen negativen Effekten führen kann. Es gibt auch eine Menge unnötiger Speicherzuweisung und -freigabe, die die Animation weiter beeinflussen kann, wenn GC einige Zeit später bereinigt wird.


Entprelltes Größenänderungsereignis

Ein üblicher Weg, um mit den hohen Auslösungsraten des Größenänderungsereignisses umzugehen, besteht darin, das Größenänderungsereignis zu entprellen.

 // Assume canvas is in scope
 addEventListener.("resize", debouncedResize );

 // debounce timeout handle
 var debounceTimeoutHandle;

 // The debounce time in ms (1/1000th second)
 const DEBOUNCE_TIME = 100; 

 // Resize function 
 function debouncedResize () { 
     clearTimeout(debounceTimeoutHandle);  // Clears any pending debounce events

     // Schedule a canvas resize 
     debounceTimeoutHandle = setTimeout(resizeCanvas, DEBOUNCE_TIME);
 }

 // canvas resize function
 function resizeCanvas () { ... resize and redraw ... }

Das obige Beispiel verzögert die Größenänderung der Leinwand bis 100 ms nach dem Größenänderungsereignis. Wenn in dieser Zeit weitere Größenänderungsereignisse ausgelöst werden, wird das vorhandene Zeitlimit für die Größenänderung abgebrochen und ein neues geplant. Dadurch werden die meisten Größenänderungsereignisse effektiv verbraucht.

Es hat immer noch einige Probleme, die bemerkenswerteste ist die Verzögerung zwischen dem Ändern der Größe und dem Anzeigen der Größe der Leinwand. Das Verringern der Entprellzeit verbessert dies, aber die Größenänderung ist immer noch nicht mit dem Anzeigegerät synchronisiert. Sie haben auch noch die Animationshauptschleife, die auf eine schlecht passende Leinwand gerendert wird.

Mehr Code kann die Probleme reduzieren! Mehr Code schafft auch neue Probleme.


Einfach und die beste Größe

Ich habe viele verschiedene Möglichkeiten ausprobiert, um die Größenänderung der Leinwand auszugleichen, von der absurden Komplexität bis hin zum Ignorieren des Problems (wen interessiert das schon?).

KISS ist für die meisten Programmierer sollten sich bewusst sein ((K eep I t S imple S tupid) Der dumme vor für nicht mit Gedanken daran Jahren mir bezieht.) Und es stellt sich heraus , die beste Lösung die einfachste von allen ist.

Ändern Sie einfach die Größe der Leinwand innerhalb der Hauptanimationsschleife. Es bleibt mit dem Anzeigegerät synchron, es gibt kein unnötiges Rendern und die Ressourcenverwaltung ist auf ein Minimum beschränkt, während die volle Bildrate erhalten bleibt. Außerdem müssen Sie dem Fenster weder ein Größenänderungsereignis noch zusätzliche Funktionen zur Größenänderung hinzufügen.

Sie fügen die Größe an der Stelle hinzu, an der Sie normalerweise die Leinwand löschen würden, indem Sie überprüfen, ob die Leinwandgröße der Fenstergröße entspricht. Wenn nicht, ändern Sie die Größe.

// Assumes canvas element is in scope as canvas

// Standard main loop function callback from requestAnimationFrame
function mainLoop(time) {

    // Check if the canvas size matches the window size
    if (canvas.width !== innerWidth || canvas.height !== innerHeight) {
        canvas.width = innerWidth;    // resize canvas
        canvas.height = innerHeight;  // also clears the canvas
    } else {
        ctx.clearRect(0, 0, canvas.width, canvas.height); // clear if not resized
    }

    // Animation code as normal.



    requestAnimationFrame(mainLoop);
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow