Blog personal de IT, viajes y otros hobbies

donald trump countdown

Reto Javascript 30 – Ejercicio #2

Wow, estos tutoriales me están encantando por el simple hecho de ver lo simple que puede ser programar algo que a simple vista parece ser complejo pero que puede realizarse mezclando un gran conjunto de conocimientos básicos. En este caso CSS y Javascript. Para el ejercicio número dos del reto Javascript 30 hay que desarrollar un reloj y se basa meramente en las funciones transform: rotate() de CSS y setInterval() de Javascript. No te preocupes si no sabes de lo que estoy hablando más abajo voy a detallar el código.

Como siempre quiero ir un poco más allá de lo que propone el ejercicio para hacer la práctica más divertida y de paso poder compartirlo con ustedes ¿Un simple reloj? No way. Estuve dándole vueltas al coco hasta que llegué a la idea de implementar el típico reloj de Mickey Mouse que mueve las manos pero con un toque extra, y ese toque extra fue mezclarlo con Donald Trump. De ahí nació el proyecto «Donald Trump Countdown» porque seamos sinceros, nadie sabe cómo llegó este energúmeno al poder (sí lo sabemos, gracias al voto de millones de energúmenos) pero sí que lo queremos fuera de cuanto antes. Entonces una cuenta regresiva sería mi ejercicio para estos días.

donald trump countdown
Interfaz gráfica del ejercicio: «Donald Trump Countdown»

Vamos a destripar un poco el código por partes para ver cómo funciona este reloj, empecemos por el cambio de la cabeza de Donald Trump:

¿Cómo cambia la cabeza de Donald Trump al ritmo de los segundos?

El corazón de este código se debe a la función Javascript setInterval(). Esta función nos permite ejecutar una función cada x milisegundos. Veamos un ejemplo utilizando el código del ejercicio:

setInterval(tick, 1000);

Este simple código Javascript ejecutará una función llamada tick cada 1000 milisegundos que equivale a 1 segundo. Ahora veamos qué código implementa la función tick para cambiar la cabeza de Donald Trump a cada segundo.

<!-- DT Faces -->
<img src="img/dt-00.png" class="dt-face dt-00 active" data-key="0" alt="Donald Trump">
<img src="img/dt-01.png" class="dt-face dt-01" data-key="1" alt="Donald Trump">
<img src="img/dt-02.png" class="dt-face dt-02" data-key="2" alt="Donald Trump">
<img src="img/dt-03.png" class="dt-face dt-03" data-key="3" alt="Donald Trump">
<img src="img/dt-04.png" class="dt-face dt-04" data-key="4" alt="Donald Trump">
<img src="img/dt-05.png" class="dt-face dt-05" data-key="5" alt="Donald Trump">
<img src="img/dt-06.png" class="dt-face dt-06" data-key="6" alt="Donald Trump">
<img src="img/dt-07.png" class="dt-face dt-07" data-key="7" alt="Donald Trump">
<img src="img/dt-08.png" class="dt-face dt-08" data-key="8" alt="Donald Trump">
<img src="img/dt-09.png" class="dt-face dt-09" data-key="9" alt="Donald Trump">

En el html podemos ver que agregamos todas las imágenes de las caras de Donald Trump. Cada una de ellas tiene un atributo data-key que utilizaremos para activar o desactivar según vayan pasando los segundos. Por otra parte vemos que el primero y a diferencia del resto tiene una clase extra llamada active. Esta clase es la que hace visible la imagen ya que por defecto todas están ocultas como puede observarse en los estilos de CSS del siguiente código.

.dt-face {
 display: none;
 position: absolute;
 z-index: 80;
}
.dt-face.active {
 display: blocK
}
function tick(){
    // Set the time
    const now = new Date();
    const seconds = now.getSeconds();
    // Remove head
    var faces = document.getElementsByClassName("dt-face");
    var facesCount = faces.length; // Gracias Carlos por esta mejora
    for (var i = 0; i < facesCount; i++) {
        faces[i].classList.remove("active");
    }
    // Get the specific head and activate it
    var face = document.querySelector("[data-key='" + seconds%faces.length + "']");
    face.classList.add("active");
}

A cada segundo el setInterval() ejecuta la función tick().  En la función declarmos un par de variables para guardar la fecha y los segundos actuales. Paso seguido quitamos la clase active a todos los elementos del documento que tengan la clase dt-face, de esa manera nos aseguramos que ninguna cara está visible. En el tercer bloque de código activamos la cara correspondiente según el segundo en el que se está ejecutando la función. Para ello utilizamos el operador mod (%) que nos devuelve el resto de la división entre los segundos actuales y la cantidad de elementos en el array de faces. De esta manera podemos despreocuparnos de cuantas caras tenga Donald Trump, a cada segundo siempre se activará la siguiente y al final de la lista volverá a comenzar.

donald trump faces

¿Cómo mueves las agujas?

Utilizando la misma función tick guardo en una variable el valor de los minutos y el de las horas. Luego realizo una división por 12 horas y por los 60 minutos respectivamente para encontrar su correlación con los grados que debo rotar las agujas. Una vez que obtengo ese número aplico la función transform: rotate() de CSS.

function tick(){
    // Set the time
    const now = new Date();
    const seconds = now.getSeconds();
    const minutes = now.getMinutes();
    const minutesDegrees = (minutes/60) * 360;
    minuteHand.style.transform = `rotate(${minutesDegrees}deg)`;
    const hours = now.getHours();
    const hoursDegrees = (hours/12) * 360;
    hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
}

En las líneas 6 y 9 se puede observar los cálculos para obtener los grados que debo girar las agujas para que apunten en las horas y minutos adecuados. Un punto muy importante: las agujas, o cualquier elemento que se quiera rotar, siempre tendrá el eje en el centro vertical y horizontal. Para el tipo de rotación de las agujas del reloj se debe modificar la propiedad transform-origin.

El código completo

Pueden descargarse el código completo desde mi cuenta de Github, ejecutar directamente el fichero index.html en su navegador y modificarlo a vuestro antojo.

Anterior

Me apunté al reto Javascript en 30 días

Siguiente

Filtros CSS

  1. Muy bueno Mauricio, y lo que es mejor además muy divertido, si me permites un pequeño comentario,, simplemente la cuenta de elementos faces no la deberías hacer en el bucle, aunque en este caso no se notaría la diferencia pero se está ejecutando la cuenta con cada iteracción, debería hacer la cuenta y después realizar el bucle.

    En vez de:
    for (var i = 0; i < faces.length; i++) {

    Poner:
    var longitud = faces.length;
    for (var i = 0; i < longitud; i++) {

    Mi enhorabuena por esta serie de retos (el de Rajoy se sale).

    • Tienes mucha razón, si bien soy un apasionado de la refactorización nunca había pensado en implementar esta sugerencia para los bucles for.

      Muchas gracias Carlos.

Deja una respuesta

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

Funciona con WordPress & Tema de Anders Norén