Recherche…


Créer un canevas pleine page réactif

Code de démarrage pour créer et supprimer un canevas pleine page qui répond au redimensionnement d'événements 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.

Si vous n'avez plus besoin de la toile, vous pouvez la supprimer en appelant removeCanvas()

Une démo de cet exemple à jsfiddle

Coordonnées de la souris après le redimensionnement (ou le défilement)

Les applications Canvas reposent souvent sur l'interaction de l'utilisateur avec la souris, mais lorsque la fenêtre est redimensionnée, les coordonnées d'événement de la souris sur lesquelles repose le canevas sont probablement modifiées car le redimensionnement entraîne un décalage du canevas par rapport à la fenêtre. Ainsi, la conception réactive nécessite que la position de décalage de la zone de dessin soit recalculée lorsque la fenêtre est redimensionnée - et également recalculée lorsque la fenêtre défile.

Ce code écoute les événements de redimensionnement de fenêtre et recalcule les décalages utilisés dans les gestionnaires d'événement de souris:

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

Animations sur toile réactives sans événements de redimensionnement.

Les événements de redimensionnement de la fenêtre peuvent se déclencher en réponse au mouvement du périphérique de saisie de l'utilisateur. Lorsque vous redimensionnez un canevas, il est automatiquement effacé et vous êtes obligé de restituer le contenu. Pour les animations, vous faites ceci chaque image via la fonction de boucle principale appelée par requestAnimationFrame qui fait de son mieux pour maintenir le rendu synchronisé avec le matériel d'affichage.

Le problème avec l'événement de redimensionnement est que lorsque la souris est utilisée pour redimensionner la fenêtre, les événements peuvent être déclenchés beaucoup plus rapidement que le taux standard de 60 images par seconde du navigateur. Lorsque l'événement de redimensionnement quitte le tampon de retour, celui-ci n'est plus synchronisé avec le périphérique d'affichage, ce qui peut entraîner des effets de cisaillement et d'autres effets négatifs. Il y a également beaucoup d'allocation et de libération de mémoire inutiles qui peuvent influer davantage sur l'animation lorsque le CPG se nettoie quelque temps après.


Evénement de redimensionnement annoncé

Une manière courante de gérer les taux de déclenchement élevés de l’événement de redimensionnement consiste à éliminer l’événement de redimensionnement.

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

L'exemple ci-dessus retarde le redimensionnement du canevas jusqu'à 100 ms après l'événement de redimensionnement. Si, au cours de cette période, d'autres événements de redimensionnement sont déclenchés, le délai d'expiration du redimensionnement existant est annulé et un nouveau planifié. Cela consomme efficacement la plupart des événements de redimensionnement.

Il y a toujours des problèmes, le plus notable est le délai entre le redimensionnement et la visualisation du canevas redimensionné. La réduction du temps de réponse améliore cela, mais le redimensionnement est toujours en décalage avec le périphérique d'affichage. Vous avez également le rendu de la boucle d'animation principale sur un canevas mal ajusté.

Plus de code peut réduire les problèmes! Plus de code crée également ses propres problèmes.


Simple et le meilleur redimensionnement

Après avoir essayé de nombreuses manières différentes de lisser le redimensionnement de la toile, du complexe absurde au simple fait d’ignorer le problème (qui se soucie de toute façon?), Je suis tombé sur un ami de confiance.

Kiss est quelque chose la plupart des programmeurs doivent être conscients de ((K EEP I t S S tupid œuvre) La bête se réfère à moi de ne pas avoir pensé il y a quelques années.) Et il se trouve la meilleure solution est la plus simple de tous.

Il suffit de redimensionner le canevas à partir de la boucle d'animation principale. Il reste synchronisé avec le périphérique d'affichage, il n'y a pas de rendu inutile et la gestion des ressources est au minimum possible tout en maintenant une fréquence d'images maximale. Vous n'avez pas non plus besoin d'ajouter un événement de redimensionnement à la fenêtre ou des fonctions de redimensionnement supplémentaires.

Vous ajoutez le redimensionnement où vous effaceriez normalement le canevas en vérifiant si la taille du canevas correspond à la taille de la fenêtre. Si ce n'est pas le redimensionner.

// 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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow