Volver al índice del curso

Lección 5: Trabajar con el Canvas

Objetivos:

El Canvas es una API de dibujo en dos dimensiones incluida en la especificación HTML5. La inclusión de una API de dibujo nativa permite a los desarrolladores generar imágenes dinámicamente dentro de una página web, por lo general a partir de datos obtenidos desde alguna fuente o a partir de la interacción con el usuario. A diferencia de los formatos conocidos de imágenes como JPG o PNG, los dibujos que se crean con Canvas se pueden modificar en tiempo real.

 

Para empezar

Vas a trabajar con algunos archivos que se encuentran en la carpeta HTML5_05lessons a lo largo de esta lección. Comprueba que has descargado y copiado la carpeta de prácticas de HTML5 en tu ordenador.

En esta lección vas a aprender los conceptos básicos de la API Canvas, que incluyen el dibujo de figuras, trazos, textos y el uso de colores y gradientes. Después vamos a continuar con conceptos más avanzados de dibujo de imágenes, sombras, el empleo de transformaciones y la creación de animaciones. Puedes utilizar el elemento Canvas de HTML5 para definir la superficie de dibujo, pero tendremos que programar en JavaScript las instrucciones de dibujo y las líneas, formas y colores resultantes. Aunque los conocimientos necesarios de JavaScript son mínimos, si nunca has programado en este lenguaje conviene que antes leas con atención esta introducción breve al lenguaje.

 

Conceptos básicos de JavaScript

JavaScript es un lenguaje de scripting con su propia estructura y sintaxis. Queda fuera del alcance de esta lección explicar por completo JavaScript y cómo se utiliza, pero sí vamos a ver aquí algunos conceptos básicos, ya que si no has programado antes en este lenguaje, necesitarás tener unos conocimientos básicos sobre la forma en que JavaScript interactúa con el código HTML, y estos conocimientos te servirán como una base que podrás aplicar a lenguajes de scripting más avanzados, como C# o PHP. En los pasos siguientes vamos a trabajar con un formulario sencillo, para entender algunos de los conceptos fundamentales de JavaScript.

1 En el editor de textos, en el Menú Archivo selecciona Abrir y ve a la carpeta HTML5_05lessons. Selecciona el archivo 05_subscribe.html  y pulsa Abrir. Para mantener una copia de seguridad de este archivo, guárdalo con otro nombre.

2 En el menú Archivo, selecciona "Guardar como" y guárdalo con el nombre 05_subscribe_work.html. Comprueba que lo has grabado en la carpeta HTML5_05lessons.

Repasa durante un momento el código HTML. Verás que está creado totalmente en HTML y que, en consecuencia, carece de toda interactividad o dinamismo. Es una página totalmente estática.

3 Visualiza la página en el navegador y pulsa después el botón Submit. No ocurre nada salvo el comportamiento por defecto del botón, que es un elemento que no tiene en esta página web ninguna función concreta.

HTML no puede comprobar si un campo de formulario tiene datos. Necesitas JavaScript para eso.

Necesitamos utilizar JavaScript para que el botón sea interactivo, ya que HTML nos permite hacer ciertas cosas, como modificar el texto que aparece en el botón, pero no aporta métodos para controlar la interactividad. Vamos a añadir código JavaScript para que al pulsar el botón se abra una ventana en el navegador y nos pida el nombre. Una vez escrito el nombre, al pulsar OK, el código JavaScript mostrará este nombre en pantalla.

4 Debajo de la etiqueta  <title> en la página, escribe estas líneas de código:

  <script type="text/javascript">
</script>

Tenemos que indicar a HTML que queremos utilizar JavaScript, igual que hemos hecho ya con CSS. Podemos insertar esas instrucciones en cualquier lugar del código HTML, pero las buenas prácticas recomendadas son añadir el código de programación en la sección de la cabecera (<head>) de la página.

El atributo type es opcional en HTML5.

5 Añade entre las etiquetas de <script> el siguiente código (en rojo):

<script type="text/javascript">
function show_prompt()
</script>

Una función en JavaScript es un código que se ejecutará como resultado de algún evento en la página. En este caso, la función tiene un nombre, show_prompt(), y lo único que hará es indicarle al navegador que abra una pequeña ventana en pantalla . El evento que dispara esta función es la acción del usuario de pulsar el botón Submit.

La función show_prompt() necesita más cosas para conseguir lo que queremos.

6 Añade este código (marcado en rojo) debajo de la función:

<script type="text/javascript">
function show_prompt()
{
 var name=prompt();
}
</script>

En esta línea de código hemos declarado una variable y le hemos asignado un valor. Esta variable, llamada name, obtiene su valor de la función "prompt()". Una línea de código es la cantidad mínima de información que se necesita para hacer que ocurra algo en JavaScript.

Para que se ejecute el código JavaScript necesitamos añadir una instrucción al botón HTML que le describirá cómo ha de ejecutar el código y qué función debe utilizar.

7 Añade este código (indicado en rojo), al HTML del botón:

<input type="button"onclick="show_prompt()" value="Submit" />

La instrucción onclick se conoce como evento JavaScript y el valor "show_prompt()" es la función JavaScript que hemos declarado en el paso 5 dentro de la etiqueta  <script>. Ahora hemos cerrado la cadena lógica que, en resumen, viene a decir "cuando el usuario pulse el botón Submit, llama a la función show_prompt. Cuando se ejecute la función show_prompt, ejecutará  otra función llamada prompt".

8 Guarda el archivo y visualiza la página en el navegador. Si la configuración de seguridad del navegador está preparada para impedir la ejecución de scripts, deberás pulsar en el botón "Permitir el contenido bloqueado". Pulsa el botón Submit y verás aparecer una ventana pidiendo un dato en pantalla (un tipo de ventana específica, denominada "User Prompt"). Es una demostración realmente simple de JavaScript en acción. Ahora vamos a añadir algo más de código para insertar datos en esta ventana emergente, en los pasos siguientes.

9 Cierra el navegador y en el editor añade el código marcado en rojo a la declaración de la variable JavaScript (la que hemos insertado en el paso 6):

var name=prompt("Please enter your name","Chris P. Bacon");

Guarda el archivo y muéstralo en el navegador. Prueba a ver qué sucede ahora al pulsar Submit. Los nuevos valores aparecen en la ventana:

 La ventana de introducción de datos ("User Prompt") es una de las demostraciones más simples JavaScript en acción.

Ahora hay que añadir código JavaScript para capturar el valor del texto introducido en esta ventana para poder mostrarlo después en una página HTML nueva.

10 Cierra el navegador y añade este código indicado en rojo al código  JavaScript:

<script type="text/javascript">
function show_prompt()
{
var name=prompt("Please enter your name","Chris P. Bacon");
if (name!=null && name!="")
{
document.write("Hello " + name + "! How are you today?");
}
}
</script>

El nuevo código añadido se compone de dos partes: una sentencia IF y una sentencia THEN. La sentencia IF busca un valor en el campo de texto. Si hay algún valor, se ejecuta la instrucción document.write de la línea siguiente, y se ve en pantalla el nombre que hemos escrito en la ventana emergente.

Los caracteres != y && que aparecen en la expresión (name!=null && name!="") se conocen como operadores en JavaScript y son piezas básicas en el diseño lógico de cualquier función.

La expresión document.write es una sentencia que le dice al navegador web que escriba un dato en una página web. En este caso, se trata de escribir la frase "Hello" seguida de las palabras que hayamos escrito en el campo de texto de la ventana emergente anterior, y terminaría con las palabras "How are you today?".

11 Guarda la página y muéstrala otra vez en el navegador. Deja el valor por defecto de momento y pulsa OK. Aparece una página nueva, como resultado del código que hemos añadido en el paso anterior.

El nombre escrito en el campo de texto se muestra en una página nueva.

Pulsa el botón Atrás del navegador y pulsa el botón Submit de nuevo, pero esta vez escribe tu nombre en la línea de texto. Pulsa Aceptar y aparecerá este nuevo nombre en la página siguiente.

Se trata de una función JavaScript relativamente sencilla, pero que nos permite saber a grandes rasgos cómo se comunica JavaScript con los elementos HTML de una página y ciertos conceptos básicos de la lógica con la que operan las funciones de JavaScript. En el siguiente ejercicio vamos a practicar con los eventos de JavaScript.

 

Eventos de JavaScript

El evento JavaScript con el que hemos practicado en el ejercicio anterior era onclick , el cual forzaba la ejecución del código al pulsar el botón Submit. Hay muchos otros eventos que podemos utilizar también y para saber mejor cómo funcionan, vamos a modificar nuestro ejemplo.

1 En el código HTML cambia el evento onclick por el evento onmouseover (como se muestra en la parte destacada en rojo):

<input type="button" onmouseover="show_prompt()" value="Submit" />

2 Guarda el archivo y ábrelo ahora en el navegador. Pasa el cursor sobre el botón, pero sin pulsar. La ventana emergente aparece. El evento onmouseover lanza el código JavaScript asociado en cuanto el cursor pasa por encima del área del botón.

En este momento el evento está asociado al botón, pero podemos mover el evento y en vez de reaccionar al botón, que lo haga asociado a toda la página.

3 Selecciona el evento onmouseover y su valor, y pulsa Ctrl + X para cortar el código. Busca la etiqueta de abertura de <body> y pulsa Ctrl + V para pegar el código, como se muestra aquí:

<body onmouseover="show_prompt()">

El evento onmouseover aplicado a la página entera va a funcionar, pero es las buenas prácticas recomiendan el uso del evento "onload", que lanza el código JavaScript en el momento en que se abre la página:

<body onload="show_prompt()">

4 Una vez hemos cambiado el evento a onload, guarda la página y ábrela en el navegador. En cuanto la página se abre, se nos muestra la ventana emergente pidiendo el nombre. Podríamos introducir el texto aquí, pero tal y como está estructurado el evento en este momento, el resultado sería que el texto escrito se mostraría en la misma página, así que pulsa Cancelar.

Con este ejercicio has aprendido que JavaScript te deja elegir el momento y la forma de llamar al código. En ambos casos la interacción del usuario lanza la ejecución de ese código, pero el evento onload nos ofrece pocas opciones para elegir el momento, mientras que el evento onclick (asociado al botón), nos da más control.

 

El Modelo de Objeto de Documento (DOM)

JavaScript tiene acceso a los objetos dentro del navegador. Así es como aparece la ventana emergente en el ejercicio anterior. Para este acceso se utiliza el denominado DOM (Document Object Model) o Modelo de Objeto de Documento, que es una convención para acceder a los datos dentro de las páginas HTML. Este modelo describe cómo se relacionan todos los elementos de una página HTML –por ejemplo textos, formularios o imágenes- con la estructura de mayor nivel, que es la que se denomina "documento".

JavaScript tiene acceso al documento y todos los elementos relacionados dentro de la página Web de un modo que no puede hacerse con HTML. Entre otras cosas, gracias a este acceso, con JavaScript se puede:

  • Validar campos de formulario
  • Detectar qué navegador estamos utilizando
  • Responder a los eventos de usuario (a su "actividad")
  • Guardar y devolver información desde/hacia el ordenador del usuario

Recuerda el primer ejercicio y la sección de código que añadiste, que tenía una etiqueta

document.write (the seventh line from the top).
<script type="text/javascript">
function show_prompt()
{
var name=prompt("Please enter your name","Chris P. Bacon");
if (name!=null && name!="")
{
document.write("Hello " + name + "! How are you today?");
}
}

</script>

A esta sección del código en rojo se la denomina una función y el comportamiento que ha demostrado la página es uno de los ejemplos más simples que se pueden hacer en JavaScript, puesto que tenemos muy pocos objetos en el documento. La mayoría de documentos HTML tienen dentro múltiples objetos y podemos pasar un valor de texto a otra zona de la página, o enviar datos desde un formulario. Ahora que tienes una idea básica de JavaScript y su funcionamiento, el trabajo con el elemento Canvas será más sencillo.

 

El elemento Canvas

El elemento canvas es algo distinto de los demás elementos de HTML5. Es más complejo en el sentido de que necesita de JavaScript para funcionar. El primer paso que daremos será añadir (o definir) un elemento canvas en nuestra página HTML. Después tenemos que guardar una referencia al contexto de dibujo para ese elemento en forma de variable de JavaScript. Más tarde utilizaremos el propio contexto para escribir nuestras instrucciones de dibujo.

1 Abre el archivo 05_canvastemplate.html dentro de la carpeta HTML5_05lessons y busca la plantilla que vamos a utilizar en los siguientes ejercicios (y que podrás modificar en futuros proyectos). Esta plantilla define un elemento <canvas> HTML , un cuadrado de 300 pixels de lado, que delimita la superficie de dibujo. Cuando se abre el cuerpo de la página, se llama a la función JavaScript setup(). Esta función encuentra el elemento canvas por su nombre y declara una variable con la referencia al contexto de dibujo del canvas. Una vez que tenemos disponible esa referencia, podemos dibujar libremente sobre esa superficie. El código HTML de la plantilla del canvas es así:

<body onload="setup();">
  
<canvas id="lessonCanvas" width="300"height="300" style="margin:100px;"></canvas>
</body>
                El código JavaScript tiene este aspecto:
<script type="text/javascript">
  function setup() {
    var canvas = document.getElementById('lessonCanvas');
    if (canvas.getContext) {
      var ctx = canvas.getContext('2d');
      <!--drawing instructions here -->
    }
  }
</script>

No vas a modificar este archivo, sino que cuando estés preparado para operar sobre el canvas por ti mismo, podrás utilizarlo como punto de partida.

2 En el menú Archivo del editor, cierra el archivo sin hacer cambios.

 

Ventajas del elemento Canvas

Según vayamos avanzando por los siguientes ejercicios seguramente pensarás que la cantidad de scripting que se necesita es mayor de la esperada. El elemento canvas nos permite crear gráficos que, de no disponer de él, tendríamos que generar con otros programas como Photoshop, Illustrator, o si se trata de animaciones, con Flash o Silverlight. La diferencia es que en vez de utilizar las herramientas de dibujo de estos programas, vamos a poder crear formas, gradientes, textos y otros elementos visuales con nuestro propio código.

El objetivo de esta lección consiste en explicar los conceptos fundamentales del manejo del elemento canvas. Sin duda, en el futuro tendremos aplicaciones que nos permitirán crear objetos y animaciones para los canvas sin necesidad de programarlos a mano. De hecho veremos algunos de estos desarrollos al final de la lección. De momento vamos a crear estos objetos desde cero, que es la mejor forma de saber cómo se hacen las cosas con el canvas.

El elemento canvas ha tenido un soporte razonablemente bueno entre los navegadores a lo largo del tiempo y podemos suponer que acabará sustituyendo a la amplia variedad de soluciones que conocemos con el nombre de "contenidos multimedia avanzados" y también se utilizará para juegos, animaciones, diagramas, gráficos, visualización de datos y para crear interfaces vectoriales de usuario, entre otros muchos usos posibles.

Una de las grandes ventajas del Canvas en todos estos casos de uso es que no necesita que instalemos un complemento en el navegador. Hay más casos de uso del canvas: los iconos de la interfaz de usuario son un ejemplo del tipo de gráficos que, en teoría, podemos crear con elementos canvas. Las imágenes creadas con este elemento pueden guardarse en el disco en forma de archivos PNG, así que podemos imaginar una aplicación web que nos permitirá exportar imágenes. Además, utilizando una funcionalidad del Canvas llamada "data uri" podemos embeber imágenes creadas con el Canvas directamente dentro de CSS.

Como sucede con la mayor parte de las funcionalidades de HTML5, queda a criterio de los diseñadores y desarrolladores el empezar ya a utilizar este elemento. En los ejercicios siguientes puedes empezar a hacerlo por ti mismo. Al finalizar la lección habrás creado un gráfico de barras empleando el canvas.

 

Trazos de dibujo ("paths")

Los trazos y las formas básicas son los componentes básicos de la creación de dibujos en el elemento canvas. Una vez te familiarices con las funciones más importantes, podrás crear elementos gráficos más complicados, como diagramas basados en datos, figuras animadas para tus juegos y otros diseños de gran utilidad e interés. Las primeras funciones que veremos en este apartado también nos van a servir para tener un conocimiento general de cómo funciona el elemento canvas.

 

Dibujo de rectángulos

El rectángulo es el trazo más sencillo que podemos dibujar. La función fillRect(x,y,width,height)que podemos utilizar dentro del objeto context , genera una figura rectangular en la posición y con el tamaño indicados por los parámetros, y con un relleno basado en el valor que tenga la variable fillStyle en ese momento. Una función estrechamente vinculada con ésta es strokeRect, que genera la misma figura pero en lugar de rellenarla,  dibuja el contorno basándose en el estilo definido en ese momento para la variable strokeStyle. La función clearRect emplea los mismos parámetros pero elimina ("limpia") todos los pixels del canvas que quedan dentro del área de un rectángulo definido.

1 Abre el archivo 05_drawingrectangles.html y guarda en la misma carpeta una copia con el nombre 05_drawingrectangles_work.html. En el código verás un elemento Canvas ya definido y una función JavaScript llamada setup que se ejecuta al abrir la página. En la función setup se guarda una referencia al contexto 2D del Canvas en una variable que es la que vamos a utilizar para dibujar.

2 En la sentencia if, después de la declaración  de la variable ctx, añade este código para dibujar un rectángulo que ocupe todo el canvas:

function setup() {
  var canvas = document.getElementById('lessonCanvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');
      ctx.strokeRect(0, 0, 300, 300);
  }
}

Como puedes ver, las coordenadas X e Y tienen un valor cero, es decir, el rectángulo se empieza a dibujar a partir de la esquina superior izquierda del canvas. Puesto que su anchura y altura valen 300 pixels, esto quiere decir que el rectángulo ocupa todo el espacio del canvas.

3 Debajo de la línea que acabas de escribir, añade estas otras dos líneas de código que cambian el color del trazo, que ahora es negro, a rojo, y una segunda que dibuja  un recuadro rojo más pequeño:

  ctx.strokeStyle = 'rgb(255, 0, 0)';
ctx.strokeRect(0.5, 0.5, 100, 100);

4 Guarda el archivo drawingrectangle_work.html y ábrelo en el navegador. Podrás ver algo similar a esta figura. Igual que con otras muchas funcionalidades de HTML5, si no vemos nada en pantalla lo que tenemos que hacer es confirmar que el navegador soporta el elemento HTML5 (el canvas en este caso).

Rectángulos con  borde negro (el mayor, coincidiendo con la superficie del canvas) y rojo (interior).

Como ves, el elemento Canvas tiene un margen definido en CSS que se añade solo a efectos de ayuda visual. Esto nos muestra que podemos utilizar CSS para modificar el estilo del elemento Canvas, igual que se hace con otros elementos HTML.

5 Vuelve al editor de textos y debajo de las líneas que acabas de escribir, añade la siguiente línea para dibujar un rectángulo con relleno:

  ctx.fillRect(20, 20, 100, 100);

6 Añade otras dos líneas de código para cambiar el color del relleno, que en este momento es negro, a verde, y dibuja otro segundo rectángulo con este nuevo color:

  ctx.fillStyle = 'rgb(0, 255, 0)';
ctx.fillRect(50, 50, 100, 100);

7 Guarda el archivo y vuelve a mostrarlo en el navegador. SI la página estaba ya abierta, simplemente actualiza el contenido (pulsando F5) o vuelve a cargar el archivo. Ahora lo que deberíamos ver es lo que aparece en esta figura:

Rectángulos con borde en rojo y negro, y otros rectángulos con relleno negro y verde creados con HTML5.

La función fillRect sirve para crear un rectángulo sólido (relleno), en vez de un recuadro.

8 Mantén abierta la página en el navegador y vuelve al editor. Debajo de las líneas del paso seis, añade este código para borrar los pixels de una zona del canvas:

  ctx.clearRect(80, 80, 30, 30);

9 Guarda el documento, vuelve al navegador y actualiza la página. Ahora verás un dibujo parecido al de la figura siguiente. La función clearRect convierte en transparentes todos los pixels que quedan dentro del área delimitada por el rectángulo, eliminando en parte los cambios de color que hemos hecho antes con strokeRect y fillRect.

Recuadros negro y rojo con rectángulos en negro y verde, y dentro de éste, un agujero transparente.

 

Dibujo de líneas y círculos

Las funciones de dibujo de rectángulos del apartado anterior son, en realidad, una de funciones aún más básicas combinadas de tal forma que su uso se hace más sencillo. Supongamos que nos interesa crear el mismo rectángulo utilizando funciones más básicas. Veamos otra vez el código de la función generadora:

ctx.strokeRect(0, 0, 300, 300);

El mismo rectángulo se puede generar siguiendo una secuencia de funciones más básicas:

ctx.moveTo(0, 0);
ctx.lineTo(300, 0);
ctx.lineTo(300, 300);
ctx.lineTo(0, 300);
ctx.lineTo(0, 0);
ctx.stroke();

Esta secuencia genera un trazo compuesto o línea poligonal, que comienza en el punto definido por las coordenadas de  moveTo(x, y). Las sucesivas funciones lineTo(x, y)van añadiendo puntos de inflexión al trazo, que se unirán posteriormente con líneas rectas. Finalmente, la función stroke es la que dibuja en el canvas las rectas que unen los puntos por orden, pero sin rellenar el espacio interior. Parece más razonable emplear la función de rectángulo puesto que hace lo mismo con una sola línea de código, pero conviene conocer cómo se manejan las funciones más básicas porque las podemos utilizar para dibujar cualquier forma.

1 Abre el archivo 05_drawinglinesandcircles.html y guarda una copia en disco, con el nombre 05_drawinglinesandcircles_work.html. Este archivo ya tiene un contexto de dibujo declarado en la función setup. En esta práctica vamos a añadir un rectángulo y una serie de líneas en zig-zag.

2 Dentro de la función setup, detrás de la línea var ctx = canvas.getContext('2d');, añade este código:

  ctx.strokeRect(0, 0, 300, 300);
ctx.moveTo(20, 20);
ctx.lineTo(100, 100);
ctx.lineTo(80, 200);
ctx.lineTo(200, 80);
ctx.lineTo(200, 200);
ctx.lineTo(280, 280);
ctx.stroke();

3 Guarda los cambios y pasa al navegador. Abre la página para revisar el resultado, que debe ser parecido a esta figura

Un recuadro negro y una línea en zig.zag atravesando el canvas.

Puedes ver que la función lineTo es bastante útil a la hora de dibujar líneas o rectángulos. Ahora vamos a cambiar el color de relleno de las líneas en zig-zag y añadiremos un círculo rojo encima del trazo.

4 Vuelve al editor y añade estas líneas de código debajo de las que has escrito en el paso 2:

  ctx.fillStyle = 'rgb(255,0,0)';
ctx.arc(100, 100, 16, 0, Math.PI * 2, false);
ctx.fill();

La primera línea cambia el color de relleno active, que pasa de blanco a rojo. La segunda línea dibuja un círculo completo con su centro situado en las coordenadas (100, 100) y un radio de 16 pixels. Los últimos tres parámetros de la función arc definen la longitud del arco. Los valores  startAngle y endAngle, medidos en radianes, definen los puntos de inicio y final, y el ultimo parámetro, llamado anticlockwise define la dirección en que se dibujará la línea entre estos el punto de inicio y el de término. Por tanto, en este código se define el dibujo de un arco que empieza en la posición 0 (el punto más a la derecha del círculo teórico) y sigue, avanzando en sentido horario, hasta que alcanza el punto 2 π radianes, es decir, una rotación completa de 360 grados, con lo que cierra el círculo. Finalmente, la función fill se encarga de darle color al interior.

5 Selecciona en el menú Archivo – Guardar y pasa al navegador para ver el efecto de estos cambios en pantalla. Como ves, el círculo ha quedado añadido al conjunto de líneas del trazo. Puesto que las líneas y el círculo forman parte del mismo trazado, el relleno de color se aplica a toda el área, no solo al círculo.

Un contorno negro y una figura quebrada rellena en rojo.

6 Si queremos dibujar trazos independientes tenemos que utilizar la función beginPath, que da por concluido el trazo activo y comienza con otro nuevo. Vuelve al editor de textos  y entre la función  fillStyle y arc, inserta las líneas siguientes:

ctx.fillStyle = 'rgb(255,0,0)';
ctx.beginPath();
ctx.arc(100, 100, 16, 0, Math.PI * 2, false);
ctx.fill();
ctx.stroke();

Esta segunda línea, ctx.stroke();, sirve para añadirle un borde al círculo.

7 Guarda el archivo y pasa al navegador para visualizar la página. El dibujo debe aparecer ahora así:

Un recuadro negro, línea en zig-zag y un círculo rojo.

8 Una vez creado el círculo, ahora vamos a añadir otro objeto, en este caso un semicírculo. Escribe estas líneas debajo de las anteriores:

  ctx.beginPath();
ctx.arc(170, 170, 16, 0, Math.PI, true);
ctx.fill();

Con este código iniciamos un nuevo trazo, para dibujar un arco independiente del círculo anterior. Los valores 170,170 son las coordenadas del centro. El valor 16 es el radio, el valor cero es el punto de inicio (startAngle)y el valor de endAngle lo dejamos en  π, con lo que solamente dibujará un semicírculo -180 grados- empezando desde el punto cero. El valor "true" para el parámetro  anticlockwise hace que el semicírculo se desarrolle hacia arriba.

9 Guarda el archivo y visualiza la página en el navegador. Ahora debe verse esta imagen:

Un recuadro negro, línea en zigzag, círculo rojo y semicírculo rojo.

Si dejamos el valor de anticlockwise como "false", el arco se trazaría en sentido horario, es decir un semicírculo curvado hacia abajo.

 

Dibujar figuras con curvas

El elemento canvas nos proporciona dos funciones de dibujo con las que podemos trazar curvas: quadraticCurveTo(cpx, cpy, x, y) y bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y). Ambas funciones utilizan puntos de control para definir la curva del trazo cuando dibuja desde un punto al siguiente.

1 En la carpeta HTML5_05lessons, abre el archivo 05_drawingcurves.html y guarda una copia en la misma carpeta, con el nombre 05_drawingcurves_work.html. El código es el mismo que el del ejercicio inicial donde se definía un elemento canvas y se guardaba una referencia al contexto 2D en una variable para su uso posterior. En este ejercicio vamos a dibujar algunas formas para crear una composición semejante a una flor.

2 En la sentencia if, después de la línea donde se declara la variable ctx, añade este código para dibujar un rectángulo que encuadra el canvas.

  ctx.strokeRect(0, 0, 300, 300);

Es el mismo rectángulo de encuadre que vimos en la sección anterior, que nos sirve de marco de referencia visual para saber dónde está el canvas dentro de nuestra página.

3 Añade las líneas siguientes debajo de la línea del paso anterior, para dibujar el tallo de la flor:

  ctx.fillStyle = 'rgb(0,173,104)';
ctx.moveTo(145, 150);
ctx.quadraticCurveTo(120, 200, 170, 280);
ctx.lineTo(190, 280);
ctx.quadraticCurveTo(125, 190, 155, 150);
ctx.fill();

La primera línea de código cambia el relleno a color verde. Las siguientes líneas definen los puntos iniciales, curvas y líneas de la forma del tallo.

4 Guarda el archivo. Pasa al navegador y muestra la página HTML. Deberás ver esta figura:

La forma de un tallo de flor verde.

Ahora vamos a crear un pétalo de la flor utilizando la función bezierCurveTo que utiliza dos puntos de control, a diferencia del único punto de control que necesita la función quadraticCurveTo del paso anterior. Además tenemos que dibujar una serie de guías utilizando los mismos puntos, para ver mejor cómo opera la función bezierCurveTo.

Puesto que vamos a utilizar una serie de puntos varias veces, lo mejor será guardar los valores de las coordenadas en variables que podremos reutilizar.

5 Vuelve al editor y añade este código debajo de las líneas de paso 3.

  var pt1 = { x: 155, y: 145 };
var pt2 = { x: 93, y: 106 };
var cp1 = { x: 111, y: 154 };
var cp2 = { x: 66, y: 131 };

6 Este código cambia los colores del trazo y el relleno, y nos dibuja el primer pétalo de la flor:

  ctx.fillStyle = 'rgb(115,206,226)';
ctx.strokeStyle = 'rgb(0,111,174)';
ctx.beginPath();
ctx.moveTo(pt1.x, pt1.y);
ctx.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, pt2.x, pt2.y);
ctx.bezierCurveTo(89, 65, 159, 118, 155, 145);
ctx.fill();
ctx.stroke();

Las dos primeras líneas del código cambian el trazo a azul oscuro y el relleno a azul claro. Las siguientes cuatro líneas generan un trazo nuevo mediante la función bezierCurveTo para conseguir curvas suaves. Finalmente, rellena el trazo y dibuja el borde.

7 Guarda el archivo HTML y muéstralo en el navegador para ver los cambios:

La forma de un tallo con un solo pétalo de la flor.

8 Vuelve al editor de textos y añade las siguientes líneas de código debajo de las que has escrito en el paso anterior. Estas nuevas líneas cambian el color del borde y del relleno  y dibujan el centro de la flor que sirve de centro para todo el conjunto:

  ctx.fillStyle = 'rgb(243,237,99)';
ctx.strokeStyle = 'rgb(253,183,58)';
ctx.beginPath();
ctx.arc(155, 145, 10, 0, Math.PI * 2, false);
ctx.fill();
ctx.stroke();

9 Para hacernos una idea de cómo trabaja la función bezierCurveTo con los puntos de control para definir una curva, vamos a añadir una guía utilizando los mismos puntos de la primera curva del pétalo de la flor. Creamos las guías añadiendo las siguientes líneas de código debajo de las del paso anterior:

  ctx.strokeStyle = 'rgb(255,0,0)';
ctx.beginPath();
ctx.arc(pt1.x, pt1.y, 2, 0, Math.PI * 2, false);
ctx.arc(cp1.x, cp1.y, 2, 0, Math.PI * 2, false);
ctx.arc(cp2.x, cp2.y, 2, 0, Math.PI * 2, false);
ctx.arc(pt2.x, pt2.y, 2, 0, Math.PI * 2, false);
ctx.stroke();

La primera línea cambia el trazo a rojo brillante, que veremos por fuera del dibujo del pétalo. Las seis líneas siguientes generan una línea poligonal con circulitos pequeños en cada punto utilizado por la primera curva de Bezier.

10 Guarda el archivo HTML y pasa al navegador para ver cómo queda el diseño tras estos cambios.

La flor con un solo pétalo y las líneas guía de desarrollo de la curva de Bezier.

 

 

Más sobre los puntos de control

 

Una vez terminada la sección de Dibujo de Curvas, y para profundizar más en la forma en que la función bezierCurveTo utiliza los puntos de control, modifica los valores de punto guardados en el paso 5. Si cambias los valores, verás que las guías siguen representando en pantalla los puntos utilizados y la curva se desarrolla hacia esos puntos de control.

Como ejemplo, cambia la coordenada X de la variable cp2 de 66 a 4. La curva de la parte de abajo del pétalo se dibuja ahora hacia el lado más a la izquierda del canvas, mientras que el segundo punto sigue siendo el mismo.

 

Uso de textos dentro del Canvas

Además de líneas y formas, en un canvas podemos dibujar textos. Los tipos de letra, tamaños y grosores se establecen de manera parecida a como se hace con CSS y siguen las mismas reglas con respecto a los tipos de letras, tamaños y grosores disponibles. A diferencia de CSS, no existe aquí el concepto de márgenes internos o externos. En este caso el texto se sitúa en la posición definida por las coordenadas X e Y, que expresan la distancia en píxels horizontal y vertical, con respecto al origen (la esquina superior izquierda del canvas). En esta sección vamos a crear una tarjeta de identificación con tu nombre para practicar con la escritura de textos en el canvas.

1 Abre el archivo 05_addingtext.html que está en la carpeta HTML5_05lessons y guarda una copia del mismo con el nombre 05_addingtext_work.html. Este archivo utiliza la misma plantilla que hemos estado usando hasta ahora, con la excepción de dos rectángulos que sirven como fondo de la tarjeta.

2 Busca la segunda función strokeRect y añade este código para dibujar el texto de cabecera:

  ctx.fillText('HELLO MY NAME IS', 12, 40);

Esta línea de código dibuja un texto, que se indica en el primer parámetro, empezando en las coordenadas indicadas por los parámetros segundo (valor x) y tercero (valor y). Utiliza la fuente por defecto y el color del texto será blanco, heredado del valor de fillStyle que se ha declarado anteriormente en el código.

3 Guarda el archivo HTML y vamos al navegador a ver el resultado, que debería quedar así:

La tarjeta de identificación con un pequeño borde.

4 Para aumentar el tamaño y grosor de la letra, inserta esta línea de código antes de la línea del paso anterior:

  ctx.font = "bold 1.8em sans-serif";
  
ctx.fillText('HELLO MY NAME IS', 12, 40);

Puedes ver que, igual que ocurre con CSS, puedes definir el tamaño de la fuente utilizando valores relativos. En este caso el texto de cabedera será 1,8 veces el tamaño de la fuente del elemento canvas, tamaño que viene heredado del objeto <body> de la página HTML salvo que indiquemos expresamente otra cosa.

5 Guarda el archivo HTML y visualízalo en el navegador, para ver los cambios:

La tarjeta de identificación con una cabecera más grande.

6 Para añadir tu nombre a la tarjeta, inserta otra llamada a fillText. Para conseguir que el texto destaque y parezca escrito a mano, vamos a utilizar una fuente distinta, con un tamaño mayor. Debajo del código del paso 2, añade lo siguiente:

  ctx.fillStyle = 'rgb(0, 0, 0)';
ctx.font = 'bold 84px Comic Sans MS';
ctx.textAlign = 'center';
ctx.fillText('Dianne', 150, 150);

La primera línea cambia el color del texto a negro. La segunda, fija la fuente con un valor absoluto de 84 pixels de altura y el tipo de letra será Comic Sans MS, que es un tipo de letra que imita la escritura manual. La siguiente línea establece el alineamiento horizontal del texto con respecto a la coordenada de posición, y le aplica el valor center. Otras posibilidades de alineamiento horizontal son right y el valor por defecto (left).

7 Guarda el archivo HTML y visualízalo en el navegador:

La tarjeta de identificación con el nombre y una bonita cabecera.

 

Uso de colores, estilos y gradientes

Hasta ahora hemos utilizado colores sólidos, pero la mayoría de objetos reales presentan transiciones suaves de un color a otro. Este tipo de transiciones se reproducen en el canvas utilizando gradientes, que pueden ser de tipo lineal o radial. Además, en esta sección vamos a ver distintas maneras de definir los colores, incluyendo valores de transparencia.

1 Abre el archivo  05_colorsstylesandgradients.html que se encuentra en la carpeta HTML5_05lessons y guarda una copia con el nombre05_colorsstylesandgradients_work.html. El archivo utiliza algunos trazos que sirven para dibujar la silueta de un vaso de Coca Cola.

2 Abre el navegador y visualiza la página HTML: el vaso aparece vacío:

Un vaso de Coca Cola vacío con una sombra negra.

3 Vuelve al editor y debajo de la función strokeRect Cambia el color de fillStyle desde el negro actual a gris, como se indica aquí:

ctx.fillStyle = 'gray';

En las secciones anteriores de esta lección hemos utilizado siempre la notación RGB para definir los colores, pero existen ciertas palabras reservadas que facilitan su uso. Otros términos para designar colores son "red", "blue", "orange", "purple", etc..

4 Guarda el archivo HTML y pasa al navegador para comprobar cómo ha quedado con los cambios.

Un vaso de Coca Cola vacío con una sombra mas clara.

5 También se puede rellenar el vaso con algo que simula la Coca Cola utilizando un gradiente lineal. Después de la sección comentada con el texto "cup inline" y antes de la sección que viene encabezada por el comentario "cup outline", inserta estas líneas de código:

  var lineGrad = ctx.createLinearGradient(150, 81, 150, 268);
lineGrad.addColorStop(0, '#fff');
lineGrad.addColorStop(0.05, '#450c0c');
lineGrad.addColorStop(0.6, '#874040');
lineGrad.addColorStop(1, 'rgba(202, 147, 147, 0.6)');
ctx.fillStyle = lineGrad;

La primera línea define un nuevo pincel de gradiente lineal donde los dos primeros argumentos definen el punto inicial del gradiente y los dos siguientes, el punto final. Para fijar la posición se utilizan coordenadas X e Y, igual que cuando colocábamos rectángulos o círculos.

Las siguientes cuatro líneas definen una serie de "puntos de parada" del gradiente. El primer parámetro define la posición del punto de parada de color relativo al punto de comienzo y finalización del gradiente (donde 0 representa el punto de inicio y 1, el punto final). El segundo parámetro define el color del punto de parada.

El formato hexadecimal se utiliza para declarar los tres primeros colores. El último color queda definido utilizando la función rgba, que amplía la función rgb añadiendo un cuarto parámetro, llamado "alpha" o también "opacidad" del color. La opacidad varía en una escala de 0 a 1, siendo cero el valor de la transparencia completa y 1 la máxima opacidad.

Si quieres conocer mejor los conceptos de la notación de color RGBA, puedes consultar el libro "HTML5 Digital Classroom" y en concreto, la Lección 11 "Aplicando estilos con CSS3".

La última línea cambia el valor de fillStyle al nuevo pincel de gradiente lineal.

6 El último paso será rellenar el contorno del vaso. En la sección que sigue al comentario "cup outline", añade la siguiente línea después de la función stroke.

  ctx.fill();

7 Guarda el archivo HTML y visualízalo en el navegador para ver el resultado:

Un vaso lleno de Coca Cola.

8 Vuelve al editor. Mediante el empleo de varios gradientes radiales vamos a añadir burbujas al vaso de Coca Cola. Después de la línea de código ctx.fill que has escrito en el paso 6, añade estas líneas:

  ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.lineWidth = 2;

La primera cambia el trazo, que pasa del negro por defecto a un blanco semitransparente. La segunda línea cambia la anchura del trazo desde el valor por defecto (1 pixel) a 2 pixels..

9 Debajo de las líneas escritas en los pasos anteriores, añade estas:

  >var radGrad = ctx.createRadialGradient(116, 107, 1, 120, 110, 10);
radGrad.addColorStop(0, 'white');
radGrad.addColorStop(0.9, 'rgba(255, 255, 255, 0)');

La primera línea define un gradiente radial de manera similar a como se hace con el gradiente lineal. Se indican los puntos de inicio y final del gradiente (los parámetros primero y segundo para el punto de inicio, y el tercer y cuarto argumentos, para el punto de finalización). La diferencia principal son los argumentos tercero y sexto, que se utilizan para indicar los radios de los respectivos puntos.

En este ejemplo, el punto de inicio se define en la posición x=116, y=107, con un radio de 1. El punto final queda definido por las coordenadas x=120, y=110, con un radio de 10.

10 Una vez definido el gradiente radial, podemos utilizarlo para rellenar un círculo que representa una burbuja. Después de las líneas de los pasos anteriores, añade estas otras.

  ctx.fillStyle = radGrad;
ctx.beginPath();
ctx.arc(120, 110, 10, 0, Math.PI * 2, false);
ctx.fill();
ctx.stroke();

11 Guarda el archivo HTML y pasa al navegador para ver el resultado de estos cambios:

Un vaso lleno de Coca Cola con una burbuja.

12 Para añadir otra burbuja tenemos que definir otro pincel de gradiente porque las coordenadas han quedado establecidas en una posición absoluta. Si movemos o cambiamos el tamaño de la burbuja, tenemos que mover el pincel también. Debajo del código del paso 10, añade estas líneas:

  radGrad = ctx.createRadialGradient(164, 140, 1, 168, 143, 8);
radGrad.addColorStop(0, 'white');
radGrad.addColorStop(0.9, 'rgba(255, 255, 255, 0)');
ctx.fillStyle = radGrad;
ctx.beginPath();
ctx.arc(168, 143, 8, 0, Math.PI * 2, false);
ctx.fill();
ctx.stroke();

13 Guarda el archivo HTML y pasa al navegador para ver el resultado de estos cambios:

Un vaso lleno de Coca Cola con dos burbujas.

14 Añadiremos una burbuja más para finalizar la composición: debajo del código del paso anterior, añade estas líneas:

  radGrad = ctx.createRadialGradient(127, 185, 1, 130, 188, 6);
radGrad.addColorStop(0, 'white');
radGrad.addColorStop(0.9, 'rgba(255, 255, 255, 0)');
ctx.fillStyle = radGrad;
ctx.beginPath();
ctx.arc(130, 188, 6, 0, Math.PI * 2, false);
ctx.fill();
ctx.stroke();

15 Guarda el archivo HTML y pasa al navegador para ver el resultado de estos cambios:

Un vaso lleno de Coca Cola con tres burbujas.

 

Añadir imágenes

Podemos utilizar una función muy sencilla, llamada drawImage para dibujar una imagen en el canvas. La parte más complicada es asegurarnos de que cuando llamemos a la función, le da tiempo suficiente al navegador para descargar la imagen externa. Una vez que la tiene disponible, la función drawImage nos ofrece una gran flexibilidad a la hora de determinar el tamaño de la imagen y el sitio donde se mostrará.

