Zoeken…


Een responsief canvas van een hele pagina maken

Startercode om een canvas met volledige pagina te maken en te verwijderen dat reageert op het formaat van gebeurtenissen wijzigen via JavaScript.

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.

Als u het canvas niet langer nodig hebt, kunt u het verwijderen door removeCanvas() aan te roepen

Een demo van dit voorbeeld op jsfiddle

Muiscoördinaten na vergroten / verkleinen (of scrollen)

Canvas-apps zijn vaak sterk afhankelijk van gebruikersinteractie met de muis, maar wanneer het formaat van het venster wordt gewijzigd, worden de muisgebeurteniscoördinaten waarop canvas vertrouwt waarschijnlijk gewijzigd omdat het formaat van het canvas ertoe leidt dat het canvas in een andere positie ten opzichte van het venster wordt verschoven. Daarom vereist een responsief ontwerp dat de canvas-offsetpositie opnieuw wordt berekend wanneer het venster wordt verkleind - en ook opnieuw wordt berekend wanneer het venster wordt geschoven.

Deze code luistert naar venstergrootte van gebeurtenissen en herberekent de offsets die worden gebruikt in muisgebeurtenishandlers:

// 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);
    // ...
}

Responsieve canvasanimaties zonder het formaat van gebeurtenissen te wijzigen.

De gebeurtenissen voor het wijzigen van het venster kunnen worden geactiveerd in reactie op de beweging van het invoerapparaat van de gebruiker. Wanneer u het formaat van een canvas wijzigt, wordt dit automatisch gewist en moet u de inhoud opnieuw renderen. Voor animaties doet u dit elk frame via de hoofdlusfunctie genaamd requestAnimationFrame die zijn best doet om de weergave synchroon te houden met de displayhardware.

Het probleem met de gebeurtenis resize is dat wanneer de muis wordt gebruikt om de grootte van het venster te wijzigen, de gebeurtenissen vele malen sneller kunnen worden geactiveerd dan de standaard 60fps snelheid van de browser. Wanneer de gebeurtenis resize wordt afgesloten, wordt de canvasback-buffer gepresenteerd aan de DOM, niet synchroon met het weergaveapparaat, wat shearing en andere negatieve effecten kan veroorzaken. Er is ook veel onnodige geheugentoewijzing en -uitgave die de animatie verder kan beïnvloeden wanneer GC enige tijd daarna opruimt.


Debounced resize-gebeurtenis

Een gebruikelijke manier om met de hoge snelheid van het resize-evenement om te gaan, is door het resize-evenement te debounken.

 // 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 ... }

In het bovenstaande voorbeeld wordt het formaat van het canvas uitgesteld tot 100 ms na de gebeurtenis Resize. Als in die tijd verdere resize-events worden geactiveerd, wordt de bestaande time-outtime-out geannuleerd en een nieuwe gepland. Dit verbruikt effectief de meeste resize-evenementen.

Het heeft nog steeds enkele problemen, de meest opvallende is de vertraging tussen het wijzigen van het formaat en het zien van het aangepaste canvas. Het verkorten van de debouncetijd verbetert dit, maar het formaat is nog steeds niet gesynchroniseerd met het weergaveapparaat. Je hebt ook nog steeds de animatie hoofdlus rendering naar een slecht passend canvas.

Meer code kan de problemen verminderen! Meer code creëert ook zijn eigen nieuwe problemen.


Eenvoudig en het beste formaat wijzigen

Na vele verschillende manieren geprobeerd te hebben om het formaat van het canvas glad te strijken, van het absurd complexe tot het probleem negeren (wat maakt het je eigenlijk uit?) Viel ik terug op een vertrouwde vriend.

KISS is iets wat de meeste programmeurs moeten zich bewust zijn van ((K EEP I t S uitvoe S tupid) De dom verwijst naar me voor het niet hebben gedacht van het jaren geleden.) En het blijkt dat de beste oplossing is de eenvoudigste van allemaal.

Pas het formaat van het canvas aan vanuit de hoofdanimatielus. Het blijft synchroon met het weergaveapparaat, er is geen onnodige rendering en het resourcebeheer is zo minimaal mogelijk met behoud van de volledige framesnelheid. U hoeft ook geen gebeurtenis om het formaat te wijzigen of extra functies voor het wijzigen van het formaat toe te voegen.

U voegt het formaat toe waar u normaal het canvas zou wissen door te controleren of de canvasgrootte overeenkomt met de venstergrootte. Wijzig het formaat als dit niet het geval is.

// 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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow