Animaciones en el Lienzo en HTML

Las animaciones en el lienzo en HTML son creadas por código JavaScript convencional. En este sentido, no existen métodos para ayudarnos a animar figuras en el lienzo, y tampoco existe un procedimiento predeterminado para hacerlo. Básicamente, debemos borrar el área del lienzo que queremos animar, dibujar las figuras y repetir el proceso una y otra vez. Por supuesto, una vez que las figuras son dibujadas, estas no se pueden mover.

De hecho, solo borrando el área y dibujando las figuras nuevamente podemos construir una animación. Por esta razón, en juegos o aplicaciones que requieren grandes cantidades de objetos a ser animados, es mejor usar imágenes en lugar de figuras construidas con trazados complejos. (Por ejemplo, los juegos normalmente utilizan imágenes en formato PNG, que, además, son útiles dada su capacidad de transparencia).

Además, existen múltiples técnicas para lograr animaciones en el mundo de la programación. De esta manera, algunas son simples y otras tan complejas como las aplicaciones para las que fueron creadas.

A continuación, vamos a ver un ejemplo simple utilizando el método clearRect() para limpiar el lienzo y dibujar nuevamente, generando una animación con solo una función. Sin embargo, no olvide que, si su intención es crear elaborados efectos, probablemente deberá adquirir un libro de programación avanzada en JavaScript previamente.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
window.addEventListener('mousemove', animacion, false);
}
function animacion(e){
lienzo.clearRect(0,0,300,500);
var xraton=e.clientX;
var yraton=e.clientY;
var xcentro=220;
var ycentro=150;
var angulo=Math.atan2(xraton-xcentro,yraton-ycentro);
var x=xcentro+Math.round(Math.sin(angulo)*10);
var y=ycentro+Math.round(Math.cos(angulo)*10);
lienzo.beginPath();
lienzo.arc(xcentro,ycentro,20,0,Math.PI*2, false);
lienzo.moveTo(xcentro+70,150);
lienzo.arc(xcentro+50,150,20,0,Math.PI*2, false);
lienzo.stroke();
lienzo.beginPath();
lienzo.moveTo(x+10,y);
lienzo.arc(x,y,10,0,Math.PI*2, false);
lienzo.moveTo(x+60,y);
lienzo.arc(x+50,y,10,0,Math.PI*2, false);
lienzo.fill();
}
window.addEventListener("load", iniciar, false);

Muestra de códigos

El código mostrará dos ojos en pantalla que miran al puntero del ratón todo el tiempo. En tal sentido, para mover los ojos, debemos actualizar su posición cada vez que el ratón es movido. Por este motivo, agregamos una escucha para el evento mousemove en la función iniciar(). Cada vez que el puntero del ratón cambia de posición, el evento es disparado y la función animacion() es llamada.

La función animacion() comienza limpiando el lienzo con la instrucción clearRect(0,0,300,500). Luego, la posición del puntero del ratón es capturada (usando las viejas propiedades clientX y clientY) y la posición del primer ojo es grabada en las variables xcentro e ycentro.

Luego de que estas variables son inicializadas, es tiempo de comenzar con las matemáticas. Así, usando los valores de la posición del ratón y el centro del ojo izquierdo, calculamos el ángulo de la línea invisible que va desde un punto al otro usando el método predefinido atan2.

Subsiguientemente, este ángulo es usado en el siguiente paso para calcular el punto exacto del centro del iris del ojo izquierdo con la fórmula xcentro + Math.round(Math.sin(angulo) × 10). El número 10 en la fórmula representa la distancia desde el centro del ojo al centro del iris (porque el iris no está en el centro del ojo, está siempre sobre el borde).

Uso de los valores

Ahora mismo, con todos estos valores ya podemos finalmente comenzar a dibujar nuestros ojos en el lienzo. El primer trazado es para los dos círculos representando los ojos. El primer método arc() para el primer ojo es posicionado en los valores xcentro y ycentro, y el círculo para el segundo ojo es generado 50 píxeles hacia la derecha usando la instrucción arc(xcentro+50, 150, 20, 0, Math.PI*2, false).

La parte animada del gráfico es creada a continuación con el segundo trazado. Este trazado usa las variables x e y con la posición calculada previamente a partir del ángulo. Ambos iris son dibujados como un círculo negro sólido usando fill().

El proceso será repetido y los valores recalculados cada vez que el evento mousemove es disparado.

Animaciones en el Lienzo en HTML: Procesado de video

Al igual que para animaciones, no hay ningún método especial para mostrar video en el elemento < canvas >. La única manera de hacerlo es tomando cada cuadro del video desde el elemento < video > y dibujarlo como una imagen en el lienzo usando drawImage(). Así que básicamente, el procesamiento de video en el lienzo es hecho con la combinación de técnicas ya estudiadas.

Construyamos una nueva plantilla y los códigos para ver de qué estamos hablando.

<!DOCTYPE html>
<html lang="es">
<head>
<title>Video en el Lienzo</title>
<style>
.cajas{
display: inline-block;
margin: 10px;
padding: 5px;
border: 1px solid #999999;
}
</style>
<script src="canvasvideo.js"></script>
</head>
<body>
<section class="cajas">
<video id="medio" width="483" height="272">
<source src="http://www.minkbooks.com/content/trailer2.mp4">
<source src="http://www.minkbooks.com/content/trailer2.ogg">
</video>
</section>
<section class="cajas">
<canvas id="lienzo" width="483" height="272">
Su navegador no soporta el elemento canvas
</canvas>
</section>
</body>
</html>

La plantilla en el Listado 7-28 incluye dos componentes específicos: el elemento < video > y el elemento < canvas >. Con la combinación de ambos vamos a procesar y mostrar video en el lienzo.

La plantilla también incluye estilos CSS embebidos para las cajas y un archivo JavaScript llamado canvasvideo.js para el siguiente código:

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
video=document.getElementById('medio');
video.addEventListener('click', presionar, false);
}
function presionar(){
if(!video.paused && !video.ended){
video.pause();
window.clearInterval(bucle);
}else{
video.play();
bucle=setInterval(procesarCuadros, 33);
}
}
function procesarCuadros(){
lienzo.drawImage(video,0,0);
var info=lienzo.getImageData(0,0,483,272);
var pos;
var gris;
for(x=0;x<=483;x++){
for(y=0;y<=272;y++){
pos=(info.width*4*y)+(x*4);
gris=parseInt(info.data[pos]*0.2989 +
info.data[pos+1]*0.5870 + info.data[pos+2]*0.1140);
info.data[pos]=gris;
info.data[pos+1]=gris;
info.data[pos+2]=gris;
}
}
lienzo.putImageData(info,0,0);
}
window.addEventListener("load", iniciar, false);

IMPORTANTE

Este ejemplo usa los métodos getImageData() y putImageData() para procesar datos de imagen. Como explicamos anteriormente, estos métodos extraen información del lienzo. Debido a restricciones de seguridad, la extracción de información desde el lienzo es desactivada luego de que el elemento recibe contenido desde un origen que no es el origen del documento que lo creó (el documento pertenece a un dominio y el video a otro).

Por lo tanto, para probar este ejemplo, deberá descargar el video desde nuestro sitio web (o usar el suyo propio) y luego subir cada uno de los archivos a su servidor.

Estudio del código

Estudiemos por un momento el código del Listado 7-29. Como dijimos previamente, para procesar video en el lienzo, simplemente debemos recurrir a códigos y técnicas ya vistas. En este código estamos usando la función presionar() tomada del Capítulo 5 para comenzar y detener la reproducción del video haciendo clic sobre el mismo.

También creamos una función llamada procesarCuadros() que está usando el mismo código del Listado 7-25 de este capítulo, excepto que esta vez en lugar de invertir la imagen estamos usando una fórmula para transformar todos los colores de cada cuadro del video en el correspondiente gris. Esto convertirá nuestro video color en un video blanco y negro.

La función presionar() cumple con dos propósitos:

  • Comenzar o detener la reproducción del video
  • Iniciar un intervalo que ejecutará la función procesarCuadros() cada 33 milisegundos.

Esta función toma un cuadro del elemento < video > y lo dibuja en el lienzo con la instrucción drawImage(video,0,0). Luego los datos se extraen del lienzo con el método getImageData() y cada pixel de ese cuadro se procesa por medio de dos bucles for (como lo hicimos en un ejemplo anterior).

El proceso a utilizar para convertir cada uno de los colores que integran cada píxel en su correspondiente gris es uno de los más populares y fáciles de encontrar en Internet. La fórmula es la siguiente:

rojo × 0.2989 + verde × 0.5870 + azul × 0.1140

Luego de que la fórmula se calcula, el resultado debe ser asignado a cada color del píxel (rojo, verde y azul), como lo hicimos en el ejemplo usando la variable gris. El proceso termina cuando dibujamos nuevamente el cuadro modificado en el lienzo usando el método putImageData().

Referencia rápida

La API Canvas es probablemente la más compleja y extensa de todas las APIs incluidas dentro de la especificación HTML5. Provee varios métodos y propiedades para crear aplicaciones gráficas sobre el elemento < canvas >.

Métodos

Estos métodos son específicos de la API Canvas:

  • getContext(contexto)

Este método crea el contexto para el lienzo. Puede tomar dos valores: 2d y 3d para gráficos en 2 y 3 dimensiones.

  • fillRect(x, y, ancho, alto)

Dicho método dibujará un rectángulo sólido directamente en el lienzo en la posición indicada por x,y y el tamaño ancho,alto.

  • strokeRect(x, y, ancho, alto)

Este método dibujará un rectángulo vacío (solo el contorno) directamente en el lienzo en la posición que se indica por x,y y el tamaño ancho,alto.

  • clearRect(x, y, ancho, alto)

Dicho método borra un área en el lienzo usando una figura rectangular que se declara por los valores de sus atributos.

  • createLinearGradient(x1, y1, x2, y2)

Este método crea un gradiente lineal para asignarlo a una figura como si fuese un color usando la propiedad fillStyle. Sus atributos solo especifican las posiciones de comienzo y final del gradiente (relativas al lienzo). Para declarar los colores que se involucran en el gradiente, este método debe usarse en combinación con addColorStop().

  • createRadialGradient(x1, y1, r1, x2, y2, r2)

Dicho método crea un gradiente radial para asignarlo a una figura como si fuese un color usando la propiedad fillStyle. El gradiente es construido por medio de dos círculos. Los atributos solo especifican la posición y radio de los círculos (relativos al lienzo). Para declarar los colores involucrados en el gradiente, este método debe ser usado en combinación con addColorStop().

  • addColorStop(posición, color)

Este método es usado para declarar los colores para el gradiente. El atributo posición es un valor entre 0.0 y 1.0, usado para determinar dónde el color comenzará la degradación.

  • beginPath()

Este método es requerido para comenzar un nuevo trazado.

  • closePath()

Dicho método puede ser usado al final de un trazado para cerrarlo. Generará una línea recta desde la última posición del lápiz hasta el punto donde el trazado comenzó. No es necesario usar este método cuando el trazado debe permanecer abierto o es dibujado en el lienzo usando fill().

  • stroke()

Este método es usado para dibujar un trazado como una figura vacía (solo el contorno).

  • fill()

Este método es usado para dibujar un trazado como una figura sólida.

  • clip()

Dicho método es usado para crear una máscara a partir de un trazado. Todo lo que sea enviado al lienzo luego de que este método es declarado será dibujado sólo si cae dentro de la máscara.

  • moveTo(x, y)

Este método mueve el lápiz virtual a una nueva posición para continuar el trazado desde ese punto.

  • lineTo(x, y)

Este método agrega líneas rectas al trazado desde la posición actual del lápiz hasta el punto indicado por los atributos x e y.

  • rect(x, y, ancho, alto)

Dicho método agrega un rectángulo al trazado en la posición x,y y con un tamaño determinado por ancho, alto.

  • arc(x, y, radio, ángulo inicio, ángulo final, dirección)

Este método agrega un arco al trazado. El centro del arco es determinado por x e y, los ángulos son definidos en radianes, y la dirección es un valor booleano para determinar si el arco será dibujado en el mismo sentido o el opuesto a las agujas del reloj.

  • quadraticCurveTo(cpx, cpy, x, y)

Este método agrega una curva Bézier cuadrática al trazado. Comienza desde la posición actual del lápiz y termina en el punto x,y. Los atributos cpx y cpy especifican la posición del punto de control que dará forma a la curva.

  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

Dicho método agrega una curva Bézier cúbica al trazado. Comienza desde la posición actual del lápiz y termina en el punto x,y. Los atributos cp1x, cp1y, cp2x, y cp2y especifican la posición de los dos puntos de control que darán forma a la curva.

  • strokeText(texto, x, y, máximo)

Este método dibuja un texto vacío (solo el contorno) directamente en el lienzo. El atributo máximo es opcional y determina el máximo tamaño del texto en píxeles.

  • fillText(texto, x, y, máximo)

Este método dibuja un texto sólido directamente en el lienzo. El atributo máximo es opcional y determina el máximo tamaño del texto en píxeles.

  • measureText(texto)

Dicho método calcula el tamaño del área que un texto ocupará en el lienzo usando los estilos vigentes. La propiedad width es usada para retornar el valor.

  • translate(x, y)

Este método mueve el origen del lienzo al punto x,y. La posición inicial del origen (0,0) es la esquina superior izquierda del área generada por el elemento < canvas >.

  • rotate(angle)

Este método es usado para rotar el lienzo alrededor del origen. El ángulo debe ser declarado en radianes. Para convertir grados en radianes, use la fórmula:

Math.PI / 180 × grados

  • scale(x, y)

