Contador Mecánico (Rotary Counter)

Aquí tienes un contador mecánico rotatorio, un ejemplo práctico de cómo combinar diseño y funcionalidad en una aplicación web. Este proyecto está realizado con JavaScript y CSS como elementos básicos y es ideal para diseñadores y estudiantes que buscan entender conceptos clave como la manipulación del DOM, eventos y animaciones. Estás preparado para ser usado como está en una página web, pero puedes personalizarlo y usarlo como base para cornómtros, contador de tiempo, contador de evetnos. Perfecto para inspirarte y aprender a crear interfaces interactivas y dinámicas.

Solución

<body>

<div class="rotaryCnt down">

<div class="digitCnt" id="dig2"></div>

<div class="digitCnt" id="dig1"></div>

<div class="digitCnt" id="dig0"></div>

</div>

</body>

<style>

body {

display: flex;

justify-content: center;

align-items: center;

height: 100vh;

}

.rotaryCnt {

width: fit-content;

display: flex;

--sense: -1; /* -1 down-up (default), +1 up-down */

&.down {

--sense: 1;

}

.digitCnt {

--size: 26px;

display: block;

overflow: hidden;

height: var(--size);

width: var(--size);

border: 1px solid #b7b7b7;

border-left: 3px solid #b7b7b7;

position: relative;

font-size: 20px;

padding: 0 4px;

.blq0, .blq1 {

position: absolute;

display: flex;

justify-content: center;

align-content: center;

flex-wrap: wrap;

top: 0;

left: 0;

height: 100%;

width: 100%;

text-align: center;

}

/*Posición inicial de bloque no visible*/

.blq1 {

top: calc(-1 * var(--sense) * 100%);

}

}

}

.animation {

animation: digit-in 1s linear forwards 1;

}

@keyframes digit-in {

from { transform: translateY(0); }

to { transform: translateY(calc(var(--sense) * var(--size))); }

}

</style>

<script>

function createDigits(name, max, duration) {

let dig;

let blocks=[];

let node = document.getElementById(name);

for (i = 0; i < 2; i++) {

dig = document.createElement("div");

dig.innerText = i.toString().padStart(2, '0');

dig.classList.add("blq" + i);

dig.classList.add("animation");

dig.style.setProperty("animation-duration", duration + "s");

node.appendChild(dig);

blocks.push(dig);

}

dig.toggleBlqs = true; // true down-up, false up-down

dig.maxCount = max;

dig.duration = duration;

dig.digits = blocks;

dig.addEventListener("animationend", endAnim);

}

// Salta cuando el segundo cuadro acaba su animación

// Uno sale y otro entra, alternativamente

function endAnim(event) {

let value = 0;

let maxCount;

let node = event.target;

let digs = node.digits;

digs[0].classList.remove("animation");

digs[1].classList.remove("animation");

maxCount = digs[1].maxCount;

// Inicializar ambos: saliente abajo, entrante dentro

if (digs[1].toggleBlqs) {

updatePosValue(digs[1], digs[0], maxCount);

} else {

updatePosValue(digs[0], digs[1], maxCount);

}

digs[0].classList.add("animation");

digs[1].classList.add("animation");

digs[1].toggleBlqs = !digs[1].toggleBlqs;

}

function updatePosValue(visible, novisible, maxCount) {

let value = 0;

visible.classList.replace("blq1", "blq0");

novisible.classList.replace("blq0", "blq1");

value = parseInt(novisible.innerText) + 2;

value = (value >= maxCount) ? (value - maxCount) : value;

novisible.innerText = value.toString().padStart(2, '0');

}

createDigits("dig0", 10, 1);

createDigits("dig1", 10, 10);

createDigits("dig2", 5, 100);

</script>

Explicación

Este es el código de la pa´gina de muestra donde se situa un contador rotatorio en el centro con tres ruedas que van de 0 a 9. Las velociades van sincronizadas de maner que cunado la primera de la derecha cuente 10 la segunda ya muestre el 01.

Fíjate que los movimientos son continuos, no hay una substitucion e un dígito por el siguiete sino que van apareciendo suavemente en el cuadro del dígito.

El código de la página es bien sencillo: un bloque div para el contador conteniendo y un bloque para cada dígito que quieras usar. En este ejemplo se muestran tres dígitos.

El bloque contenedor de los dígitos lleva la clase rotaryCnt. Por defecto los dígitos van de abajo arriba, si quieres que vayan de arriba abajo como este ejemplo se le añade la clase down.

Cada dígito lleva la clase digitCnt y un atributo id. Este atributo lo identifica y se usará en el script para ir cambiano los valores del contador. Es el bloque que contiene los dígitos que van a rotar.

Con eso tienes el código html listo.

Ahora toca el código CSS. Si te fijas se usa un @keyframe para la animación de los dígitos. Es una animación que mueve el dígito de vertical. La velocidad de la animación se colocará con el script.

El selecor digitCnt tiene posicionamiento relativo, esto es importante para poder situar los dígitos de forma absoluta.

Los selectroes  blq10 y blq1 se van a usar para cada dígito: uno va a contener el dígito que se ve y otro el dígito siguiente. Son los que van a moverse con la propiedad animation. Tiene poscionamiento absoluto dentro del bloque que los contiene (digitCnt)

Los tamañosy sentido del desplazamiento se controlan con variables CSS: --size y --sense

Y lo que queda es el Javascript. La idea es que los dígitos se mueven en vertical, cuando hay un dígito completo visible en el visro, el dígito anterior acaba de salir, no se ve y se le cambia a la posición de partida y el valor que contiene. Una vez hecho esto se reinicia la animación y rl ciclo se repite hasta que se alcanza el límite (10 i va de 0 a 9) donde se reinician los valores.

Fíjate como en las primeras lineas del código se crean los bloques donde se van a mostrar los dígitos. Cada dígito usa dos bloques div: uno estará entrnado en el visor del contador y el otro está saliendo. Este movimiento se realiza con un @keyframe que ves en la hoja de estilos

Se el evento animationEnd lanzado por el navegador cuando acaba una animacion CSS. Cuadno esto ocurre significa que hay un dígito visible, en el visor, y otra ya ha salido. Es cuando se al elmento visible se le pone su posición top actual y al otro se le pone la posición fuera del visor, desde donde va a entrar. Se incremente el valor del contador no visible y se reinicia la animación.

Este paso se hace usando estilos blq0 - blq1, en realidad consiste en intercmabiar las clases bl10 x blq1 en cada bloque del dgito

El contador de cada dígito se inicia con createCounter que lelva tres argumentos: id del bloque donde va el dígito (el de la clase dgitCnt), el número máximo de valores (10 si va de 0 a 9, 60 si va de 0 a 59) y el tiempo de la animacion, en segundos.

Siquieres sincronizar varios dígitos para un reloj por ejemplo pues debes sincronizar los tiempos: si el dígito tendría de tiempo 1s, el de minutos 60s y el de horas 3600s.

Este script se puede usar tal cual in cluso puedes crear un contador realista como el que te muestro en este ejemplo

ejemplo de contador mecánico