HTML5 (HyperText Markup Language, versión 5) es la quinta revisión importante del lenguaje básico de la World Wide Web, HTML. Es el lenguaje de marcado predominante para la elaboración de páginas web que describe y traduce la estructura e información en forma de texto, y complementa el texto con objetos tales como imágenes. HTML5 aún se encuentra en modo experimental, lo cual indica la misma W3C, aunque ya es usado por múltiples desarrolladores web debido a sus avances, mejoras y ventajas. Al no ser reconocido en viejas versiones de navegadores por sus nuevas etiquetas, se le recomienda al usuario común actualizar a la versión más nueva, para poder disfrutar de todo el potencial que provee HTML5.



HTML5 establece una serie de nuevos elementos y atributos que reflejan el uso típico de los sitios web modernos. Algunos de ellos son técnicamente similares a las etiquetas <div> y <span>, pero tienen un significado semántico, como por ejemplo <nav> (bloque de navegación del sitio web) y <footer>. Otros elementos proporcionan nuevas funcionalidades a través de una interfaz estandarizada, como los elementos <audio> y <video>. Algunos elementos de HTML 4.01 han quedado obsoletos, incluyendo elementos puramente de presentación, como <font> y <center>, cuyos efectos son manejados por el CSS. También hay un renovado énfasis en la importancia del scripting DOM para el comportamiento de la Web 2.0.

HTML5 Incorpora etiquetas (canvas 2D y 3D, audio, video) con codecs para mostrar los contenidos multimedia capaces de renderizar en los navegadores más importantes (Mozilla, Chrome, Opera, Safari e IE). Actualmente hay una lucha entre imponer codecs libres (WebM + VP8) o privados (H.264/MPEG-4 AVC). También incorpora etiquetas para manejar grandes conjuntos de datos: Datagrid, Details, Menu y Command (permiten generar tablas dinámicas que pueden filtrar, ordenar y ocultar contenido en el cliente); nuevos tipos de datos en los formularios (email, number, url, datetime, etc.) y facilidades para validar el contenido sin JavaScript; visores MathML (fórmulas matemáticas) y SVG (gráficos vectoriales), aunque se deja abierto a poder interpretar otros lenguajes XML; y funcionalidades "Drag & Drop" para arrastrar objetos.

Entre sus novedades, lo que para mi gusto más se destaca son las etiquetas <canvas>. Utilizando canvas es posible crear gráficos 2D y 3D a partir de código JavaScript. Esta funcionalidad permite reemplazar imágenes PNG o JPG por gráficos y dibujos creados en tiempo de ejecución. Esto es, desde PHP (o cualquier otro lenguaje CGI en el servidor Web) es posible crear código JavaScript que será ejecutado en el cliente (Web browser) para crear un gráfico dinámico. A su vez, este código JavaScript para dibujar el gráfico puede ser alterado para modificar el gráfico ante un determinado evento, sin necesidad de recargar la página.

Una ventaja adicional que tienen las etiquetas canvas, es que reducen el tamaño en disco y tiempo de descarga de las páginas Web. Esto se debe a que el código fuente (PHP/JavaScript) es texto plano y ocupa mucho menor espacio que las imágenes, lo cual mejora notablemente los tiempos de transferencia (a cambio de un mayor costo de ejecución en el Web browser cliente, ya que debe encargarse del proceso de renderizado o dibujado).

En este artículo presento un par de ejemplos para dibujar relojes con segundero y minutero en movimiento utilizando <canvas> y funciones Javascript de HTML5.

Aclaración: No voy a hacer un repaso de trigonometría, teorema de Pitágoras, funciones seno y coseno, etc. en este artículo. Para ello remitirse a Wikipedia en español (que por cierto incluye un bonito GIF animado). Estos conceptos son fundamentales para comprender el código Javascript que se presenta a continuación.