1 En la carpeta HTML5_05lessons, abre el archivo 05_addingimages.html y guarda una copia en esa misma carpeta con el nombre 05_addingimages_work.html. El archivo está preparado como copia de la plantilla original del canvas que utilizábamos en la primera parte de esta lección.

2 Visualiza desde el sistema operativo el archivo fishlake.jpg que hay en la carpeta images para que veas la imagen que vamos a utilizar en este ejercicio.

3 En la sentencia  if, detrás de la declaración de la variable ctx añade el código siguiente:

  var img = new Image();
img.onload = function(){
}
img.src = 'images/fishlake.jpg';

La primera línea declara un nuevo objeto de tipo imagen y la segunda define una función para el evento onload de la propia imagen. En la última línea se indica el URL del archivo de imagen a utilizar. Una vez que el navegador ha descargado la imagen, hace una llamada a la función de la segunda línea.

4 Dentro de los símbolos de llaves ({, }) de la función onload, añade este código marcado en rojo:

img.onload = function(){
  ctx.drawImage(img, 0, 0);
}

Esta instrucción le indica al canvas que tiene que reproducir la imagen en las coordenadas 0,0.

5 Guarda el archivo HTML y ábrelo en el navegador para ver cómo queda después de estos cambios:

La imagen original aparece está recortada.

La imagen aparece en pantalla, pero recortada porque el tamaño original del archivo es mayor que el tamaño del canvas.

6 Para cambiar el tamaño de la imagen y que quepa en el espacio disponible, vamos a añadir a la función  drawImage una anchura de destino de 300 y una altura de 200 pixels. Modifica la línea que has escrito en el paso cuatro añadiendo estos dos nuevos argumentos a la función:

ctx.drawImage(img, 0, 0, 300, 200);

Con ello le indicamos al canvas que tiene que mostrar la imagen en la posición 0,0 y alterar su tamaño para conseguir una viñeta de 300x200 pixels.

7 Guarda el archivo HTML y visualízalo en el navegador para comprobar el efecto de este cambio:

La imagen del lago después de cambiar el tamaño para que quepa en el espacio disponible.

8 La última variación que haremos sobre la función drawImage es definir la posición de inicio, la anchura y la altura junto con la posición de destino, anchura y altura. Modifica la misma línea del paso cuatro de esta manera:

  ctx.drawImage(img, 287, 132, 100, 100, 0, 0, 300, 300);

Con este cambio le estamos indicando al canvas que tiene que mostrar la imagen en la posición 0,0, con una anchura y altura de 300 pixels, utilizando una porción rectangular de la imagen original que empieza en la posición (287,132) y con una anchura y altura de 100 pixels.

9 Guarda el archivo HTML y vuelve al navegador para visualizar la página HTML y comprobar el efecto de este cambio.

Esta técnica de ampliación de imágenes no es perfecta, ya que el resultado suele presentarse pixelado. En este caso lo vemos solo con fines de demostración.

La imagen del lago, después de ampliar una parte concreta .

 

Uso de las transformaciones

Las transformaciones, combinadas con los estados de dibujo del Canvas nos permiten crear diseños complejos y dinámicos. Como hemos visto en apartados anteriores de esta lección, los cambios globales como los que provocan strokeStyle, fillStyle y lineWidth, se guardan en distintos niveles de cambio de estado que podemos guardar y recuperar más tarde. Los tres tipos de transformaciones (cambio de escala, rotaciones y traslaciones) también se guardan en niveles de cambios de estado globales y se pueden utilizar fácilmente si sabemos cómo hacerlo, empleando las funciones save y restore.

1 En la carpeta HTML5_05lessons, abre el archivo 05_usingtransforms.html y guarda una copia en la misma carpeta con el nombre 05_usingtransforms_work.html. El archivo muestra cinco cuadrados negros en fila, dentro del canvas.

2 Abre el navegador y muestra la página para ver los cuadrados. En realidad, aunque son figuras cuadradas, son "rectángulos" (de lados iguales). Aquí los consideraremos "rectángulos".

Cinco rectángulos.

3 Después del comentario relativo al rectángulo 1 y antes del comentario del rectángulo 2, añade esta línea de código indicada en rojo:

//rectangle1
  ctx.fillRect(30, 120, 40, 40);
ctx.translate(0, 20);
//rectangle2
  ctx.fillRect(80, 120, 40, 40);

La transformación de traslación provoca un desplazamiento para cualquier instrucción posterior, basada en el primer parámetro que corresponde con el valor de desplazamiento sobre el eje X, y el segundo parámetro que es el valor de desplazamiento sobre el eje Y.

4 Guarda el archivo HTML y pasa al navegador para ver el resultado de este cambio.

Los cuatro rectángulos siguientes se han desplazado hacia abajo, al aplicar el desplazamiento sobre el eje Y.

5 Como ves, la transformación de traslación se aplica a todas las instrucciones que aparecen a partir de ella. Del comentario del rectángulo 1 y antes del código que has escrito en el paso 3, añade la siguiente línea, para que el código quede así:

//rectangle1
  ctx.fillRect(30, 120, 40, 40);
  ctx.save();
  ctx.translate(0, 20);

6 Después del comentario del rectángulo 4 y antes del rectángulo 5, añade la línea indicada aquí en rojo:

//rectangle4
  ctx.fillRect(180, 120, 40, 40);
ctx.restore();
//rectangle5
  ctx.fillRect(230, 120, 40, 40);

Con estos cambios, lo que hacemos es que antes de añadir la transformación de traslación, guardamos una "instantánea" del estado global del canvas. Después de dibujar el cuarto rectángulo recuperamos el estado global del canvas a la situación que teníamos antes de que se aplicase la transformación.

7 Guarda el archivo HTML y vuelve al navegador para visualizar la página y comprobar el efecto de estos cambios.

Ahora, solo los tres rectángulos centrales se desplazan hacia abajo sobre el eje vertical.

8 Vuelve al editor, y después del comentario del rectángulo 2 y antes del rectángulo 3, añade estas dos líneas:

 ctx.save();
ctx.rotate(0.19);

La primera guarda otra vez una captura de los valores globales de estado del canvas. La segunda añade una transformación de rotación donde el parámetro corresponde al valor en radianes del giro que queremos aplicar a la figura.

9 Guarda al archivo HTML y visualízalo en el navegador para comprobar los cambios.

Los cuatro últimos rectángulos aparecen más abajo y en el centro, dos de ellos girados levemente.

Al llamar a la función save dos veces y solo una a la función restore, el último rectángulo queda afectado por la transformación de traslación, pero no por la de rotación.

10 En el editor, detrás del comentario del rectángulo tres y antes del rectángulo 4, añade esta línea:

 ctx.restore();

11 Guarda el archivo HTML y vuelve al navegador para ver los cambios en la página.

Tres rectángulos desplazados hacia abajo y uno de ellos girado

12 Debajo de la función restore del paso 6 y antes del rectángulo 5, añade esta línea:

 ctx.scale(0.5, 0.7);

13 Guarda de nuevo el archivo y visualízalo en el navegador:

Tres rectángulos desplazados hacia abajo, uno rotado y otro con un cambio de escala.

 

Creación de un bucle de dibujo

Ahora que tienes unas nociones básicas de dibujo con el canvas, vamos a ver la parte "dinámica" de este elemento. Ciertas funciones de JavaScript como setInterval, nos permiten llamar de manera reiterada a una función de dibujo. En cada llamada podemos modificar ligeramente algún parámetro de la figura y con ello se genera la ilusión de animación.

1 En la carpeta HTML5_05lessons, abre el archivo 05_drawingloop.html y guarda una copia del mismo con el nombre 05_drawingloop_work.html. Este archivo contiene un código que dibuja un bonito cielo nocturno con un platillo volante.

2 Abre el navegador para ver la composición inicial.

Un cielo nocturno y un platillo volante.

3 Revisa el código JavaScript que genera el bucle de dibujo.

Como sucedía en los apartados anteriores, el evento onload del cuerpo de la página llama a la función setup que abre el objeto de imagen y descarga el archivo ufo.png. Fíjate bien en que las variables ctx e img inicialmente se declaran fuera de la función setup. Así conseguimos que estas variables puedan utilizarse desde otras funciones, en este caso las funciones draw y drawbackground.

