Logo de Mosaic
HTML5
Canvas HTML5: Fundamentos

Canvas HTML5: Fundamentos

Mihai Sucan. 8 de enero de 2009. Publicado en: imágenes, texto, gráficos, 2D, gradientes, html5, web abierta, canvas

Introducción

La especificación de HTML5 incluye un montón de nuevas características, una de las cuales es el elemento canvas (literalmente, lienzo). Los canvas de HTML5 proporcionan una manera fácil y potente de dibujar gráficos usando JavaScript. Para cada elemento canvas puedes utilizar un "contexto" (piensa en una página de un cuaderno de dibujo), en el que puedes lanzar comandos JavaScript para dibujar lo que quieras. Los navegadores pueden aplicar múltiples contextos canvas y las diferentes APIs proporcionan la funcionalidad de dibujo.

La mayoría de los navegadores más importantes incluyen la capacidad de contextos canvas 2D: Opera, Firefox, Konqueror y Safari. Además, hay versiones experimentales de Opera que incluyen soporte para contextos canvas 3D, y un add-on que habilita el soporte para canvas 3D en Firefox:

En este artículo veremos los fundamentos de la aplicación de un contexto canvas 2D, y cómo utilizar las funciones básicas de canvas, incluyendo rectas, formas simples, imágenes, texto y mucho más. Supondremos que ya dominas los fundamentos de JavaScript.

Ten en cuenta que puedes descargar todos los ejemplos de código en un solo archivo zip, así como verlos en vivo usando los enlaces que incluimos.

Las bases del uso de canvas

Crear un contexto canvas en una página es tan fácil como añadir el elemento <canvas> al documento HTML así:

<canvas id="myCanvas" width="300" height="150">
  Contenido para el caso en que el navegador no soporte Canvas.
</canvas>

Es necesario definir un ID de elemento para poder localizar después el elemento en el código JavaScript, y también es necesario definir una anchura y una altura para el lienzo.

Ya hemos creado el cuaderno de dibujo, o sea que toca llevar el lápiz al papel. Para dibujar en el canvas hay que utilizar JavaScript. Primero se localiza el elemento canvas con getElementById y, a continuación, se inicializa el contexto que desees. Una vez hecho esto, puedes empezar a dibujar en el canvas con los comandos disponibles en la API del contexto. La siguiente secuencia de comandos (ejecuta el ejemplo en vivo) dibuja un simple rectángulo en el canvas definido anteriormente:

// Get a reference to the element.
var elem = document.getElementById('myCanvas');
  
// Always check for properties and methods, to make sure your code doesn't break
// in other browsers.
if (elem && elem.getContext) {
  // Get the 2d context.
  // Remember: you can only initialize one context per element.
  var context = elem.getContext('2d');
  if (context) {
    // You are done! Now you can draw your first rectangle.
    // You only need to provide the (x,y) coordinates, followed by the width and
    // height dimensions.
    context.fillRect(0, 0, 150, 100);
    }
}

Puedes elegir entre incluir el script en el head del documento o en un fichero externo.

La API de contexto 2D

Ya hemos creado nuestra primera imagen canvas básica. Echemos ahora una ojeada un poco más profunda a la API 2D de canvas, y veamos qué tenemos a nuestra disposición.

Segmentos y trazos básicos

Ya hemos visto en el ejemplo anterior que es muy fácil dibujar rectángulos de color a nuestro gusto.

Con las propiedades fillStyle y strokeStyle puedes elegir fácilmente los colores utilizados para crear formas y trazos básicos. Los valores de color que puedes utilizar son los mismos que en CSS: códigos hexadecimales, RGB(), rgba() e incluso HSLA(), si el navegador es compatible (por ejemplo, esta función es soportada por Opera 10.0 y versiones posteriores).

Con fillRect puedes dibujar rectángulos rellenos. Con strokeRect puedes dibujar solo los bordes del rectángulo, sin rellenar. Si deseas borrar una parte del canvas, puedes utilizar clearRect. Los tres métodos usan los mismos argumentos: x, y, width, height. Los dos primeros argumentos dan las coordenadas (x, y) y los dos últimos dan las dimensiones de anchura y altura del rectángulo.

Para cambiar el grosor de las líneas puedes utilizar la propiedad lineWidth. Veamos un ejemplo que utiliza clearRect, fillRect, strokeRect y más:

context.fillStyle = '#00f'; // azul
context.strokeStyle = '#f00'; // rojo
context.lineWidth = 4;

// Dibujar unos cuantos rectángulos.
context.fillRect (0, 0, 150, 50);
context.strokeRect(0, 60, 150, 50);
context.clearRect (30, 25, 90, 60);
context.strokeRect(30, 25, 90, 60);

Este ejemplo produce un resultado como el que se puede fer en la Figura 1.

Ejemplo de fillRect, strokeRect y clearRect

Figura 1: Ejemplo de fillRect, strokeRect y clearRect.

Caminos

Los caminos (paths) de canvas permiten dibujar formas personalizadas. Primero se dibuja el "perfil", a continuación se dibujan los trazos y finalmente se rellena la forma, si se desea. Crear una forma personalizada es simple: para empezar a dibujar usas beginPath() y a continuación trazas el camino que compone la forma mediante líneas, curvas y otras primitivas. Una vez has terminado, usas fill y stroke si quieres para rellenar la forma o dibujar un trazo y, finalmente, usas closepath() para acabar la forma.

Toca un ejemplo. El siguiente código dibuja un triángulo:

// Establece las propiedades de estilo.
context.fillStyle = '#00f';
context.strokeStyle = '#f00';
context.lineWidth = 4;

context.beginPath();
// Comenzar desde el punto de arriba a la izquierda.
context.moveTo(10, 10);
// se dan las coordenadas (x,y)
context.lineTo(100, 10);
context.lineTo(10, 100);
context.lineTo(10, 10);

// Listo! Ahora se rellena la forma y dibuja la línea.
// Nota: la forma no será visible hasta que llames uno de los dos métodos.
context.fill();
context.stroke();
context.closePath();

Esto genera algo como lo que se muestra en la Figura 2.

Un triángulo básico

Figura 2: Un triángulo básico

También he preparado un ejemplo de rutas más complejo, con rectas, curvas y arcos. Échale un vistazo.

Insertar imágenes

El método drawImage permite insertar otras imágenes (elementos img y canvas) en el contexto de tu canvas. En Opera también se pueden dibujar imágenes SVG dentro de un canvas. Se trata de un método bastante complejo, que puede tomar tres, cinco o nueve argumentos:

El siguiente código de ejemplo muestra los tres tipos de drawImage en acción:

// 3 argumentos: elemento y coordenadas (x,y) de destino.
context.drawImage(img_elem, dx, dy);

// 5 argumentos: elemento, coordenadas (x,y) de destino y
// anchura y altura (si quieres cambiarle el tamaño a la imagen).
context.drawImage(img_elem, dx, dy, dw, dh);

// 9 argumentos: el elemento, coordenadas (x,y) de la fuente, anchura y
// altura de la fuente (para recortar), coordenadas (x,y) de destino y anchura y
// altura de destino (reescalado).
context.drawImage(img_elem, sx, sy, sw, sh, dx, dy, dw, dh);

Esto debería generar lo que se muestra en la Figura 3.

Ejemplo de drawImage

Figura 3: Ejemplo de drawImage

Manipulación basada en píxels

La API del contexto 2D ofrece tres métodos para dibujar píxel a píxel: createImageData, getImageData y putImageData.

Los píxeles en bruto se guardan en objetos de tipo ImageData. Cada objeto tiene tres propiedades: width, height y data. La propiedad data es de tipo CanvasPixelArray, y almacena una cantidad de elementos igual a width*height*4, lo que significa que para cada píxel se definen los valores de rojo, verde, azul y alfa, en el orden en que quieres que aparezcan (todos los valores van de 0 a 255, incluyendo el alfa). Los píxeles se ordenan de izquierda a derecha, fila por fila, de arriba a abajo.

Para entender mejor cómo funciona todo esto, echa un vistazo a un ejemplo que dibuja un bloque de píxeles de color rojo.

// Crea un objeto ImageData.
var imgd = context.createImageData(50,50);
var pix = imgd.data;

// Bucle sobre cada píxel y poner a rojo.
for (var i = 0; n = pix.length, i < n; i += 4) {
  pix[i ] = 255; // red channel
  pix[i+3] = 127; // alpha channel
}

// Dibujar el objeto ImageData en las coordenadas (x,y) dadas.
context.putImageData(imgd, 0,0);

Nota: No todos los navegadores han implementado createImageData. En los navegadores sin soporte es necesario obtener el objeto ImageData utilizando el método getImageData. Por favor, consulta el código de ejemplo proporcionado.

Con las capacidades de ImageData se puede hacer mucho más que esto. Por ejemplo, se puede hacer filtrado de imágenes, o visualizaciones matemáticas (como fractales y más). El código siguiente muestra cómo crear un filtro simple de inversión de color:

// Obener el CanvasPixelArray de las coordenadas y dimensiones dadas.
var imgd = context.getImageData(x, y, width, height);
var pix = imgd.data;

// Bucle sobre cada píxel e invertir color.
for (var i = 0, n = pix.length; i < n; i += 4) {
  pix[i ] = 255 - pix[i ]; // rojo
  pix[i+1] = 255 - pix[i+1]; // verde
  pix[i+2] = 255 - pix[i+2]; // azul
  // i+3 es el alfa (el cuarto elemento)
}

// Dibujar ImageData en las coordenadas (x,y) dadas.
context.putImageData(imgd, x, y);

La figura 4 muestra el filtro de inversión de color aplicado a un gráfico de Opera (compara con la figura 3, que muestra el esquema de color original del gráfico de Opera).

