Esta traducción está incompleta. Por favor, ayuda a traducir este artículo del inglés.
Ya que estamos usando JavaScript para controlar los <canvas>
, tambien es muy facil hacer animaciones (interactivos). En este capitulo veremos como hacer algunas animaciones basicas.
Probablemente la mayor limitacion es, que una vez que la forma se dibuja, quede asi. Y si tuvieramos que moverla tendriamos que redibujar todo y todo lo que fue dibujado antes. Esto tomaria mucho tiempo en redibujar (los marcos y las figuras complejas) y esto va a depender en gran medida de la velocidad a la que corra tu computadora.
Pasos para una Animacion Basica
Estos son los pasos que necesitas para dibujar un marco:
- Limpiar el Canva
A menos que la forma que dibujes llene por completo el canva (Por Ejemplo una imagen de fondo), necesitas limpiar cualquier forma que hallas dibujado previamente. Esto facilemente podrias hacerlo usando el metodoclearRect()
. - Guardar el estado del Canva
Si tu modificas cualquier ajuste (como un estilo, transfomacion, etc.) que afecte estado del canva y quieres asegurarte que el estado original se use cada vez que dibujes un marco, entonces necesitas guardar el estado original. - Dibujar formas animadas
Este es le paso donde haces el renderizado del marco actual. - Restaurar el estado del Canva
Si tu has guardado el estado del canva, debes restaurarlo antes de dibujar un nuevo marco.
Controlar una Animacion
Para crear formas en en los canvas usamos los metodos de canvas o hacemos el llamando a funciones personalizadas. En un caso normal, nosostros solo vemos que el resultado aparece cuando el el script se ha ejecutado. Por ejemplo, no es posible hacer una animacion desde un bucle for.
Esto significa que necesitamos una manera de ejecutar nuestras funciones de dibujo en un período de tiempo. Hay 2 formas para controlar una animacion como esta.
Actualizaciones Programadas
Primero window.setInterval()
, window.setTimeout()
, y window.requestAnimationFrame()
son funciones que pueden ser usadas para llamar una funcion especifica en un periodo de tiempo establecido.
setInterval(function, delay)
- Ejecuta una funcion especificada por
function
cadadelay
milisegundos. setTimeout(function, delay)
- Ejecuta una funcion especificada por
function
dentro dedelay
milisegundos. requestAnimationFrame(callback)
- Comunica al navegador que deseas iniciar una animacion y requieres que el navegador llame a las funciones especificas para actualizar la misma antes de la siguiente escena.
Si no quieres ninguna interaccion del usuario puedes usar la funcion setInterval()
que repite la ejecucion del codigo suminsitrado. Si lo que queremos es hacer un juego, nosotros usariamos los eventos del mouse o el teclado para controlar la animacion y usariamos setTimeout()
. Al establecer los EventListener
, capturamos cualquier interaccion del usuario y ejecutamos nuestras funciones de animacion.
En los siguiente ejemplo,usaremos el metodo para controlar animaciones window.requestAnimationFrame()
. El metodo requestAnimationFrame
provee formas amigables y mas eficientes para animar llamando cada marco de animacion cuando el sistema esta listo para dibujar. Las retrollamadas son usualmente 60 veces por segundo y podria ser reducido a menor periodo cuando se corre en un segundo plano. Para mas informacion acerca de los ciclos de animacion, especialmente para juegos, Ver el Articulo Anatomia de un video juego en nuestra GameZona de desarrollo de Juegos.
Un sistema solar animado
Este ejemplo animado es un pequeño modelo de nuestro sistema solar
var sun = new Image(); var moon = new Image(); var earth = new Image(); function init(){ sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png'; moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png'; earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png'; window.requestAnimationFrame(draw); } function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.globalCompositeOperation = 'destination-over'; ctx.clearRect(0,0,300,300); // clear canvas ctx.fillStyle = 'rgba(0,0,0,0.4)'; ctx.strokeStyle = 'rgba(0,153,255,0.4)'; ctx.save(); ctx.translate(150,150); // La tierra var time = new Date(); ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() ); ctx.translate(105,0); ctx.fillRect(0,-12,50,24); // Shadow ctx.drawImage(earth,-12,-12); // La luna ctx.save(); ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() ); ctx.translate(0,28.5); ctx.drawImage(moon,-3.5,-3.5); ctx.restore(); ctx.restore(); ctx.beginPath(); ctx.arc(150,150,105,0,Math.PI*2,false); // Earth orbit ctx.stroke(); ctx.drawImage(sun,0,0,300,300); window.requestAnimationFrame(draw); } init();
<canvas id="canvas" width="300" height="300"></canvas>
Screenshot | Live sample |
---|---|
Un reloj animado
Este ejemplo dibuja una reloj animado, mostrando la hora actual.
function clock(){ var now = new Date(); var ctx = document.getElementById('canvas').getContext('2d'); ctx.save(); ctx.clearRect(0,0,150,150); ctx.translate(75,75); ctx.scale(0.4,0.4); ctx.rotate(-Math.PI/2); ctx.strokeStyle = "black"; ctx.fillStyle = "white"; ctx.lineWidth = 8; ctx.lineCap = "round"; // Aguja de la hora ctx.save(); for (var i=0;i<12;i++){ ctx.beginPath(); ctx.rotate(Math.PI/6); ctx.moveTo(100,0); ctx.lineTo(120,0); ctx.stroke(); } ctx.restore(); // Aguja del minuto ctx.save(); ctx.lineWidth = 5; for (i=0;i<60;i++){ if (i%5!=0) { ctx.beginPath(); ctx.moveTo(117,0); ctx.lineTo(120,0); ctx.stroke(); } ctx.rotate(Math.PI/30); } ctx.restore(); var sec = now.getSeconds(); var min = now.getMinutes(); var hr = now.getHours(); hr = hr>=12 ? hr-12 : hr; ctx.fillStyle = "black"; // Escribimos la hora ctx.save(); ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec ) ctx.lineWidth = 14; ctx.beginPath(); ctx.moveTo(-20,0); ctx.lineTo(80,0); ctx.stroke(); ctx.restore(); // escribimos los minutos ctx.save(); ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec ) ctx.lineWidth = 10; ctx.beginPath(); ctx.moveTo(-28,0); ctx.lineTo(112,0); ctx.stroke(); ctx.restore(); // escribimos los segundos ctx.save(); ctx.rotate(sec * Math.PI/30); ctx.strokeStyle = "#D40000"; ctx.fillStyle = "#D40000"; ctx.lineWidth = 6; ctx.beginPath(); ctx.moveTo(-30,0); ctx.lineTo(83,0); ctx.stroke(); ctx.beginPath(); ctx.arc(0,0,10,0,Math.PI*2,true); ctx.fill(); ctx.beginPath(); ctx.arc(95,0,10,0,Math.PI*2,true); ctx.stroke(); ctx.fillStyle = "rgba(0,0,0,0)"; ctx.arc(0,0,3,0,Math.PI*2,true); ctx.fill(); ctx.restore(); ctx.beginPath(); ctx.lineWidth = 14; ctx.strokeStyle = '#325FA2'; ctx.arc(0,0,142,0,Math.PI*2,true); ctx.stroke(); ctx.restore(); window.requestAnimationFrame(clock); } window.requestAnimationFrame(clock);
<canvas id="canvas" width="150" height="150"></canvas>
Screenshot | Live sample |
---|---|
Un ciclo Panoramico
En este ejemplo, una foto panoramica avanza de izquierda a derecha. Donde usaremos una imagen del Parque Nacional de Yosemite que tomamos de Wikipedia, pero tu podrias usar cualquier imagen que sea mas grande que el canva.
var img = new Image(); // Variables de usuario - personalizamos estas para cambiar la imagen cuando inicie el desplazamiento // direccion y velocidad. img.src = 'https://mdn.mozillademos.org/files/4553/Capitan_Meadows,_Yosemite_National_Park.jpg'; var CanvasXSize = 800; var CanvasYSize = 200; var speed = 30; //lower is faster var scale = 1.05; var y = -4.5; //vertical offset // Program Base var dx = 0.75; var imgW; var imgH; var x = 0; var clearX; var clearY; var ctx; img.onload = function() { imgW = img.width*scale; imgH = img.height*scale; if (imgW > CanvasXSize) { x = CanvasXSize-imgW; } // image larger than canvas if (imgW > CanvasXSize) { clearX = imgW; } // image larger than canvas else { clearX = CanvasXSize; } if (imgH > CanvasYSize) { clearY = imgH; } // image larger than canvas else { clearY = CanvasYSize; } //Obtenemos el elemento canva ctx = document.getElementById('canvas').getContext('2d'); //Establecemos la tasa de repeticiones return setInterval(draw, speed); } function draw() { //Limpiamos los Canvas ctx.clearRect(0,0,clearX,clearY); //If image is <= Canvas Size if (imgW <= CanvasXSize) { //reseteamos, iniciamos desde el principio if (x > (CanvasXSize)) { x = 0; } //dibujamos una imagen adicional if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-CanvasXSize+1,y,imgW,imgH); } } //Si la imagen es > tamaño del Canvas else { //reseteamos, iniciamos desde el principio if (x > (CanvasXSize)) { x = CanvasXSize-imgW; } //dibujamos una imagen adicional if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-imgW+1,y,imgW,imgH); } } //Dibujamos la imagen ctx.drawImage(img,x,y,imgW,imgH); //aumentamos al movimiento x += dx; }
Debajo esta el elemento <canvas>
en el cual va la imagen se va ha desplazar. Nota que el ancho y el alto especificado aqui son las variables CanvasXZSize
y CanvasYSize
.
<canvas id="canvas" width="800" height="200"></canvas>
Other examples
- Un lanzador de rayos basico
- Un buen ejemplo de como hacer animaciones usando como control el teclado
- Animaciones avanzadas
- Vamos a echar un vistazo a algunas técnicas de animación avanzadas y la física en el próximo capítulo.