Interactividad

Como bien deben suponer, además de presentar visualizaciones animadas, también es posible generar interacción con el usuario, ya sea en forma de herramientas, juegos, ads publicitarios, etc.

Para estos casos se puede re-renderizar en la acción del usuario o continuar con el intervalo según se necesite. Un ejemplo básico de interacción con el mouse, en el cual el re-renderizado se ejecuta en el click del usuario.

Como en el ejemplo del artículo anterior, comenzamos creando el canvas:

<canvas id="canvas" width="300" height="300">

Nuevamente le damos algo de visibilidad:

canvas {
    background: #ccc;
}

Y finalmente lo importante, el código. Para este ejemplo vamos a dibujar circulos rojos al clickear, utilizando las coordenadas provistas por el evento en cuestión.

// Nuestras variables
var canvas, ctx;

// Obtenemos una referencia al canvas
canvas = document.getElementById('canvas');

// Y a su "contexto 2d"
ctx = canvas.getContext('2d');

// Hoy pintamos de rojo
ctx.fillStyle = "#f00";

// Creamos el listener
canvas.addEventListener('click', function(ev) {
    // Borramos
    ctx.clearRect(0, 0, 300, 300);

    // Reseteamos los paths
    ctx.beginPath();  

    // Creamos el circulo
    ctx.arc(ev.clientX, ev.clientY, 25, 0, Math.PI * 2, true);  

    // Y rellenamos
    ctx.fill();
}, false);

Y finalmente, el ejemplo en acción:

Otro ejemplo, utilizando una composición de canvas, en este caso dos canvas superpuestos, siendo uno para el escenario generado y otro para el “personaje”.

Para este caso, el escenario se genera una única vez en un canvas propio, dejando la animación e interactividad para el canvas en el que se dibuja el personaje.

Sumando complejidad, aprovechando el vídeo HTML5

En ejemplos anteriores generamos gráficos (bastantes precarios) y utilizamos imágenes. El elemento vídeo nos permite disponer prácticamente de cada frame, por lo que las posiblidades de generar animaciones basadas en vídeo son prácticamente infinitas.

El método context.drawImage acepta como primer argumento una referencia al elemento vídeo, dibujando el frame actual en el canvas. Este proceso repetido ciclicamente da como resultado la animación en cuestión.

Para manipular el vídeo basta con capturar el frame actual para luego alterarlo, ya sea agregando componentes (imágenes u objetos) así como también manipulando sus pixels de manera individual. Esta última técnica, permite generar resultados muy vistosos con muy poco código, tal como puede verse en un artículo que he desarrollado previamente (o en este gran artículo de Stoyan Stefanov).

Este es un pequeño ejemplo de como se pueden lograr sorprendentes resultados con muy poco código (requiere browsers modernos):

*El código fuente (comentado) de este ejemplo puede encontrarse en este gist.

Sobre el framerate

Como mencionamos anteriormente, el framerate es la frecuencia con la cual se redibujan las imágenes en una secuencia animada. En principio, hay que considerar que el framerate “aceptable” variará de acuerdo a lo que se esté animando, objetos de rápido movimiento requerirán un alto framerate para evitar cualquier tipo de “desprolijidad” en el movimiento.

Luego, hay que considerar la forma en la que calculamos la posición/estado de la animación. En su versión simplificada (la que se utilizó hasta ahora en los ejemplos) simplemente contamos el frame actual y actuamos en consecuencia, aunque si quisiéramos hacer un juego/animación algo más serio, tendría mas sentido separar el renderizado del resto de la lógica, a fines de evitar que la experiencia de usuario se vea demasiado afectada por la capacidad de computo de su computadora/mobile/etc (siendo que no solo el renderizado será lento, sino también la interacción).

Afortunadamente, HTML5 nos provee de un API (window.requestAnimationFrame y familiares) que brinda algunos beneficios adicionales sobre el setInterval/setTimeout, como ser gestión inteligente (detiene el loop al cambiar de tab), mayor precisión de tiempo y lo mejor de todo, consumo de recursos optimizado (sincroniza los repaints para evitar procesamiento adicional).

La gente de Microsoft hizo un excelente artículo (con una gran demo incluida), donde se pueden apreciar las ventajas que ofrece este método en términos de performance.


Microsoft requestAnimationFrame demo

En la documentación de Mozilla, podemos encontrar mayor información sobre este método. Por otro lado, Paul Irish ofrece un ligero polyfill en su blog, entrada en la cual además, podemos encontrar recursos adicionales para seguir indagando sobre esta API.

Se supone que en un futuro, esta API nos permita definir el framerate a utilizar (actualmente ronda los 60fps), con lo cual las alternativas de setTimeout/setInterval quedarían completamente obsoletas.

Consideraciones sobre performance

Hay que tener en cuenta, a la hora de realizar animaciones en canvas, el costo que puede implicar. Este aspecto es importante tenerlo en cuenta, ya que puede limitar la experiencia de usuario a un grupo muy reducido.

Por ejemplo, consideremos que clase de computadora/dispositivo tiene el común de la gente. En StatCounter podemos observar, que a la fecha (Junio 2012) en el mundo, la resolución 1024×768 tiene un marketshare de casi el 20% (y más si reducimos la búsqueda a América Latina).

No es difícil imaginar que clase de computadora/tablet puede acompañar semejante resolución, por lo cual siempre debemos sopesar el resultado final contra el costo de cómputo que pueda tener, más para desarrollos que se supongan “masivos” y no experimentales, como suele suceder en la gran mayoría de las demos presentadas.

En caso de necesitar optimizar, está disponible un excelente artículo en el portal html5rocks, que trata específicamente sobre técnicas de optimización para animaciones en canvas, entre las cuales podemos destacar el pre-rendering, la composición de canvases (utilizado en uno de los ejemplos), etc.

Conclusiones

Como habrán visto, realizar animaciones sencillas no requiere de excesivo conocimiento técnico ni cantidades industriales de código, siendo posible (y hasta recomendable en algunos casos) evitar el uso de librerías/frameworks.

Para el caso de desarrollos más complejos, el uso de estas librerías/frameworks permite reducir los costos y tiempos de desarollo delegando los problemas de ‘bajo nivel’ a sus respectivos autores. En cada uno de los websites se pueden encontrar algunos (impresionantes) ejemplos.

ATENCIÓN: Algunas de las librerías aquí mencionadas pueden utilizar algún lenguaje de programación intermedio y/o sintaxis no nativa.

Algunas librerías que pueden servirnos para esta tarea son:

Para desarrollo de juegos podemos encontrar algunas librerías que no solo nos facilitan el renderizado, sino también complicaciones clásicas como detección de colisiones y física:

Referencias de Canvas

Para las personas interesadas en ahondar conocimientos sobre el tema (que ciertamente es extenso en literatura), les recomiendo las siguientes lecturas y sitios:

Demos

  • Canvas Demos | Demos, demos y más demos utilizando canvas. Excelente recurso para obtener inspiración.

Tutoriales

Performance

Recursos