Cómo hacer un reloj digital con jQuery y CSS3

Todo empezó la semana pasada cuando vi este bonito regate. Inmediatamente sentí la necesidad de convertirlo en un reloj funcional y compartirlo con los lectores de Tutorialzine. Si quieres saber cómo lo hice, ¡sigue leyendo!

El marcado

El reloj no necesita mucho HTML. Esto se debe a que una gran parte, como los nombres de los días de la semana y el código de los dígitos, se genera dinámicamente. Este es el marcado que debe tener en su página para usar el reloj:

index.html

<div id="clock" class="light">
    <div class="display">
        <div class="weekdays"></div>
        <div class="ampm"></div>
        <div class="alarm"></div>
        <div class="digits"></div>
    </div>
</div>

El elemento principal, el div #clock, contiene .display, que a su vez contiene la lista de días de la semana, la etiqueta AM/PM, el icono de alarma y la hora. Y aquí está el marcado generado para uno de los dígitos:

<div class="zero">
    <span class="d1"></span>
    <span class="d2"></span>
    <span class="d3"></span>
    <span class="d4"></span>
    <span class="d5"></span>
    <span class="d6"></span>
    <span class="d7"></span>
</div>

El elemento .digits contendrá 6 de estos divs con intervalos, uno para cada dígito de la hora. Como puede ver en el fragmento anterior, estos divs obtienen un nombre de clase de cero a nueve (más sobre eso en un segundo), y contiene siete elementos de intervalo con clases únicas. Estos lapsos son los segmentos de los dígitos, como en los relojes digitales de antaño:

Están diseñados completamente con CSS y están configurados para opacity:0 por defecto. La clase asignada a su div principal es lo que los hace visibles. Aquí está el CSS para el cero:

activos/css/estilos.css

/* 0 */

#clock .digits div.zero .d1,
#clock .digits div.zero .d3,
#clock .digits div.zero .d4,
#clock .digits div.zero .d5,
#clock .digits div.zero .d6,
#clock .digits div.zero .d7{
    opacity:1;
}

Todos los segmentos son visibles, excepto el del medio (de lo contrario, sería un 8). He agregado una propiedad de transición CSS3 a todos estos tramos, que anima la opacidad al cambiar entre números.

Hay muchos otros CSS en la hoja de estilos, pero no los presentaré aquí. Creo que la mejor manera de aprender cómo funciona el CSS es inspeccionar el código de trabajo en vivo de la demostración en Firebug, el Inspector de Chrome o las herramientas de desarrollo de su navegador de elección.

El código jQuery

Para que el reloj funcione, tendremos que usar jQuery para generar el marcado para cada uno de los dígitos y configurar un temporizador para actualizar las clases cada segundo. Para facilitarnos la vida, utilizaremos la biblioteca moment.js (consejo rápido) para compensar la falta de funciones nativas de fecha y hora de JavaScript.

activos/js/script.js

$(function(){

    // Cache some selectors

    var clock = $('#clock'),
        alarm = clock.find('.alarm'),
        ampm = clock.find('.ampm');

    // Map digits to their names (this will be an array)
    var digit_to_name = 'zero one two three four five six seven eight nine'.split(' ');

    // This object will hold the digit elements
    var digits = {};

    // Positions for the hours, minutes, and seconds
    var positions = [
        'h1', 'h2', ':', 'm1', 'm2', ':', 's1', 's2'
    ];

    // Generate the digits with the needed markup,
    // and add them to the clock

    var digit_holder = clock.find('.digits');

    $.each(positions, function(){

        if(this == ':'){
            digit_holder.append('<div class="dots">');
        }
        else{

            var pos = $('<div>');

            for(var i=1; i<8; i++){
                pos.append('<span class="d' + i + '">');
            }

            // Set the digits as key:value pairs in the digits object
            digits[this] = pos;

            // Add the digit elements to the page
            digit_holder.append(pos);
        }

    });

    // Add the weekday names

    var weekday_names = 'MON TUE WED THU FRI SAT SUN'.split(' '),
        weekday_holder = clock.find('.weekdays');

    $.each(weekday_names, function(){
        weekday_holder.append('<span>' + this + '</span>');
    });

    var weekdays = clock.find('.weekdays span');

    // Run a timer every second and update the clock

    (function update_time(){

        // Use moment.js to output the current time as a string
        // hh is for the hours in 12-hour format,
        // mm - minutes, ss-seconds (all with leading zeroes),
        // d is for day of week and A is for AM/PM

        var now = moment().format("hhmmssdA");

        digits.h1.attr('class', digit_to_name[now[0]]);
        digits.h2.attr('class', digit_to_name[now[1]]);
        digits.m1.attr('class', digit_to_name[now[2]]);
        digits.m2.attr('class', digit_to_name[now[3]]);
        digits.s1.attr('class', digit_to_name[now[4]]);
        digits.s2.attr('class', digit_to_name[now[5]]);

        // The library returns Sunday as the first day of the week.
        // Stupid, I know. Lets shift all the days one position down, 
        // and make Sunday last

        var dow = now[6];
        dow--;

        // Sunday!
        if(dow < 0){
            // Make it last
            dow = 6;
        }

        // Mark the active day of the week
        weekdays.removeClass('active').eq(dow).addClass('active');

        // Set the am/pm text:
        ampm.text(now[7]+now[8]);

        // Schedule this function to be run again in 1 sec
        setTimeout(update_time, 1000);

    })();

    // Switch the theme

    $('a.button').click(function(){
        clock.toggleClass('light dark');
    });

});

El fragmento de código más importante aquí es el update_time función. Dentro de él, obtenemos la hora actual como una cadena y la usamos para completar los elementos del reloj y establecer las clases correctas para los dígitos.

¡Con esto nuestro reloj digital está listo! Consulte la siguiente parte, donde agregamos soporte para configurar alarmas y reproducirlas con audio HTML5.