Sök…


Skapa en lyhörd duk på hela sidan

Startkod för att skapa och ta bort en hemsida som svarar för att ändra storlek på händelser 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.

Om du inte längre behöver duken kan du ta bort den genom att ringa removeCanvas()

En demo av det här exemplet på jsfiddle

Muskoordinater efter storleksändring (eller rullning)

Canvas-appar förlitar sig ofta starkt på användarens interaktion med musen, men när fönstret ändras i storlek ändras sannolikt mushändelsekoordinaterna som duken förlitar sig på eftersom storleksändring gör att canvasen kompenseras i en annan position relativt fönstret. Således kräver responsiv design att läget för förskjutning av kanfas beräknas om när fönstret ändras i storlek - och också beräknas igen när fönstret rullas.

Den här koden lyssnar på fönstret för att ändra storlek på händelser och beräknar förskjutningar som används i mushändelseshanterare:

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

Responsiva kanfasanimationer utan att ändra storlek på händelser.

Händelsernas storlek på storleken kan avfyras som svar på rörelsen för användarens inmatningsenhet. När du ändrar storlek på en duk rensas den automatiskt och du tvingas återge innehållet. För animationer gör du detta varje ram via huvudslingfunktionen som kallas av requestAnimationFrame som gör sitt bästa för att hålla rendering synkroniserad med skärmhårdvaran.

Problemet med storlekshändelsen är att när musen används för att ändra storlek på fönstret kan händelserna utlösas många gånger snabbare än webbläsarens standardfrekvens på 60 fps. När storlekshändelsen går ut presenteras bakre kanvasbuffert för DOM från synkronisering med displayenheten, vilket kan orsaka skjuvning och andra negativa effekter. Det finns också mycket onödigt allokering och frigörelse av minnet som kan påverka animeringen ytterligare när GC städar upp lite tid efteråt.


Återställd storlekshändelse

Ett vanligt sätt att hantera storlekshändelsens höga skottfrekvens är att debattera storlekshändelsen.

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

Exemplet ovan försenar storleken på duken tills 100 ms efter storlekshändelsen. Om ytterligare storlekshändelser utlöses under den tiden avbryts den nuvarande storleken på storleksstorleken och en ny planeras. Detta konsumerar effektivt de flesta av storleksändringarna.

Det har fortfarande några problem, det mest anmärkningsvärda är förseningen mellan att ändra storleken och se den storlek på duken. Att minska avstängningstiden förbättrar detta men storleken ändå är inte synkroniserad med skärmenheten. Du har fortfarande animationen huvudslingan återgivning till en dålig passande duk.

Mer kod kan minska problemen! Mer kod skapar också egna nya problem.


Enkel och den bästa storleken

Efter att ha försökt många olika sätt att jämna ut storleken på duken, från det absurda komplexa, till att bara ignorera problemet (vem bryr sig ändå?) Föll jag tillbaka till en pålitlig vän.

KISS är något de flesta programmerare borde vara medvetna om (( K eep I t S imple S tupid) Den dumma hänvisar till mig för att jag inte har tänkt på det för år sedan. ) Och det visar sig att den bästa lösningen är den enklaste av alla.

Ändra storleken på duken från huvudanimationsslingan. Det förblir synkroniserat med bildskärmsenheten, det finns ingen onödig återgivning, och resurshanteringen är på det minsta möjliga med bibehållen full bildhastighet. Du behöver inte heller lägga till en storlekshändelse i fönstret eller ytterligare storlekar på funktioner.

Du lägger till storleken där du normalt skulle rensa duken genom att kontrollera om dukstorleken matchar fönsterstorleken. Om inte ändra storlek på den.

// 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow