Decimal to Binary Converter
Il Progetto
Convertitore decimale-binario interattivo sviluppato con funzioni ricorsive JavaScript. Un'applicazione che dimostra il potere della ricorsione attraverso la conversione numerica, completa di animazione del call stack per visualizzare il processo ricorsivo.
Codice Sorgente
- index.html
- styles.css
- script.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Decimal to Binary Converter</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>
Decimal to Binary <br />
Converter
</h1>
<section class="input-container">
<label for="number-input">Enter a decimal number:</label>
<input
value=""
type="number"
name="decimal number input"
id="number-input"
class="number-input"
/>
<button class="convert-btn" id="convert-btn">Convert</button>
</section>
<section class="output-container">
<output id="result" for="number-input"></output>
<h2>Call stack</h2>
<div id="animation-container"></div>
</section>
<script src="script.js"></script>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--light-grey: #f5f6f7;
--dark-blue: #1b1b32;
--orange: #f1be32;
}
body {
display: flex;
flex-direction: column;
align-items: center;
font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console,
monospace;
font-size: 1.125rem;
color: var(--light-grey);
background-color: var(--dark-blue);
padding: 0 4px;
}
h1 {
font-size: 2.125rem;
text-align: center;
margin: 20px 0;
}
h2 {
font-size: 1.5rem;
text-align: center;
margin: 20px 0;
}
.input-container {
display: flex;
flex-direction: column;
gap: 10px;
justify-content: center;
align-items: center;
width: clamp(320px, 50vw, 460px);
margin: 10px auto;
}
.input-container label {
white-space: nowrap;
word-spacing: -6px;
}
.convert-btn {
font-size: inherit;
font-family: inherit;
background-color: var(--orange);
width: 100%;
height: 2rem;
padding: 0 6px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.number-input {
font-size: inherit;
padding: 0.3rem;
width: 100%;
}
.output-container {
margin-inline: auto;
width: clamp(320px, 50vw, 460px);
}
#result {
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
text-align: center;
min-height: 80px;
margin-block-start: 20px;
padding: 15px;
border: 2px solid var(--orange);
border-radius: 2px;
}
#animation-container {
display: flex;
flex-direction: column-reverse;
justify-content: end;
gap: 1rem;
margin-block-end: 1rem;
min-height: 40vh;
border: 2px dashed var(--orange);
padding: 1rem;
}
.animation-frame {
font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui,
helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial,
sans-serif;
padding: 15px 10px;
border: 5px solid var(--orange);
font-size: 1.2rem;
text-align: center;
}
@media screen and (min-width: 36em) {
body {
font-size: 1rem;
}
.input-container {
flex-direction: row;
width: unset;
}
.number-input {
width: unset;
}
}
const numberInput = document.getElementById("number-input");
const convertBtn = document.getElementById("convert-btn");
const result = document.getElementById("result");
const animationContainer = document.getElementById("animation-container");
const animationData = [
{
inputVal: 5,
addElDelay: 1000,
msg: 'decimalToBinary(5) returns "10" + 1 (5 % 2). Then it pops off the stack.',
showMsgDelay: 15000,
removeElDelay: 20000,
},
{
inputVal: 2,
addElDelay: 1500,
msg: 'decimalToBinary(2) returns "1" + 0 (2 % 2) and gives that value to the stack below. Then it pops off the stack.',
showMsgDelay: 10000,
removeElDelay: 15000,
},
{
inputVal: 1,
addElDelay: 2000,
msg: "decimalToBinary(1) returns '1' (base case) and gives that value to the stack below. Then it pops off the stack.",
showMsgDelay: 5000,
removeElDelay: 10000,
}
];
const decimalToBinary = (input) => {
if (input === 0 || input === 1) {
return String(input);
} else {
return decimalToBinary(Math.floor(input / 2)) + (input % 2);
}
};
const showAnimation = () => {
result.innerText = "Call Stack Animation";
animationData.forEach((obj) => {
setTimeout(() => {
animationContainer.innerHTML += `
<p id="${obj.inputVal}" class="animation-frame">
decimalToBinary(${obj.inputVal})
</p>
`;
}, obj.addElDelay);
setTimeout(() => {
document.getElementById(obj.inputVal).textContent = obj.msg;
}, obj.showMsgDelay);
setTimeout(() => {
document.getElementById(obj.inputVal).remove();
}, obj.removeElDelay);
});
setTimeout(() => {
result.textContent = decimalToBinary(5);
}, 20000);
};
const checkUserInput = () => {
const inputInt = parseInt(numberInput.value);
if (!numberInput.value || isNaN(inputInt) || inputInt < 0) {
alert("Please provide a decimal number greater than or equal to 0");
return;
}
if (inputInt === 5) {
showAnimation();
return;
}
result.textContent = decimalToBinary(inputInt);
numberInput.value = "";
};
convertBtn.addEventListener("click", checkUserInput);
numberInput.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
checkUserInput();
}
});
I Dieci Giorni di Pausa Produttiva
Sono stati 10 giorni impegnativi ma allo stesso tempo l'alternare parecchie attività mi ha aiutato parecchio per rigenerarmi.
Ho completato il corso 4/7 di Google UX, spianato la strada per 3 esami universitari e completato questo progetto.
Mi sono reso conto che JavaScript ha incrementato enormemente la mia capacità di concentrazione. Tutte le attività che ho svolto mi sono sembrate più facili. Leggere 150 pagine di un esame, leggerne 100 di un altro, preparare insieme al mio team l'elaborato per la pitching session relativa a un esame, così come il corso 4 di Google riguardante la UX Research: le ho percepite tutte con un grado di complessità parecchio inferiore rispetto all'ultima volta.
Il Primo Riconoscimento Professionale
Oltre a ciò ha innalzato la mia autostima anche il ricevimento di una proposta di colloquio su LinkedIn da parte di un'azienda che cerca un UX designer dicendomi che hanno trovato il mio profilo interessante. Ho declinato ringraziandola e rispondendole che sto investendo in questo periodo tutto il mio tempo in UX Google Certificate, JavaScript, università e lavoro, ma mandandole ugualmente il portfolio di freeCodeCamp e dicendole che mi piacerebbe ci risentissimo più avanti quando avrò completato questo percorso.
La Prospettiva della Fabbrica
Tutte le fabbriche in cui ho lavorato come operaio hanno in comune la percezione che hanno gli operai stessi nei confronti degli impiegati. Qui chi lavora negli uffici viene visto come una figura mitologica, un essere dotato di capacità superiori e intelletto fuori dal comune, come un mondo irraggiungibile, spesso guardato con un misto tra ammirazione e invidia.
Per quanto cerchi di mantenere il mio pensiero critico, ammetto che anche le mie credenze sono state influenzate da questa percezione e sono felice che la proposta ricevuta mi abbia confermato che entrare in quel mondo è possibile.
La Scoperta della Ricorsione
Comunque è stato un progetto molto bello! Le funzioni ricorsive sono state un concetto che non mi sarei nemmeno aspettato esistesse. Avevo dato per assodato dentro di me che per ogni scopo ci fosse il suo strumento specifico. Non credevo si potesse chiamare la stessa funzione dentro se stessa creando così un ciclo (è persino strano da dire). Per quegli scopi pensavo ci fossero solo while, for... Mi sto accorgendo che c'è dell'arte anche qui, in quello che dall'esterno appare come un campo puramente logico.
L'Ispirazione di Antirez
In questi giorni nel tempo libero ho avuto il piacere di guardare alcuni video di un dio dell'informatica, ovvero Salvatore Sanfilippo (antirez). Stavo proprio qualche minuto fa leggendo il suo articolo relativo ai commenti (https://antirez.com/news/124), dove, mostrando i commenti che ha scritto in Redis, risale alle best practice per scriverli, affermando che scrivere buoni commenti è difficile tanto quanto scrivere buon codice. Ringrazio di averlo conosciuto proprio ora perché mettere in pratica i suoi insegnamenti fin da subito è molto più semplice che farlo più avanti con abitudini già consolidate.
Cosa Ho Imparato
Funzioni Ricorsive:
- Concetto di base case per terminare la ricorsione
- Pattern ricorsivo:
return function(newInput) + operation Math.floor(input / 2)per divisione intera- Gestione del caso base con
input === 0 || input === 1
Call Stack Visualization:
- Animazione del call stack per comprendere la ricorsione
setTimeout()per creare animazioni temporizzate- Visualizzazione di come le chiamate si impilano e poi si risolvono
Input Validation Avanzata:
parseInt()per conversione stringa-numeroisNaN()per controllo validità numerica- Gestione di numeri negativi e input vuoti
- Alert per feedback utente immediato
Event Handling:
- Event listener per click e keydown
- Gestione del tasto Enter per submit alternativo
e.key === "Enter"per controllo tasti specifici
DOM Manipulation Dinamica:
innerHTML += templateper aggiungere elementidocument.getElementById().remove()per rimozione elementi- Manipolazione
textContentper aggiornamenti dinamici
Algoritmi Numerici:
- Conversione decimale-binario con divisioni successive
- Operatore modulo
%per ottenere resto della divisione - Costruzione stringa risultato attraverso concatenazione
Riflessione
JavaScript continua a sorprendermi.
La ricorsione ha aperto una nuova dimensione nel mio modo di pensare alla programmazione.
Non più solo cicli lineari, ma funzioni che si chiamano creando pattern potenti ed eleganti.
Prossimo Progetto: Costruire un Roman Numeral Converter (CERTIFICATION PROJECT!)