Dicho método cambia la escala del lienzo. Los valores por defecto son (1.0, 1.0). Los valores provistos pueden ser negativos.

  • transform(m1, m2, m3, m4, dx, dy)

Este método modifica la matriz de transformación del lienzo. La nueva matriz se calcula sobre la anterior.

  • setTransform(m1, m2, m3, m4, dx, dy)

Este método modifica la matriz de transformación del lienzo. Reinicia los valores anteriores y declara los nuevos.

  • save()

Dicho método graba el estado del lienzo, incluyendo la matriz de transformación, propiedades de estilo y la máscara.

  • restore()

Este método restaura el último estado del lienzo grabado, incluyendo la matriz de transformación, propiedades de estilo y la máscara.

  • drawImage()

Este método dibujará una imagen en el lienzo. A este respecto, existen tres sintaxis posibles:

– La sintaxis drawImage(imagen,x,y), que dibuja la imagen en la posición x,y.

– La sintaxis drawImage(imagen,x,y,ancho,alto), la cualdibuja la imagen en la posición x,y con un nuevo tamaño declarado por ancho,alto.

– Y la sintaxis drawImage(imagen, x1, y1, ancho1, alto1, x2, y2, ancho2, alto2), la cual toma una porción de la imagen original. Esta imagen está determinada por x1,y1,ancho1,alto1 y la dibuja en el lienzo en la posición x2,y2 y el nuevo tamaño ancho2,alto2.

  • getImageData(x, y, ancho, alto)

Dicho método toma una porción del lienzo y la graba como datos en un objeto. Los valores del objeto son accesibles a través de las propiedades width, height y data. A su vez, las primeras dos propiedades retornan el tamaño de la porción de la imagen tomada, y data retorna la información como un array con valores representando los colores de cada píxel. Este valor puede accederse usando la fórmula (ancho×4×y)+(x×4).

  • putImageData(datosImagen, x, y)

Este método dibuja en el lienzo la imagen representada por la información en datosImagen.

  • createImageData(ancho, alto)

Este método crea una nueva imagen en formato de datos. Todos los píxeles se inicializan en color negro transparente. Puede tomar datos de imagen como atributo en lugar de ancho y alto. En este caso la nueva imagen tendrá el tamaño determinado por los datos provistos.

  • createPattern(imagen, tipo)

Dicho método crea un patrón desde una imagen que luego podrá asignarse a una figura usando la propiedad fillStyle. Los valores posibles para el atributo tipo son repeat, repeat-x, repeat-y y no-repeat.

Propiedades (específicas para API Canvas)

  • strokeStyle

Esta propiedad declara el color para las líneas de las figuras. Puede recibir cualquier valor CSS, incluidas funciones como rgb() y rgba().

  • fillStyle

Esta propiedad declara el color para el interior de figuras sólidas. Puede recibir cualquier valor CSS, incluidas funciones como rgb() y rgba(). También se usa para asignar gradientes y patrones a figuras. (Estos estilos se asignan primero a una variable y luego esa variable se declara como el valor de esta propiedad).

  • globalAlpha

Esta propiedad se usa para determinar el nivel de transparencia de las figuras. Recibe valores entre 0.0 (completamente opaco) y 1.0 (completamente transparente).

  • lineWidth

Esta propiedad especifica el grosor de la línea. Esta, por defecto, tiene un valor de 1.0.

  • lineCap 

Determina la forma de la terminación de las líneas. Adicionalmente, se pueden utilizar tres valores: butt (terminación normal), round (termina la línea con un semicírculo) y square (termina la línea con un cuadrado).

  • lineJoin

Esta propiedad determina la forma de la conexión entre líneas. Se pueden utilizar tres valores: round (la unión es redondeada), bevel (la unión es cortada) y miter (la unión se extiende hasta que ambas líneas alcanzan un punto en común).

  • miterLimit

Esta propiedad determina cuánto se extenderán las líneas cuando la propiedad lineJoin se declara como miter.

  • font

Dicha propiedad es similar a la propiedad font de CSS y utiliza la misma sintaxis para declarar los estilos del texto.

  • textAlign

Esta propiedad determina cómo el texto se alineará. Los posibles valores son start, end, left, right y center.

  • textBaseline

Esta propiedad determina el alineamiento vertical para el texto. Los posibles valores son: top, hanging, middle, alphabetic, ideographic y bottom.

  • shadowColor

Esta propiedad establece el color para la sombra. Utiliza valores CSS.

  • shadowOffsetX

Esta propiedad declara la distancia horizontal entre la sombra y el objeto.

https://aprendeinformaticas.com/

https://www.facebook.com/aprendeinformaticas/