Decimal to Binary Converter
The Project
Interactive decimal-to-binary converter developed with recursive JavaScript functions. An application that demonstrates the power of recursion through numerical conversion, complete with call stack animation to visualize the recursive process.
Source Code
- 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();
}
});
Ten Productive Days of Recovery
It was 10 challenging days but at the same time alternating between many activities helped me a lot to regenerate.
I completed course 4/7 of Google UX, laid the groundwork for 3 university exams and completed this project.
I realized that JavaScript has enormously increased my concentration capacity. All the activities I carried out seemed easier to me. Reading 150 pages of one exam, reading 100 of another, preparing the paper with my team for the pitching session related to an exam, as well as Google's course 4 regarding UX Research: I perceived them all with a much lower degree of complexity than last time.
The First Professional Recognition
In addition to this, my self-esteem also received a boost by receiving a job interview proposal on LinkedIn from a company looking for a UX designer telling me they found my profile interesting. I declined, thanking them and explaining that I'm currently investing all my time in UX Google Certificate, JavaScript, university and work, but also sending her my freeCodeCamp portfolio and telling her I'd be interested in reconnecting when I've completed this path.
The Factory Perspective
All the factories where I've worked have in common the perception that the workers themselves have towards the office employees. Here those who work in offices are seen as mythological figures, beings endowed with superior abilities and extraordinary intellect, like an unreachable world, often looked at with a mixture of admiration and envy.
As much as I try to maintain my critical thinking, I admit that my beliefs have also been influenced by this perception and I'm happy that the proposal I received confirmed that entering that world is possible.
The Discovery of Recursion
Anyway, it was a very beautiful project! Recursive functions were a concept I never would have expected to exist. I had taken for granted within myself that for every purpose there was its specific tool. I didn't believe you could call the same function within itself creating a loop like that (it's even strange to say). For such purposes, I thought there were only while, for... I'm realizing that there's art here too, in what from the outside appears as a purely logical field.
The Inspiration from Antirez
These days in my free time I had the pleasure of watching some videos of a god of computer science, namely Salvatore Sanfilippo (antirez). I was just a few minutes ago reading his article about comments (https://antirez.com/news/124), where, showing the comments he wrote in Redis, he traces back to the best practices for writing them, stating that writing good comments is as difficult as writing good code. I'm grateful to have discovered him right now because putting his teachings into practice right away is much simpler than doing it later with already consolidated habits.
What I Learned
Recursive Functions:
- Base case concept to terminate recursion
- Recursive pattern:
return function(newInput) + operation Math.floor(input / 2)for integer division- Base case handling with
input === 0 || input === 1
Call Stack Visualization:
- Call stack animation to understand recursion
setTimeout()to create timed animations- Visualization of how calls stack up and then resolve
Advanced Input Validation:
parseInt()for string-to-number conversionisNaN()for numeric validity checking- Handling negative numbers and empty inputs
- Alert for immediate user feedback
Event Handling:
- Event listeners for click and keydown
- Enter key handling for alternative submit
e.key === "Enter"for specific key control
Dynamic DOM Manipulation:
innerHTML += templateto add elementsdocument.getElementById().remove()for element removaltextContentmanipulation for dynamic updates
Numerical Algorithms:
- Decimal-to-binary conversion with successive divisions
- Modulo operator
%to get division remainder - Result string construction through concatenation
Reflection
JavaScript continues to surprise me.
Recursion has opened a new dimension in my way of thinking about programming.
No longer just linear loops, but functions that call themselves creating powerful and elegant patterns.
Next Project: Build a Roman Numeral Converter Project (CERTIFICATION PROJECT!)