Buscar..
Creación de un lienzo de página completa sensible
Código de inicio para crear y eliminar un lienzo de página completa que responde para cambiar el tamaño de los eventos a través de 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 ya no necesita el lienzo, puede eliminarlo llamando a removeCanvas()
Una demostración de este ejemplo en jsfiddle
Coordenadas del ratón después de cambiar el tamaño (o desplazamiento)
Las aplicaciones de lienzo a menudo dependen en gran medida de la interacción del usuario con el mouse, pero cuando se cambia el tamaño de la ventana, las coordenadas del evento del mouse en las que se basa el lienzo probablemente se cambian porque el cambio de tamaño hace que el lienzo se desplace en una posición diferente con respecto a la ventana. Por lo tanto, el diseño responsivo requiere que la posición de desplazamiento del lienzo se vuelva a calcular cuando se cambie el tamaño de la ventana, y también se vuelva a calcular cuando la ventana se desplace.
Este código escucha los eventos de cambio de tamaño de la ventana y vuelve a calcular las compensaciones utilizadas en los controladores de eventos del mouse:
// 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);
// ...
}
Animaciones de lienzos sensibles sin eventos de cambio de tamaño.
Los eventos de cambio de tamaño de la ventana pueden activarse en respuesta al movimiento del dispositivo de entrada del usuario. Cuando cambia el tamaño de un lienzo, se borra automáticamente y se ve obligado a volver a renderizar el contenido. Para las animaciones, haga esto en cada fotograma a través de la función de bucle principal llamada por requestAnimationFrame
que hace todo lo posible para mantener la representación sincronizada con el hardware de la pantalla.
El problema con el evento de cambio de tamaño es que cuando se usa el mouse para cambiar el tamaño de la ventana, los eventos pueden activarse muchas veces más rápido que la tasa estándar de 60 fps del navegador. Cuando el evento de cambio de tamaño sale del lienzo, el búfer posterior se presenta al DOM desincronizado con el dispositivo de visualización, lo que puede causar distorsión y otros efectos negativos. También hay una gran cantidad de memoria y distribución innecesarias que pueden afectar aún más a la animación cuando GC se limpia un poco después.
Evento de cambio de tamaño anunciado
Una forma común de lidiar con las altas tasas de activación del evento de cambio de tamaño es rebotar el evento de cambio de tamaño.
// 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 ... }
El ejemplo anterior retrasa el cambio de tamaño del lienzo hasta 100 ms después del evento de cambio de tamaño. Si en ese momento se activan más eventos de cambio de tamaño, se cancela el tiempo de espera de cambio de tamaño existente y se programa uno nuevo. Esto efectivamente consume la mayoría de los eventos de cambio de tamaño.
Todavía tiene algunos problemas, el más notable es el retraso entre cambiar el tamaño y ver el lienzo redimensionado. Reducir el tiempo de rebote mejora esto, pero el cambio de tamaño aún no está sincronizado con el dispositivo de pantalla. También tiene la representación de bucle principal de animación en un lienzo de mal ajuste.
¡Más código puede reducir los problemas! Más código también crea sus propios problemas nuevos.
Simple y el mejor tamaño
Después de haber probado muchas formas diferentes de suavizar el cambio de tamaño del lienzo, desde el complejo absurdamente, hasta simplemente ignorar el problema (¿a quién le importa de todos modos?) Me volví a un amigo de confianza.
KISS es algo de lo que la mayoría de los programadores deberían saber (( K eep I t S ple S tple Supple) El estúpido se refiere a mí por no haberlo pensado hace años ) y resulta que la mejor solución es la más simple de todas.
Simplemente redimensiona el lienzo desde dentro del bucle principal de animación. Permanece sincronizado con el dispositivo de visualización, no hay una representación innecesaria y la gestión de recursos es lo mínimo posible mientras se mantiene la velocidad de fotogramas completa. Tampoco necesita agregar un evento de cambio de tamaño a la ventana o cualquier función de cambio de tamaño adicional.
Agregue el tamaño del lugar donde normalmente borraría el lienzo al verificar si el tamaño del lienzo coincide con el tamaño de la ventana. Si no lo cambiamos de tamaño.
// 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);
}