La función Javascript más importante que se utiliza para dibujar estos relojes es arc, la cual se encuentra explicada en el siguiente tutorial de canvas de Mozilla.

Cronómetro

El primer ejemplo se trata de un cronómetro. Un reloj que comienza a contar tiempo a partir de cero:

0:00

Su navegador no permite utilizar canvas.

Código Javascript del cronómetro:

function retornarLienzo(x) {
  
var canvas = document.getElementById(x);
  
if (canvas.getContext) {
    
var lienzo = canvas.getContext("2d");   
    
return lienzo;
  
} else
    
return false;
}

function dibujar() {

  
var lienzo=retornarLienzo("lienzo");
  
if (lienzo) {

    
// Valor del reloj
    
var minuto = document.getElementById("minuto").innerHTML;
    
var segundo = document.getElementById("segundo").innerHTML;

    
// Longitudes de las manecillas del reloj
    
var minutero = 60;
    
var segundero = 80;
    
var radio = 100;

    
// Defino lí­mites en pí­xeles
    
var minx = 50;
    
var maxx = 250;
    
var miny = 50;
    
var maxy = 250;

    
// Centro del recuadro
    
cx = minx+(maxx-minx)/2;
    
cy = miny+(maxy-miny)/2;

    
// Borrar lienzo
    
lienzo.clearRect(0,0,300,300);
    
lienzo.strokeStyle="rgb(0,0,0)";
    
lienzo.lineWidth = 1;

    
// Dibujar el cí­rculo del reloj
    
lienzo.beginPath();
    
lienzo.arc(cx,cy,radio,0,Math.PI*2,false);
    
lienzo.stroke();

    
// Dibujar el centro de las manecillas
    
lienzo.beginPath();
    
lienzo.arc(cx,cy,5,0,Math.PI*2,false);
    
lienzo.fill();

    
// Dibujar el minutero
    
lienzo.beginPath();
    
lienzo.lineWidth = 2;
    
lienzo.moveTo(cx,cy); // posiciono el lápiz en el centro del recuadro
    
angulo = 2*Math.PI * (minuto/60); // calculo el ángulo del minutero
    
// Calculo los desplazamientos para el minutero
    
dx = minutero * Math.sin(angulo);
    
dy = -minutero * Math.cos(angulo);
    
lienzo.lineTo(cx+dx,cy+dy);
    
lienzo.stroke();
    
lienzo.lineWidth = 1;

    
// Dibujar el segundero
    
lienzo.beginPath();
    
lienzo.moveTo(cx,cy); // posiciono el lápiz en el centro del recuadro
    
angulo = 2*Math.PI * (segundo/60); // calculo el ángulo del segundero
    
// Calculo los desplazamientos para el segundero
    
dx = segundero * Math.sin(angulo);
    
dy = -segundero * Math.cos(angulo);
    
lienzo.lineTo(cx+dx,cy+dy);
    
lienzo.stroke();

    
// Dibujar los marcadores cada 1 minuto
    
lienzo.beginPath();
    
for (i=0; i&lt;60; i+=1) {
        
lienzo.moveTo(cx,cy);
        
angulo = 2*Math.PI * (i/60);
        
px = (radio-5) * Math.sin(angulo);
        
py = -(radio-5) * Math.cos(angulo);
        
lienzo.moveTo(cx+px,cy+py);
        
dx = 5 * Math.sin(angulo);
        
dy = -5 * Math.cos(angulo);
        
lienzo.lineTo(cx+px+dx,cy+py+dy);
    
}
    
lienzo.stroke();

    
// Dibujar los marcadores cada 5 minutos
    
lienzo.beginPath();
    
lienzo.lineWidth = 2;
    
//lienzo.strokeStyle="rgb(0,0,0)";
    
for (i=0; i&lt;60; i+=5) {
        
lienzo.moveTo(cx,cy);
        
angulo = 2*Math.PI * (i/60);
        
px = (radio-5) * Math.sin(angulo);
        
py = -(radio-5) * Math.cos(angulo);
        
lienzo.moveTo(cx+px,cy+py);
        
dx = 5 * Math.sin(angulo);
        
dy = -5 * Math.cos(angulo);
        
lienzo.lineTo(cx+px+dx,cy+py+dy);
    
}
    
lienzo.stroke();

  
}
}