Después de que se abre la imagen podemos utilizar la función setInterval para llamar a la función draw cada 36 milisegundos.

La función draw después llama a la función drawbackground que se encarga de dibujar el cielo y las estrellas. Acto seguido, llega al comentario de "ufo" y a partir de ahí empieza a dibujar el platillo volador.

4 Debajo de la línea donde se define la variable img y antes de la función setup, añade las líneas de código que se muestran en rojo aquí:

             <script type="text/javascript">
  var ctx;
  var img;
   var x = 0;
  var y = 40;

Estas variables se utilizan para cambiar la posición del platillo volante, pero tendremos que modificar la función drawpara que utilice estas nuevas variables.

5 En la función draw cambia drawImage para que utilice estas nuevas variables y actualice el valor de x de la siguiente manera:

function draw() {
  drawBackground();
  <!--ufo-->
    ctx.drawImage(img, x, y);
    x += 1;
}

6 Guarda el archivo HTML y vuelve al navegador para comprobar el resultado de estos cambios. El platillo volador se mueve ahora lentamente por el canvas.

El platillo volante moviéndose por el cielo nocturno.

7 Para repetir la acción y que el platillo volador vuelva a su sitio cuando se sale del área visible, tenemos que reiniciar la variable x en el momento en que su valor supere la anchura del canvas. Además, podemos variar la velocidad de desplazamiento si aumentamos el incremento de la variable x de esta forma:


x += 3;
if(x > 300){
  x = -50;
}

El valor de la variable x se reinicia a –50 en lugar de cero porque tenemos que tener en cuenta el tamaño de la propia imagen del platillo volante (50 pixels).

8 Guarda el archivo HTML y vuelve al navegador para comprobar el efecto de estos cambios. Cuando el platillo volante llega al borde derecho del canvas, desaparece y reaparece luego en el lado izquierdo.

El platillo volante se mueve por el cielo, sale por el lado derecho y regresa por el izquierdo

9 Para animar imágenes podemos utilizar también la función Math.random de JavaScript. Por ejemplo, podemos cambiar el valor de la variable y de forma aleatoria, y así nuestro platillo volador, al desaparecer por el lado derecho,  volverá por el izquierdo en un lugar imprevisible. En la sentencia if que utilizamos para reiniciar la variable x, inserta la línea que aparece aquí en rojo:

x += 3;
if(x > 300){
  x = -50;
  y = Math.random() * 300;
}

Math.random devuelve un número aleatorio entre 0 y 1 que debe multiplicarse por el número máximo que queremos que nos devuelva. En este caso es 300, que es la altura del canvas.

10 Guarda el archivo HTML y vuelve al navegador para ver el efecto de este cambio. El platillo va moviéndose por el cielo en distintas alturas de forma aleatoria.

El platillo se desplaza cambiando de altura a cada ciclo.

 

Dibujo de gráficas con Canvas

El canvas no solo nos permite diseños estáticos, sino también mostrar contenidos cuya forma puede venir derivada de datos externos. En la siguiente práctica vamos a crear un gráfico de barras tomando como fuentes de datos una matriz simple.

1 Abre el archivo 05_graphing.html en el editor. Guarda una copia en la misma carpeta con el nombre 05_graphing_work.html. Como ves, en el código de este archivo hay una matriz de datos que ya hemos definido con una serie de objetos que representan cada uno de los componentes que vamos a dibujar en el diagrama de barras.

var sampleData = [
   {
          label:"Profit",
          value: 1200
   },
   {
          label:"Expenses",
          value: 800
   },
   {
          label:"Budget",
          value: 1000
   }
];

La matriz se compone de tres objetos, cada uno compuesto a su vez por una etiqueta y un valor. La propiedad "label" contiene el nombre de cada componente. La propiedad "value" define el valor de ese componente, y es el número que utilizaremos en esta práctica para calcular el tamaño relativo de cada barra dentro del diagrama.

2 Añade las siguientes variables para guardar información de color y formato necesaria para el gráfico, directamente debajo de la matriz de datos que hemos comentado en el paso anterior.

var colors = ["rgb(255, 0, 0)", "rgb(0, 255, 0)", "rgb(0, 0, 255)"];
var margin = 30;
var spacing = 5;
var labelFont = "12px sans-serif";

3 En la función window.onload que ya viene definida dentro del archivo HTML, añade este código para indicar el estilo de la fuente y su alineamiento dentro del canvas (las líneas en rojo):

window.onload = function()
{
   var canvas = document.getElementById('barGraph');
   if (canvas.getContext)
   {
          var ctx = canvas.getContext('2d');
          ctx.font = labelFont;
          ctx.textAlign = "center";
   }
}

4 Justo debajo de ese mismo código, incluye tres nuevas variables que van a guardar valores temporales (las indicadas en rojo):

   ctx.textAlign = "center";
   var value, label, highest = 0;

5 Después necesitaremos establecer el valor máximo dentro de nuestra matriz de datos para poder dibujar las barras correctamente. Añade este bucle justo debajo del código que acabas de escribir en el paso anterior, para calcular el valor más alto.

for( var i = 0; i < sampleData.length; i++ )
{
   value = sampleData[i].value;
   if( value && value > highest )
          highest = value;
}

La variable highest va a contener el valor más elevado de la serie de datos de nuestra matriz de ejemplo.

6 Para recordar los valores de medida y posición de cada una de las barras que deben dibujarse, añade un objeto "bar" que va guardar los valores de posición x e y, la anchura y la altura de cada barra. Este código debe añadirse justo debajo del bucle del paso anterior.

var bar = {
   x: margin,
   y: canvas.offsetHeight - margin,
   width: (canvas.offsetWidth - margin * 2 - ( spacing * ( sampleData.length - 1 ) ) ) / sampleData.length,
   height: 0
};

En esta práctica, todas las barras del diagrama tienen la misma anchura. Esta anchura la calculamos dividiendo el ancho total del canvas por el número de elementos de nuestra matriz, añadiéndole todos los márgenes y espacios necesarios. El valor vertical (y) se especifica a partir del borde inferior del canvas, puesto que es donde se empiezan a dibujar las barras.

7 A continuación vamos a crear un bucle para dibujar cada una de las barras del gráfico. Guardamos la etiqueta y el valor del elemento en curso dentro de variables temporales y cambiamos el valor de fillColor activo del canvas a un color distinto, recorriendo la matriz de colores definida anteriormente. Este código deberás añadirlo directamente después del que has escrito en el paso anterior.

for( i = 0; i < sampleData.length; i++ )
{
   value = parseInt(sampleData[i].value);
   label = sampleData[i].label;
   ctx.fillStyle = colors[ i % sampleData.length ];
}

8 La altura de cada barra se obtiene calculando la proporción entre la barra más grande y la altura del canvas. La altura debe ser un valor negativo ya que las barras se vana  dibujar desde abajo hacia arriba partiendo de la base del canvas. Añade este código (la línea destacada en rojo) dentro del bucle del paso anterior:

ctx.fillStyle = colors[ i % sampleData.length ];
bar.height = -(canvas.offsetHeight / highest * value - margin * 2);
}

9 Lo siguiente que necesitamos es desplazar el puntero de dibujo un poco para separar cada barra con respecto a la anterior, y darles un pequeño espacio entre medias, a fin de que aparezcan como columnas verticales independientes. Aumenta el valor de la posición horizontal para cada barra añadiendo a su valor de x  la anchura de cada columna más el tamaño en pixels del espacio de separación. Esto lo hace la línea destacada en rojo:

   bar.height = -(canvas.offsetHeight / highest * value - margin * 2);
   bar.x += bar.width + spacing;
}

10 Escribe la línea siguiente directamente encima de la que acabas de escribir en el paso anterior para dibujar las  barras (la línea en rojo).

   ctx.fillRect( bar.x, bar.y, bar.width, bar.height );
bar.x += bar.width + spacing;

11 Guarda el archivo y ábrelo ahora en el navegador. Podrás ver tres barras con tres colores distintos.

El gráfico muestra los valores en forma de barras, pero no incluye etiquetas.

 

Creación de las etiquetas

Para que el diagrama de barras sea realmente útil tendremos que añadir diversos indicadores visuales que añadan un contexto, tanto para conocer a qué dato refiere cada barra como para saber el valor a que corresponde. Estas etiquetas deben obtenerse a partir del origen de datos.

1   Tras la línea de código añadida en el paso anterior, escribe la siguiente línea de código que genera una etiqueta de texto debajo de cada barra, con el nombre de la columna. Es la línea indicada en rojo aquí:

ctx.fillRect( bar.x, bar.y, bar.width, bar.height );
ctx.fillText( label, bar.x + bar.width/2, bar.y + spacing + parseInt(labelFont) );
bar.x += bar.width + spacing;

La función fillText empezará a escribir en el centro de la columna. Se muestra correctamente en pantalla al aplicarse el alineamiento centrado del texto que hemos visto ya en prácticas anteriores. El espacio vertical se calcula a partir de la altura de la fuente.

2  Guarda el archivo y visualízalo en el navegador. Los colores de las etiquetas coinciden con los de las barras correspondientes.

Cada barra tiene ahora una etiqueta debajo que sirve para identificarla.

Pero ahora, aunque las columnas tienen nombre no sabemos realmente qué valores representan estas barras en términos absolutos. Tendremos que añadir otra serie de etiquetas, en el lado izquierdo, para representar la escala de valores empleada.

3  Debajo de las llaves que delimitan el bucle, añade esta línea de código para reiniciar el color de la fuente del canvas a negro otra vez (la línea destacada en rojo aquí).

for( i = 0; i < sampleData.length; i++ )
{
   ...
}
ctx.fillStyle = "rgb(0,0,0)";

Dibujar textos en vertical seguramente acabará siendo más fácil en el futuro, pero en el momento de redactar este manual, la forma más sencilla de rotar textos consiste en rotar el propio canvas. Por suerte, el canvas nos permite guardar su estado previo, así que solamente tenemos que rotarlo de forma temporal.

4  Creamos un bucle sencillo que se ejecutará tres veces, una por cada barra. Este bucle debe aparecer debajo del código que hemos añadido en el paso anterior.

for( i = 0; i < 3; i++ )
{
}

5 Dentro de este bucle vamos a guardar el estado del canvas antes de aplicar cualquier rotación, lo que hacemos con la siguiente línea (marcada en rojo).

for( i = 0; i < 3; i++ )
{
   ctx.save();
}

6   Vamos a crear una sentencia switch debajo de esta línea. Esta sentencia switch ejecuta una acción distinta dependiendo de la etiqueta que vayamos a dibujar (es el código en rojo).

for( i = 0; i < 3; i++ )
{
   ctx.save();
   switch( i )
   {
   }
}

7  Dentro de la sentencia switch, añade una instrucción case para la primera etiqueta (que se escribirá en la parte inferior del gráfico), la cual va a mostrar el número cero.

for( i = 0; i < 3; i++ )
{
   ctx.save();
   switch( i )
   {
          case 0:
                 label = "0";
                 ctx.textAlign = "right";
                 ctx.translate( margin-spacing-parseInt(labelFont), canvas.offsetWidth - margin );
                 break;
   }
}

Te habrás dado cuenta de que el canvas se desplaza al ejecutar la sentencia case. Aunque no es absolutamente necesario, esto facilita mucho la tarea de dibujar textos en vertical.

8   Debajo de la llave de cierre de la sentencia switch vamos a añadir una instrucción para rotar el canvas 90 grados con la línea de código que se indica aquí en rojo:

for( i = 0; i < 3; i++ )
{
  ctx.save();
   switch( i )
   {
          ...
   }
   ctx.rotate( Math.PI/2 );

9  Ahora, con el canvas girado y colocado, solo tenemos que escribir el texto en él. Añade estas líneas de código que figuran aquí en rojo, justo a continuación de la línea que has escrito en el paso anterior para dibujar texto en el punto donde dejamos nuestro "puntero de dibujo" y después devolvemos al canvas a su estado anterior.

for( i = 0; i < 3; i++ )
{
   ...
   ctx.rotate( Math.PI/2 );
   ctx.fillText( label, 0, 0 );           
   ctx.restore();
}

10  Aunque se mostrará una de las etiquetas, las otras dos aún no están preparadas. Añade dos instrucciones "case" al selector "switch" que has modificado en el paso 7  para indicar las ubicaciones y los textos de las otras dos barras (escribe el  código señalado en rojo):

switch( i )
{
   case 0:
         label = "0";
         ctx.textAlign = "right";
          ctx.translate( margin-spacing-parseInt(labelFont), canvas.offsetWidth - margin );
          break;
   case 1:
         label = (highest/2).toString();
          ctx.textAlign = "center";
          ctx.translate( margin-spacing-parseInt(labelFont),  canvas.offsetHeight /2 );
          break;
   case 2:
          label = (highest).toString();
          ctx.textAlign = "left";
          ctx.translate( margin-spacing-parseInt(labelFont),  margin );
          break;
}

11  Guarda el archivo y comprueba el resultado en el navegador. Ahora ya tenemos un diagrama de barras completo creado a partir de un grupo de datos de ejemplo.

La altura de las columnas ahora se puede comparar con una escala en el lado izquierdo.

 

 

Recursos disponibles para saber más sobre Canvas

 

Las capacidades del elemento canvas han generado una gran expectación entre la comunidad de desarrolladores y diseñadores web. Aquí te indicamos algunos recursos que te ayudaran a investigar más a fondo las posibilidades de este elemento de HTML5.

AI->Canvas

Es un complemento para Illustrator que nos permite exportar creatividades desde la aplicación y utilizar el código canvas resultante en nuestras páginas web. Incluso dispone de soporte integrado para animaciones.
https://visitmix.com/work/ai2canvas/

Lucidchart

Esta aplicación web es muy parecida a las aplicaciones de diagramas como Visio, y está totalmente construida con el elemento canvas. Como extra, podemos exportar los diseños que generemos con ella..
http://www.lucidchart.com/documents/demo 

 

 

Autoestudio

Puedes seguir experimentando con el ejercicio de bucle de dibujo cambiando la imagen animada y la composición del fondo de la escena. Para añadirle más niveles de interacción, cambia la posición de la imagen en movimiento dependiendo de la posición del ratón. Puedes probar a aplicar transformaciones a la composición también, para ver cómo se aplican los efectos en transformaciones múltiples simultáneas.

 

Repaso

Preguntas

1 ¿Cuáles son los requisitos básicos para dibujar con Canvas en HTML5?

2 ¿Cómo se dibuja un círculo en el Canvas?

3 ¿Cómo podemos definir un color semitransparente?

Respuestas

1 Debe definirse e incorporarse un elemento canvas al cuerpo de la página. Las instrucciones de dibujo se aplican después utilizando una referencia al Contexto 2D del elemento canvas.

2 Utilizando la función arc podemos dibujar un círculo completo si indicamos los valores startAngle a cero y endAngle como Math.PI*2. Los ángulos se miden en radianes y la función Math.PI equivale a 180 grados.

3 La función  rgba tiene cuatro parámetros. Los tres primeros representan los valores de color rojo, verde y azul, y pueden tener un valor entre 0 y 255, que modifica la fuerza de cada componente de color. El último parámetro (alpha) admite valores entre cero y uno, y determina el grado de opacidad (cero es transparente y 1 totalmente opaco).


Windows, Bing, PowerPoint, Internet Explorer, Visual Studio, WebMatrix, DreamSpark y Silverlight son marcas registradas o marcas comerciales de Microsoft Corporation en Estados Unidos y/o en otros países. Otros nombres de productos y compañías mencionados aquí pueden ser marcas registradas de sus dueños respectivos.

Las empresas, organizaciones, productos, nombres de dominio, direcciones de correo, logos, personas, lugares y eventos de ejemplo utilizados aquí son ficticios. No se intenta ni debe deducirse ninguna relación con cualquier empresa, organización, producto, nombre de dominio, dirección de correo, logo, persona, lugar o evento real.

La información contenida en este curso se ofrece sin garantía, expresa, implícita o estatutaria. Ni los autores, Microsoft Corporation, ni los distribuidores o comercializadores serán responsables por ningún daño causado o imputado que pueda tener su origen, de manera directa o indirecta, en los contenidos de este curso.

Creado para  Microsoft por Avlade: www.Avlade.com

©2011  Microsoft Corporation.

Ciertas secciones extraídas de la guía HTML5 Digital Classroom están protegidas por copyright 2011 de AGI Training y se utilizan con autorización. Si desea más información sobre el libro HTML5 Digital Classroom visite el sitio web http://www.digitalclassroombooks.com/Web-Design/HTML5-Digital-Classroom-Book.html