Ejemplo de la inversión de color

Figura 4: el filtro de inversión de color en acción

Texto

La API de texto sólo está disponible sólo en versiones recientes de WebKit y en las compilaciones de prueba (‘nightlies’) de Firefox 3.1, pero decidí incluirla aquí por completitud1.

Las siguientes propiedades de texto están disponibles en el objeto context:

Hay dos métodos para escribir texto: fillText y strokeText. El primero da forma al texto y lo rellena con el fillStyle actual, mientras que el segundo dibuja el perfil/borde del texto con el strokeStyle actual. Ambos toman tres argumentos: el texto que desea mostrar, y las coordenadas (x, y) para definir dónde mostrarlo. También hay un cuarto argumento opcional: anchura máxima. Esto hace que el navegador reduzca el tamaño del texto para que quepa en el ancho dado, si es necesario.

Las propiedades de alineación del texto afectan a la posición del texto en relación con las coordenadas (x, y) que pases a los métodos de dibujo.

En este punto toca un ejemplo. El siguiente código es un ejemplo simple de texto canvas "hola mundo".

context.fillStyle = '#00f';
context.font = 'italic 30px sans-serif';
context.textBaseline = 'top';
context.fillText ('Hello world!', 0, 0);
context.font = 'bold 30px sans-serif';
context.strokeText('Hello world!', 0, 50);

La figura 5 muestra lo que crea el ejemplo.

Ejemplo de texto

Figura 5: un ejemplo sencillo de texto en canvas

Sombras

La API de sombras da cuatro propiedades:

El uso es muy sencillo, como demuestra el siguiente ejemplo de código de sombra canvas:

context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = 'rgba(255, 0, 0, 0.5)';
context.fillStyle = '#00f';
context.fillRect(20, 20, 150, 100);

Genera lo mostrado en la figura 6.

Ejemplo de sombra canvas. Rectángulo azul con sombra roja

Figura 6: Ejemplo de sombra canvas. Rectángulo azul con sombra roja.

Degradados

A las propiedades fillStyle y strokeStyle también se les puede asignar objetos CanvasGradient, en lugar de cadenas de color CSS: estos permiten utilizar gradientes de color para líneas y rellenos en lugar de colores sólidos.

Para crear objetos CanvasGradient puedes utilizar dos métodos: createLinearGradient y createRadialGradient. El primero crea un gradiente lineal —líneas de color todas en una dirección— mientras que el segundo crea un gradiente radial —círculos de color emanando desde un solo punto.

Una vez tienes el objeto gradiente puedes agregar saltos de color a lo largo del gradiente usando el método addColorStop del objeto.

El código siguiente muestra cómo utilizar gradientes:

// Hay que dar las coordenadas (x,y) de origen y destino
// para el gradiente (dónde empieza y dónde acaba).
var gradient1 = context.createLinearGradient(sx, sy, dx, dy);

// Ahora se puede añadir colores al gradiente.
// El primer argumento da la posición del color en el gradiente. El
// rango de valores aceptados va de 0 (inicio del gradiente) a 1 (final del gradiente).
// El segundo argumento da el color deseado, con el formato de color de CSS.
gradient1.addColorStop(0, '#f00'); // rojo
gradient1.addColorStop(0.5, '#ff0'); // amarillo
gradient1.addColorStop(1, '#00f'); // azul

// Para el gradiente radial también hay que dar
// fuente y el radio del círculo de destino.
// Las coordenadas (x,y) definen el punto central del
// círculo (inicio y destino).
var gradient2 = context.createRadialGradient(sx, sy, sr, dx, dy, dr);

// Añadir colores a un gradiente radial es igual que
// añadir colores a gradientes lineales.

También he preparado un ejemplo más avanzado, que hace uso de un degradado lineal, sombras y texto. El ejemplo produce el resultado que se ve en la Figura 7.

Ejemplo de salida usando un gradiente lineal

Figura 7: Ejemplo de salida usando un gradiente lineal.

Demos en línea de canvas

Si quieres ver lo que han hecho otros con Canvas, puedes echar una ojeada a los siguientes proyectos:

Resumen

Canvas es una de las características más interesantes de HTML5, y puede usarse en la mayoría de navegadores web modernos. Ofrece todo lo necesario para crear juegos, mejoras en la interfaz de usuario y aún más cosas. La API de contexto 2D incluye una gran cantidad de funcionalidades además de las que se tratan en este artículo. Espero que hayas obtenido una buena base de canvas, y sed de saber más.


1 Desde la elaboración de este artículo, múltiples navegadores han añadido soporte para la API de texto.

Logo Creative Commons
Los contenidos recogidos en este artículo están sujetos a una licencia Creative Commons
Reconocimiento, No comercial - Compartir bajo la misma licencia 3.0 No adaptada
.
: Ir al índice : Ir al artículo siguiente