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:

[fuente: Can I Use]Compatibilidad de CANVAS - HTML5

Compatibilidad de funciones básicas con exploradores

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 ** y seteamos el tamaño. Noten que ingrese el tamaño como atributo del tag y no como CSS, es importante hacerlo así ya que en algunos exploradores no funciona bien si lo hacemos por CSS.

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?:

  1. Seteo un estilo
  2. Dibujo con ese estilo
  3. Seteo otro estilo
  4. Dibujo con el nuevo estilo
  5. 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.