Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions README_ES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
logo_ironhack_blue 7
# LAB | JS IronChronometer
![giphy (1)]()

## Introducción
En este laboratorio, vamos a crear un cronómetro. Los cronómetros se usan muy comúnmente en deportes: carreras de coches, atletismo, etc. ¿Por qué no practicar un poco nuestros conocimientos de JavaScript y manipulación del DOM creando nuestro propio IronChronometer? Luego podremos usarlo para ver cuántos minutos y segundos tardamos en completar cualquiera de nuestros labs. Suena bien, ¿no?

¡Vamos allá!

### Estas son nuestras metas:
- Nuestro cronómetro tendrá una pantalla LCD, donde veremos los minutos y segundos avanzar.
- También tendrá dos botones distintos que cambiarán su comportamiento dependiendo del estado del cronómetro. Por ejemplo, el botón de start se convertirá en stop cuando el cronómetro esté en marcha.
- Como extra, añadiremos una funcionalidad *split* que nos permitirá registrar el tiempo en el momento en que presionemos el botón.

¡Vamos a ello!

Para ver cómo debería verse tu versión final, consulta esta demo.

## Requisitos
1. Haz un fork de este repositorio.
2. Clónalo en tu máquina.

## Entrega
Una vez termines, ejecuta los siguientes comandos:

```bash
git add .
git commit -m "solve iteration x, y, z"
git push origin master
```

Crea un Pull Request para que tus TAs puedan revisar tu trabajo.

## Instrucciones

### Archivos proporcionados:

```
├── README.md
├── index.html
├── javascript
│ ├── chronometer.js
│ └── index.js
├── styles
│ ├── fonts
│ │ └── ds-digi.ttf
│ └── style.css
└── tests
└── chronometer.spec.js
```

La hoja de estilos ya incluye la fuente `ds-digi`, que nos permite simular una pantalla LCD clásica.

El diseño visual ya está creado para que puedas concentrarte en la lógica JavaScript.

## Partes del lab

- Parte 1: lógica (archivo `javascript/chronometer.js`)
- Parte 2: manipulación del DOM (archivo `javascript/index.js`)

### Iteración 1: La lógica

#### Clase Chronometer

Constructor sin argumentos:
- `currentTime` inicia en 0
- `intervalId` inicia en null

#### Método start(callback)

- Usa `setInterval` para aumentar `currentTime` cada segundo.
- Guarda el ID del intervalo en `intervalId`.
- Si se pasa un callback, ejecútalo en cada tick.

💡 Consejo: Usa arrow functions para mantener `this`.

#### Método getMinutes()

- Devuelve los minutos completos transcurridos (`Math.floor(currentTime / 60)`)

#### Método getSeconds()

- Devuelve los segundos desde el inicio del minuto actual (`currentTime % 60`)

#### Método computeTwoDigitNumber(value)

- Devuelve una cadena con dos dígitos. Ej: `7 → "07"`

#### Método stop()

- Usa `clearInterval(this.intervalId)`

#### Método reset()

- Resetea `currentTime` a 0

#### Método split()

- Devuelve un string `mm:ss` usando los métodos anteriores

---

### Iteración 2: Manipulación del DOM

Trabaja en `index.js`. No modifiques `index.html` o `style.css`.

#### Botones y estados

| Estado | Botón | Texto | Clase |
|--------|-------|-------|--------|
| Detenido | btnLeft | START | btn start |
| Detenido | btnRight | RESET | btn reset |
| En marcha | btnLeft | STOP | btn stop |
| En marcha | btnRight | SPLIT | btn split |

#### Comportamiento

- Al hacer clic en btnLeft:
- Si tiene clase `start`, cambia a `STOP` y btnRight a `SPLIT`, y llama a `start()`
- Si tiene clase `stop`, cambia a `START` y btnRight a `RESET`, y llama a `stop()`

- Actualiza el texto y clase con `.innerHTML` y `.className`

- Instancia `Chronometer` y actualiza la pantalla cada segundo

---

### Iteración 3: Tiempo Split

#### HTML & CSS

Usa la lista ordenada con id `splits` para guardar los tiempos

#### JavaScript

- Crea un elemento `<li>` cada vez que se pulse el botón SPLIT
- Asigna clase `list-item`
- Su contenido es el resultado de `chronometer.split()`
- Añádelo al elemento `#splits`

---

### Iteración 4: Reset

- Reinicia los valores a cero
- Elimina todos los elementos `<li>` del `#splits`

---

### BONUS Iteración 5: Milisegundos

- Modifica HTML/CSS para mostrar décimas y centésimas
- Añade lógica en JavaScript para contar milisegundos
- Añádelos al método `split()`
- Reinícialos en `reset()`

---

## Prueba tu código

Este lab incluye tests automáticos.

```bash
cd lab-javascript-chronometer
npm install
npm run test:watch
```

Abre `lab-solution.html` con Live Server para ver los resultados.

🔔 *Nota*: Esta vista no permite ver los `console.log`. Para eso, abre `index.html` con Live Server.

---