dibujar();

function actualizar_reloj() {
    
minuto = parseInt(document.getElementById("minuto").innerHTML);
    
segundo = parseInt(document.getElementById("segundo").innerHTML);

    
if (segundo == 59) {
        
segundo = "00";
        
minuto = minuto + 1;
    
}
    
else {
        
segundo = segundo + 1;
        
if (segundo &lt; 10) {
            
segundo = "0" + segundo;
        
}
    
}
    
document.getElementById("minuto").innerHTML = minuto;
    
document.getElementById("segundo").innerHTML = segundo;
    
dibujar(); // Renderizo el reloj
}

var contador = window.setInterval(actualizar_reloj,1000);

La función actualizar_reloj es invocada automáticamente cada 1 segundo (1000 milésimas de segundo). Luego de actualizar el valor numérico del reloj, invoca a la función dibujar() para renderizar el reloj en el lienzo, cuyo id es "lienzo". La función dibujar() está explicada en los comentarios, utiliza trigonometría básica para dibujar los arcos y líneas rectas. El principio fundamental es dividir el perímetro del reloj en 60 unidades (segundos o minutos, según corresponda) los cuales coinciden con 2*π en radianes (360°). En cada segundo, calcula el ángulo (en radianes) entre el segundo actual y el segundo 0 (idem para los minutos). Utilizando estos ángulos, junto con las funciones matemáticas seno (Math.sin()) y coseno (Math.cos()), se calculan los desplazamientos para dibujar las manecillas del reloj y los marcadores.

Cuenta regresiva

El segundo ejemplo es un reloj que retrocede en forma de cuenta regresiva. Al finalizar (llegar a cero) detiene el reloj y muestra un mensaje:

1:59

Su navegador no permite utilizar canvas.

Código Javascript para implementar la cuenta regresiva:

function retornarLienzo(x) {
  
var canvas = document.getElementById(x);
  
if (canvas.getContext) {
    
var lienzo = canvas.getContext("2d");
    
return lienzo;
  
} else
    
return false;
}

function dibujar2() {

  
var lienzo=retornarLienzo("lienzo2");
  
if (lienzo) {

    
// Valor del reloj
    
var minuto = document.getElementById("minuto2").innerHTML;
    
var segundo = document.getElementById("segundo2").innerHTML;

    
// Longitudes de las manecillas del reloj
    
var minutero = 60;
    
var segundero = 80;
    
var radio = 100;

    
// Defino límites en pí­xeles
    
var minx = 50;
    
var maxx = 250;
    
var miny = 50;
    
var maxy = 250;

    
// Centro del recuadro
    
cx = minx+(maxx-minx)/2;
    
cy = miny+(maxy-miny)/2;

    
// Borrar lienzo
    
lienzo.clearRect(0,0,300,300);
    
lienzo.strokeStyle="rgb(0,0,0)";
    
lienzo.lineWidth = 1;

    
// Dibujar el círculo del reloj
    
lienzo.beginPath();
    
lienzo.arc(cx,cy,radio,0,Math.PI*2,false);
    
lienzo.stroke();

    
// Dibujar los segundos restantes
    
lienzo.beginPath();
    
lienzo.fillStyle="rgb(128,196,255)";
    
lienzo.moveTo(cx,cy); // posiciono el lápiz en el centro del recuadro
    
angulo = 2*Math.PI * (segundo/60); // calculo el ángulo del segundero
    
lienzo.arc(cx,cy,radio,-Math.PI/2,angulo-Math.PI/2,false);
    
lienzo.lineTo(cx,cy);
    
lienzo.fill();

    
// Dibujar los minutos restantes
    
lienzo.beginPath();
    
lienzo.fillStyle="rgb(128,128,255)";
    
lienzo.moveTo(cx,cy); // posiciono el lápiz en el centro del recuadro
    
angulo = 2*Math.PI * (minuto/60); // calculo el ángulo del segundero
    
lienzo.arc(cx,cy,radio,-Math.PI/2,angulo-Math.PI/2,false);
    
lienzo.lineTo(cx,cy);
    
lienzo.fill();

    
// Dibujar los marcadores cada 1 minuto
    
lienzo.beginPath();
    
for (i=0; i&lt;60; i+=1) {
        
lienzo.moveTo(cx,cy);
        
angulo = 2*Math.PI * (i/60);
        
px = (radio-5) * Math.sin(angulo);
        
py = -(radio-5) * Math.cos(angulo);
        
lienzo.moveTo(cx+px,cy+py);
        
dx = 5 * Math.sin(angulo);
        
dy = -5 * Math.cos(angulo);
        
lienzo.lineTo(cx+px+dx,cy+py+dy);
    
}
    
lienzo.stroke();

    
// Dibujar los marcadores cada 5 minutos
    
lienzo.beginPath();
    
lienzo.lineWidth = 2;
    
//lienzo.strokeStyle="rgb(0,0,0)";
    
for (i=0; i&lt;60; i+=5) {
        
lienzo.moveTo(cx,cy);
        
angulo = 2*Math.PI * (i/60);
        
px = (radio-5) * Math.sin(angulo);
        
py = -(radio-5) * Math.cos(angulo);
        
lienzo.moveTo(cx+px,cy+py);
        
dx = 5 * Math.sin(angulo);
        
dy = -5 * Math.cos(angulo);
        
lienzo.lineTo(cx+px+dx,cy+py+dy);
    
}
    
lienzo.stroke();

  
}
}

dibujar2();

function cuenta_regresiva() {
    
minuto = document.getElementById("minuto2").innerHTML;
    
segundo = document.getElementById("segundo2").innerHTML;

    
if (segundo == 0) {
        
if (minuto == 0) {
            
document.getElementById("mensaje2").innerHTML = "Fin de la cuenta regresiva";
            
window.clearInterval(contador2);
        
}
        
else {
            
segundo = 59;
            
minuto = minuto - 1;
        
}
    
}
    
else {
        
segundo = segundo - 1;
        
if (segundo &lt; 10) {
            
segundo = "0" + segundo;
        
}
    
}
    
document.getElementById("minuto2").innerHTML = minuto;
    
document.getElementById("segundo2").innerHTML = segundo;
    
dibujar2(); // Renderizo el reloj
}

var contador2 = window.setInterval(cuenta_regresiva,1000);

El principio de funcionamiento es el mismo excepto que, en lugar de dibujar las manecillas del reloj, llena el reloj con un color de acuerdo a la cantidad de tiempo restante, en forma de gráfico de torta. Para realizar este tipo de dibujo se debe utilizar una combinación de llamadas a arc(), moveTo(), lineTo() y fill().

Cabe destacar que en ambos ejemplo se renderiza completamente el lienzo en cada segundo, lo cual impone una carga de procesamiento en el browser cliente. Para utilizar estos ejemplos en un sitio en producción es necesario modificar el código para que se renderice de forma más eficiente. Es decir, en cada segundo sólo se debe modificar la posición de las manecillas, o la porción de tiempo, y no renderizar nuevamente los marcadores, decorados, etc.

El objetivo de este artículo es demostrar cómo se utilizan las funciones HTML5 más comunes y de qué forma es posible dibujar arcos y líneas de forma sencilla. Espero que sea de gran utilidad, sobretodo para quienes necesitan mostrar un reloj online en su sitio o página Web.


Tal vez pueda interesarte


Compartí este artículo