Dibujando en CANVAS – HTML5
Canvas de HTML5 es simplemente un TAG, un contenedor en donde vamos a dibujar ya sea desde líneas, cuadrados y círculos hasta imágenes y texto. Aparte de tener el poder de dibujar tenemos otra ventaja … no utilizamos el DOM, es decir, si tuviéramos que realizar lo mismo con divs, spans, etc. por cada elemento vamos a estar utilizando el DOM y re-flows del explorador, pero dentro de canvas no se va a crear un elemento DOM para lo que dibujemos (ojo que al no tener DOM tampoco tenemos eventos como mouseover, click, etc. por cada elemento que dibujemos, pero si por todo el tag canvas).
Compatibilidad
Hay que tener en cuenta que al ser HTML 5 no va a funcionar en cualquier explorador viejo:
Si necesitamos que funcione en IE, hay algunas opciones para lograr el soporte, les dejo la de Google: Explore Canvas
Configurando
<canvas id="miCanvas" width="145px" height="145px">
<span>Tu explorador es anciano, renovalo si queres ver la magia</span>
</canvas>
Tan simple como eso, agregamos al html el tag *
Si no asignamos el width o height, por default cada uno es 160px.
El contenido dentro de los tags se va a mostrar si el explorador desconoce lo que significa el tag canvas (tambien se puede poner html, no solo texto).
Para comenzar a dibujar obtenemos el contexto del canvas en javascript:
var canvas = document.getElementById('miCanvas');
var contexto = canvas.getContext('2d');
Dibujando
Para hacerlo más divertido, vamos a recrear el logo de FernetJS en canvas:
Comencemos por dibujar el cuadrado amarillo del fondo:
var canvas = document.getElementById('miCanvas');
var contexto = canvas.getContext('2d');
// le damos un color de llenado al contexto
contexto.fillStyle = '#F0DB4F';
// dibujamos un cuadrado con el color de llenado
contexto.fillRect(0, 10, 145, 145); // fillRect(x, y, largo, alto)
// le damos al contexto un tamaño y color de linea
contexto.lineWidth = 3;
contexto.strokeStyle = 'black';
// dibujamos un cuadrado pero solo de contorno
contexto.strokeRect(1, 10, 143, 134); // strokeRect(x, y, largo, alto)
Ahora dibujemos el ‘JS’, lo voy a escribir en el canvas para mostrarles que se puede, pero el método que voy a utilizar de dibujar texto tiene graves problemas de performance, es preferible hacer una imagen o una imagen por letra y dibujar la/s imagen/es (como en los viejos, pero muy viejos tiempos).
// cambiamos el color de llenado del contexto
contexto.fillStyle = '#333';
// asignamos al contexto el tipo de letra, tamaño y posicion inicial
contexto.font = 'bold 64px sans-serif';
contexto.textBaseline = 'top';
// dibujamos el texto
contexto.fillText('JS', 2, 5); // fillText(texto, x, y);
Como se darán cuenta a esta altura, el contexto tiene propiedades que son aplicadas al momento de dibujar un elemento. Por ejemplo contexto.fillStyle, ese valor lo podríamos asignar al principio de un set de dibujos y todos van a ser aplicados con el mismo color de fondo. Esto pasa con varias propiedades, .font, .strokeStyle, .lineWidth, etc.
Pero qué pasa si tenemos el siguiente escenario?:
- Seteo un estilo
- Dibujo con ese estilo
- Seteo otro estilo
- Dibujo con el nuevo estilo
- Necesito el primer estilo para dibujar algo nuevo
En el último paso deberíamos volver a ejecutar el código (repetirnos) para setearle al contexto el estilo que teníamos antes. Bueno, hay dos funciones que nos ayudan en eso:
contexto.fillStyle = 'blue';
contexto.fillRect(10, 10, 10, 10); // Dibujo cuadrado azul
contexto.save(); //Guardo el fillStyle = 'blue'
contexto.fillStyle = 'red'; // Lo cambio a rojo
contexto.fillRect(20, 20, 10, 10); // Dibujo cuadrado rojo
contexto.restore(); //Recupero el fillStyle = 'blue'
contexto.fillRect(30, 30, 10, 10); // Dibujo cuadrado azul
Con las functiones .save() y .restore() podemos guardar y recuperar configuraciones de nuestro contexto y sí, se pueden anidar, es decir con 2 veces .save() y 2 veces .restore() vuelvo al primer estado.
Volviendo con el dibujo del logo, vamos a estirar la palabra JS, pero para esto vamos a tener que escalar el contexto y en este momento sería útil guardar la configuración de contexto actual, así que vamos a editar donde dibujamos la palabra:
// me guardo la configuración de contexto actual
contexto.save();
// escalo el contexto (amplío)
contexto.scale(1.8, 2.4); //.scale(ancho, alto)
// dibujo la palabra JS, pero ahora con la escala
contexto.fillStyle = '#333';
contexto.font = 'bold 64px sans-serif';
contexto.textBaseline = 'top';
contexto.fillText('JS', 2, 5);
// recupero la configuracion del contexto guardada con .save()
contexto.restore();
De esta forma continuamos dibujando después del .restore() y la configuración del contexto que aplicamos para la palabra JS se eliminó.
Ahora vamos a dibujar la imagen del vaso en el canvas, esta es nuestra imagen:
var vaso = new Image();
vaso.onload = function() {
//.drawImage(imagen, x, y);
contexto.drawImage(vaso, 0, 0);
};
vaso.src = "[URL DE LA IMAGEN]";
Primero creamos un objeto Image() de javascript, que es básicamente DOM, como lo genera el explorador cuando agregamos un tag en el HTML. Luego me suscribo al evento onload para asegurarme que la imagen esté cargada antes de dibujarla en el canvas.
La función .drawImage() tiene muchas “sobrecargas”, use las más simple de todas.
El parámetro de imagen también puede recibir una imagen embebida del tipo: ‘data:image/gif;base64,R0lGODlhCwA …’, lo cual nos viene genial ya que no necesitamos esperar a que se descargue porque al ser texto ya lo bajamos junto con el archivo js.
Lo último que nos quedaría es dibujar las líneas para enfatizar el vaso. Esas líneas las podemos pensar como triángulos, y para dibujarlos tenemos que armar un path:
// seteo el estilo de llenado del contexto a negro.
contexto.fillStyle = 'black';
// comienzo un path
contexto.beginPath();
// muevo el puntero para empezar en (80,25)
contexto.moveTo(80,25); // [1] en la imagen
// dibujo una línea hasta (115,10)
contexto.lineTo(115,10); // [2] en la imagen
// dibujo otra línea desde el último punto hasta (125,10)
contexto.lineTo(125,10); // [3] en la imagen
// cierro el path, lo cual genera la última línea
contexto.closePath();
// lleno el path con el color negro
contexto.fill();
Bastante bien, no?, bueno después simplemente realizamos los otros triángulos y nos queda el logo terminado:
Les dejo un jsFiddle con el código completo por si quieren modificarlo y hacer pruebas
Hay muchísimo más por explorar en lo que respecta a CANVAS, pero es un buen punto de partida conocer de que se trata y sus funciones básicas.