El canvas de HTML 5 (II). Trazos en 2d.

Facebooktwittergoogle_pluslinkedinmailFacebooktwittergoogle_pluslinkedinmail

En el artículo anterior aprendimos lo básico para crear lienzos de dibujo en HTML 5. En concreto, aprendimos a insertar los lienzos en la página, prever un mecanismo de fallback para navegadores inadecuados y referenciar los lienzos desde JavaScript.

Sin embargo, aún no sabemos qué hacer con ellos, ni nos sirven para nada. En este artículo vamos a empezar a aprender a incluir formas en 2d en nuestros canvas. Y subrayo lo de “empezar” porque el dibujo en lienzos de HTML 5 permite tantas posibilidades que abarcarlas todas en un artículo es imposible. Sin embargo, de aquí saldremos con unos conocimientos básicos que, en posteriores artículos, nos permitirán seguir avanzando.

Cómo siempre, espero que disfrutes de esta lectura y, sobre todo, que te resulte interesante y provechosa.

INTRODUCCIÓN

Como ya avanzamos en el artículo anterior, las formas en los lienzos se dibujan mediante instrucciones JavaScript. Eso quiere decir muchas cosas pero, la más relevante, es que no insertamos imágenes: creamos líneas de código y estas generan las imágenes “al vuelo”. Como consecuencia de esto, nuestro documento web pesará mucho menos que si hubiera imágenes, por ligeras que estas fueran, y se cargará en el navegador mucho más rápido.

Para empezar a dibujar algunas formas primitivas en 2d en un canvas, debemos controlar, básicamente, cuatro aspectos principales:

  • El color. Podemos usar colores planos, gradientes (tanto lineales como radiales) e, incluso, texturas. En este artículo nos centraremos en colores planos, dejando los gradientes y las texturas para más adelante. Los colores pueden establecerse en los mismos formatos que en CSS 3, es decir, por nombre, en hexadecimal, en rgb y en rgba, cómo iremos viendo.
  • El trazo. Es el contorno de las figuras que dibujemos. Podremos controlar aspectos como su color, grosor, terminaciones, etc. No todas las figuras tienen por qué tener contorno. Una figura puede dibujarse con o sin contorno.
  • El relleno. Las figuras pueden ser “huecas” (si sólo tienen contorno) o “sólidas” (si, tienen relleno, con o sin contorno). En este artículo hablaremos de figuras huecas.
  • El orden de apilamiento. En un mismo canvas podemos definir varias figuras. Estas se van colocando en el orden en que se dibujen en el código, de modo que las primeras van “al fondo” del lienzo, mientras que las últimas se colocan encima.

Y, con esto, de momento, tenemos suficiente. Vamos a empezar a dibujar.

FIGURAS HUECAS

Vamos a crear un canvas con algunas figuras huecas en su interior. En concreto, una línea recta, un rectángulo y un arco circular. Como la mejor manera de aprender es practicando, vamos a empezar viendo el código correspondiente, llamado canvas_006.htm:

Cómo ves, esta vez no he sido parco en comentarios. El CSS sólo establece un borde para el lienzo, con un fondo blanco, cómo ves a continuación:

El resultado lo vemos en la siguiente imagen:

Como ves, en esta ocasión sólo empleamos un canvas, en lugar de dos. De momento, es todo lo que necesitamos. Veamos lo que hemos hecho. Según lo vayamos viendo, presta especial atención a los comentarios del código.

Como ya sabemos, aparte de definir el canvas en HTML (etiquetas <canvas>...</canvas>), lo primero que hacemos es referenciarlo en jQuery y crear un contexto que será donde dibujemos. Lo hacemos entre las líneas 15 y 19 del código:

/* Referenciamos el canvas y, si se han referenciado correctmente,
creamos el correspondiente contexto.
Si el navegador soporta canvas, la referenciación no presenta problemas. */
var objeto_canvas_1 = $('#canvas_1');
if ($(objeto_canvas_1)[0].getContext) var contexto_canvas_1 = $(objeto_canvas_1)[0].getContext('2d');

Esto aprendimos a hacerlo en el artículo anterior, y ya no tiene más misterio. A continuación empezamos a dibujar en el objeto de contexto (recuerda que dijimos que, con los lienzos, no se dibuja en el propio lienzo, sino en el contexto). Vamos a crear una línea azul que cruce el lienzo desde la esquina superior izquierda hasta la esquina inferior derecha.