## ¡Feliz programación! ❤️
45 changes: 37 additions & 8 deletions javascript/chronometer.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,63 @@
class Chronometer {
constructor() {
// ... your code goes here
this.currentTime = 0;
this.milliseconds = 0
this.intervalId = null;
this.millisecondsIntervalId = null
}

start(callback) {
// ... your code goes here
this.intervalId = setInterval(() => {
this.currentTime++;

const { mainDisplay } = callback?.() || {};
if (mainDisplay) mainDisplay();
}, 1000);

const { millisDisplay } = callback?.() || {};
if (millisDisplay) {
this.millisecondsIntervalId = setInterval(() => {
this.milliseconds = (this.milliseconds + 1) % 100;
millisDisplay();
}, 10);
}
}

getMinutes() {
// ... your code goes here
return Math.floor(this.currentTime / 60);

}

getSeconds() {
// ... your code goes here
return Math.floor(this.currentTime % 60);
}

getMilliseconds() {
return this.milliseconds;
}

computeTwoDigitNumber(value) {
// ... your code goes here
return (value < 10) ? `0${value}` : `${value}`
}

stop() {
// ... your code goes here
clearInterval(this.intervalId);
this.intervalId = null;
clearInterval(this.millisecondsIntervalId);
this.millisecondsIntervalId = null;

}

reset() {
// ... your code goes here
this.currentTime = 0;
this.milliseconds = 0;
}

split() {
// ... your code goes here
const minutes = this.computeTwoDigitNumber(this.getMinutes());
const seconds = this.computeTwoDigitNumber(this.getSeconds());
const milliseconds = this.computeTwoDigitNumber(this.getMilliseconds())
return `${minutes}:${seconds}:${milliseconds}`;
}
}

Expand Down
74 changes: 61 additions & 13 deletions javascript/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,100 @@ const milUniElement = document.getElementById('milUni');
const splitsElement = document.getElementById('splits');

function printTime() {
// ... your code goes here
return{
mainDisplay: () => {
printMinutes();
printSeconds();
},
millisDisplay: () => {
printMilliseconds();
}

}

}

function printMinutes() {
// ... your code goes here
const minutes = chronometer.getMinutes();
const minutesToString = chronometer.computeTwoDigitNumber(minutes);

minDecElement.textContent = minutesToString[ 0 ];
minUniElement.textContent = minutesToString[ 1 ];
}

function printSeconds() {
// ... your code goes here
const seconds = chronometer.getSeconds();
const secondsToString = chronometer.computeTwoDigitNumber(seconds);

secDecElement.textContent = secondsToString[ 0 ];
secUniElement.textContent = secondsToString[ 1 ];
}

// ==> BONUS
function printMilliseconds() {
// ... your code goes here
const milliseconds = chronometer.getMilliseconds();
const millisecondsToString = chronometer.computeTwoDigitNumber(milliseconds);
milDecElement.textContent = millisecondsToString[ 0 ];
milUniElement.textContent = millisecondsToString[ 1 ];

}

function printSplit() {
// ... your code goes here
function printSplit(listItem) {
splitsElement.append(listItem)
}

function clearSplits() {
// ... your code goes here
splitsElement.innerHTML = '';
}

function setStopBtn() {
// ... your code goes here
chronometer.stop();
btnLeftElement.textContent = "START"
btnLeftElement.className = "btn start";
btnRightElement.textContent = "RESET";
btnRightElement.className = "btn reset";
}

function setSplitBtn() {
// ... your code goes here
const split= chronometer.split()
const listItem=document.createElement('li')
listItem.className="list-item"
listItem.textContent=split;
printSplit(listItem);

}


function setStartBtn() {
// ... your code goes here
chronometer.start(printTime); // pasamos el callback para que actualize UI del timer
btnLeftElement.textContent = "STOP";
btnLeftElement.className = "btn stop";
btnRightElement.textContent = "SPLIT";
btnRightElement.className = "btn split";
}

function setResetBtn() {
// ... your code goes here
// resetea el crhono
chronometer.reset();

// resetea los splits
clearSplits();

// resetea la UI
minDecElement.textContent = '0';
minUniElement.textContent = '0';
secDecElement.textContent = '0';
secUniElement.textContent = '0';
milDecElement.textContent = '0';
milUniElement.textContent = '0';
}

// Start/Stop Button
btnLeftElement.addEventListener('click', () => {
// ... your code goes here
(btnLeftElement.textContent === "START") ? setStartBtn() : setStopBtn();
});

// Reset/Split Button
btnRightElement.addEventListener('click', () => {
// ... your code goes here
(btnRightElement.textContent === "RESET") ? setResetBtn() : setSplitBtn();
});
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"test:watch": "jest --watchAll --verbose=false"
},
"devDependencies": {
"jest": "^26.6.3",
"jest-html-reporter": "^3.3.0",
"jest-junit": "^12.0.0"
"jest": "^30.0.2",
"jest-html-reporter": "^4.1.0",
"jest-junit": "^16.0.0"
},
"jest": {
"reporters": [
Expand Down
Loading