TRAZANDO UNA LÍNEA RECTA

Lo primero que hacemos es inicializar una ruta. Cuando trabajamos con trazos, es necesario, en la mayoría de los casos, realizar este proceso cada vez que vamos a dibujar una línea o el contorno de una forma. Si no, al establecer un color, podemos cambiar, sin desearlo, el color de otros trazos que ya existan en el lienzo. Además, si la figura que vamos a dibujar no empieza justo en el punto donde terminó la anterior, pueden aparecer líneas no deseadas. Hay casos, según la última figura dibujada y la siguiente que vayamos a dibujar, en los que no es necesario inicializar la ruta, pero es de esos procesos que “no piden pan”, y así nos aseguramos de obtener los resultados deseados. Para inicializar la ruta usamos el método beginPath() del objeto de contexto, como vemos en la línea 25:

contexto_canvas_1.beginPath(); // Inicializamos una ruta

En este caso no lo podríamos haber ahorrado ya que, dado que aún no hay contenido en el lienzo, lo que hagamos no va a afectar a nada anterior. Sin embargo, más vale ir cogiendo buenas costumbres.

A continuación establecemos el color azul para la línea que vamos a dibujar, usando la propiedad strokeStyle del objeto de contexto, como se ve en la línea 31:

contexto_canvas_1.strokeStyle = "#2E3FA6"; // Un azul medio

Ahora vamos a establecer el grosor del trazo para la figura que vamos a dibujar. Eso lo hacemos con la propiedad lineWidth del objeto de contexto. El grosor se expresa en píxeles y, por defecto (si no lo establecemos, ni está establecido de antes) su valor es 1. En este caso lo vamos a fijar en 3, como vemos en la línea 33:

contexto_canvas_1.lineWidth = 3;

El siguiente paso es situar el punto de inicio de la línea recta. Para ello empleamos el método moveTo(x, y) del objeto de contexto. Este método recibe, como ves, dos argumentos, correspondientes a las coordenadas cartesianas X e Y del punto que queremos establecer como inicio. A este efecto, recuerda que el punto 0, 0 corresponde con la esquina superior izquierda del lienzo. El eje de las X crece hacia la derecha, mientras que el eje de las Y crece hacia abajo. Vemos como establecer el punto inicial en la línea 35:

contexto_canvas_1.moveTo(0, 0);

El siguiente paso es decirle hasta donde llegará la línea. Para ello empleamos el método lineTo(x,y) del objeto de contexto. Este método recibe, como argumentos, las coordenadas del punto final, en píxeles, siendo válido todo lo que hemos comentado aquí sobre coordenadas. Lo vemos en la línea 36:

contexto_canvas_1.lineTo(299, 149);

Esto nos dice que la línea terminará en el punto X = 299, Y = 149. Si recuerdas, cunado se define un canvas en HTML sin especificar la anchura ni la altura (ni por CSS ni por atributos), se toman, por defecto, 300 píxeles de ancho y 150 de alto. Por lo tanto, el canvas está definido entre 0, 0 y 299, 149. Este último par de coordenadas define, en nuestro ejemplo, la esquina inferior derecha.

ATENCIÓN. Para que quede claro. Cuando dibujes una forma en un canvas, ten cuidado de no exceder sus límites. Si la forma que dibujas “sale” fuera del canvas, la parte que no quepa no se visualizará. Por supuesto, puedes redimensionar el canvas con CSS o jQuery, pero ese redimensionado no se hace automáticamente. Si tu no lo haces por programación, lo que dibujes deberá quedar siempre contenido dentro del lienzo, o sólo se visualizará parcialmente, estropeando tu diseño.

Bien. Ya tenemos definidos los extremos de la línea, pero aún no la hemos dibujado. Cuando se define una forma en trazo, se debe terminar empleando el método stroke() del objeto de contexto, que es el que, finalmente, la dibuja. Lo vemos en la línea 37:

contexto_canvas_1.stroke();

Y ya está. Ya tenemos nuestra línea azul cruzando el canvas.

DIBUJANDO UN RECTÁNGULO

Bien. A continuación vamos a ver como dibujar un rectángulo (sólo el contorno, sin contenido). Empezamos, como ya hemos comentado, inicializando una ruta, como vemos en la línea 41:

contexto_canvas_1.beginPath();

A continuación vamos a establecer el color del trazo, en este caso, un rojo medio, como vemos en la línea 42:

contexto_canvas_1.strokeStyle = "#D63333"; // Un rojo medio

Lo siguiente es definir el rectángulo, con el método rect(origen_X, origen_Y, anchura, altura), del objeto de contexto. Los parámetros que recibe, expresados en píxeles se refieren a las coordenadas X e Y del punto de origen, y a la anchura y altura del rectángulo. Lo vemos en la línea 43:

contexto_canvas_1.rect(10, 10, 120, 130);

Por último, empleamos, como ya sabemos, el método stroke() para dibujar la forma que acabamos de definir, como vemos en la línea 44:

contexto_canvas_1.stroke();

Observa que, como esta vez no hemos modificado el valor de lineWidth se mantienen los 3 píxeles de ancho.

DIBUJAR UN ARCO

Esta es una forma que requiere un poco más de atención. No obstante, cómo vas a ver, tampoco es que sea especialmente difícil, una vez se entiendo la operativa. Empezamos iniciando una ruta, cambiando el color del trazo a verde y estableciendo un ancho de trazo de 1 píxel, como ves en las líneas 48, 49 y 50:

contexto_canvas_1.beginPath();
contexto_canvas_1.strokeStyle = "#32AF38"; // Un verde medio
contexto_canvas_1.lineWidth = 1;

Esto ya lo conocemos, y ya no hay nada de particular.

A continuación, definimos el arco. Este puede ser parte de una circunferencia, o una circunferencia completa. Para ello usamos el método arc(centro_X, centro_Y, radio, angulo_inicio, angulo_final), del objeto de contexto. Lo vemos en la línea 51:

contexto_canvas_1.arc(200, 75, 40, D2R(270), D2R(90));

Vamos a hablar un  poco sobre los parámetros. Los tres primeros no tienen misterio. Como un arco es parte de una circunferencia, definimos las coordenadas X e Y del centro, y el radio de dicha circunferencia, siendo las tres medidas en píxeles.

A continuación tenemos que definir el punto angular donde empieza el arco, y el punto angular donde termina. Para esto, debemos saber que podemos considerar la circunferencia como si fuera la esfera de un reloj: El punto correspondiente a 0º está situado a la derecha, donde estarían las 3; el punto correspondiente a 90º está situado en la parte inferior, donde estarían las 6; el punto correspondiente a 180º está situado a la izquierda, donde estarían las 9; por último, el punto correspondiente a 270º está situado en la parte superior, donde estarían las 12. Partiendo de este razonamiento, por ejemplo, el punto correspondiente a 30º estaría situado en la parte derecha, un poco desplazado hacia abajo, en el lugar que estarían las 4 en la esfera del reloj, y, así, sucesivamente. El esquema obedece a la imagen que ves a la derecha.

Así, en nuestro ejemplo, como tenemos un arco que va de la parte superior de la circunferencia a la parte inferior de la misma, el ángulo de inicio corresponde a 270º, y el de final a 90º.

Sin embargo, aquí surge un problema. Cuando hablamos de ángulos, la mayoría de nosotros estamos acostumbrados a pensar en términos de grados, minutos y segundos. Sin embargo, los ángulos de los arcos en canvas deben ser expresados en radianes. Es una unidad de medida con la que no estamos familiarizados. Afortunadamente, la fórmula de conversión es muy simple, y hemos añadido una función que recibe un valor en grados, y devuelve su contravalor en radianes, como vemos en las líneas de la 55 a la 58:

function D2R(deg){
    var rad = (deg * Math.PI)/180;
    return rad;
}

Cómo ves en la línea 51, hemos usado esta función en los parámetros relativos a los ángulos, para poder expresarlos en grados y que el método arc() los reciba en radianes.

Y ya casi está. Hemos definido el arco y, como hemos hecho con las otras figuras, ya sólo nos falta dibujarlo, como ves en la línea 52:

contexto_canvas_1.stroke();

CONCLUYENDO

Con lo que hemos visto aquí tenemos suficiente de momento. En posteriores artículos seguiremos aprendiendo a dibujar en nuestros canvas. Antes de acabar quiero hacerte una reflexión. Observa que, en cada caso, hemos usado el método stroke() para dibujar la forma que hemos definido. Considera cada forma que defines como en un buffer intermedio de memoria. El método stroke() vuelca el contenido de ese buffer en el canvas, vaciándolo para definir la siguiente forma.

Cómo ya es habitual, puedes descargar los ejemplos de este artículo en este enlace.

     

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *