Files
cabrits-math/binary-to-decimal-converter.html
2026-05-12 06:26:33 -04:00

460 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Binary to Decimal Converter - Form 1</title>
<style>
:root {
--primary: #4527a0;
--accent: #00838f;
--soft: #ede7f6;
--soft-alt: #d1c4e9;
--good: #2e7d32;
--good-soft: #e8f5e9;
--warn: #c62828;
--warn-soft: #ffebee;
--ink: #1a1a1a;
}
* { box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.5;
max-width: 1100px;
margin: 0 auto;
padding: 20px;
background: #f5f3fa;
color: var(--ink);
}
.app {
background: #fff;
padding: 28px 34px;
border: 2px solid var(--primary);
box-shadow: 0 2px 10px rgba(69, 39, 160, 0.08);
}
.header {
text-align: center;
border-bottom: 3px solid var(--primary);
padding-bottom: 12px;
margin-bottom: 18px;
}
.header h1 { margin: 0; font-size: 1.6em; color: var(--primary); }
.header h2 { margin: 4px 0 0; font-size: 1em; color: var(--accent); font-weight: normal; }
h3 {
border-bottom: 2px solid var(--primary);
padding: 6px 0;
margin: 22px 0 10px 0;
font-size: 1.1em;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--primary);
}
.input-row {
display: flex;
gap: 14px;
align-items: center;
flex-wrap: wrap;
margin-bottom: 12px;
}
.input-row label {
font-weight: bold;
color: var(--primary);
font-size: 1em;
}
#binaryInput {
font-family: 'Courier New', monospace;
font-size: 1.6em;
padding: 6px 10px;
border: 2px solid var(--primary);
color: var(--primary);
letter-spacing: 4px;
width: 220px;
text-align: center;
background: #fff;
}
#binaryInput:focus {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
button {
font-family: inherit;
font-size: 0.95em;
padding: 8px 14px;
border: 1.5px solid var(--accent);
background: #fff;
color: var(--accent);
font-weight: bold;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 0.4px;
}
button:hover { background: var(--soft); color: var(--primary); border-color: var(--primary); }
button.primary { background: var(--primary); color: #fff; border-color: var(--primary); }
button.primary:hover { background: #311b92; color: #fff; }
button.warn { color: var(--warn); border-color: var(--warn); }
button.warn:hover { background: var(--warn-soft); color: var(--warn); }
.preset-row {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin: 6px 0 12px;
}
.preset-row button {
font-family: 'Courier New', monospace;
letter-spacing: 2px;
padding: 4px 10px;
font-size: 1em;
text-transform: none;
}
.chart-wrapper {
border: 2px solid var(--primary);
padding: 14px;
margin: 12px 0;
background: var(--soft);
overflow-x: auto;
}
.chart {
margin: 0 auto;
border-collapse: collapse;
font-family: 'Courier New', monospace;
}
.chart td {
border: 1.5px solid var(--primary);
padding: 10px 18px;
text-align: center;
background: #fff;
min-width: 64px;
}
.chart .row-power { background: var(--soft); color: var(--primary); font-weight: bold; font-size: 1em; }
.chart .row-value { background: #fff; color: var(--primary); font-weight: bold; font-size: 1.15em; }
.chart .row-digit { background: #fff; font-size: 1.6em; font-weight: bold; }
.chart .row-contrib { background: #fafbfc; color: var(--accent); font-weight: bold; font-size: 1.05em; }
.chart .row-digit.is-one { background: var(--good-soft); color: var(--good); }
.chart .row-contrib.is-one { background: var(--good-soft); color: var(--good); }
.chart .row-digit.is-zero { color: #888; }
.chart .row-contrib.is-zero { color: #888; }
.working-line {
text-align: center;
font-family: 'Courier New', monospace;
font-size: 1.2em;
margin: 10px 0;
color: var(--primary);
font-weight: bold;
}
.answer-banner {
border: 2px solid var(--good);
background: var(--good-soft);
color: var(--good);
padding: 14px 18px;
text-align: center;
font-size: 1.4em;
font-weight: bold;
margin: 14px 0 6px;
font-family: 'Courier New', monospace;
}
.answer-banner.hidden {
background: var(--soft);
color: var(--primary);
border-color: var(--primary);
}
.error-banner {
border: 2px solid var(--warn);
background: var(--warn-soft);
color: var(--warn);
padding: 10px 14px;
text-align: center;
font-weight: bold;
margin: 12px 0;
}
.controls-row {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin: 6px 0 0;
}
.footer-note {
margin-top: 18px;
padding: 8px 12px;
border-left: 4px solid var(--accent);
background: var(--soft);
color: var(--primary);
font-size: 0.92em;
}
@media print {
body { background: #fff !important; color: #000 !important; }
.app { border: 1.5px solid #000 !important; box-shadow: none !important; }
*, *::before, *::after {
background: #fff !important;
background-color: #fff !important;
color: #000 !important;
box-shadow: none !important;
}
.header, h3, .chart-wrapper, .chart td, .answer-banner, .error-banner, button, .footer-note {
border-color: #000 !important;
}
button { display: none !important; }
}
</style>
</head>
<body>
<div class="app">
<div class="header">
<h1>BINARY &rarr; DECIMAL CONVERTER</h1>
<h2>Form 1 - Lesson 30 - Same shape, different base</h2>
</div>
<h3>Type a Binary Number</h3>
<div class="input-row">
<label for="binaryInput">Binary:</label>
<input id="binaryInput" type="text" maxlength="8" autocomplete="off" spellcheck="false" placeholder="e.g. 1011">
<button class="primary" id="convertBtn">Convert</button>
<button id="clearBtn">Clear</button>
<button id="randomBtn">Random</button>
</div>
<div class="preset-row">
<button data-preset="101">101</button>
<button data-preset="1011">1011</button>
<button data-preset="1101">1101</button>
<button data-preset="10101">10101</button>
<button data-preset="11000">11000</button>
<button data-preset="11111">11111</button>
<button data-preset="100000">100000</button>
<button data-preset="110010">110010</button>
</div>
<div id="errorMsg" class="error-banner" style="display: none;"></div>
<h3>Place Value Chart (powers of 2)</h3>
<div class="chart-wrapper">
<table class="chart">
<tbody id="chartBody"></tbody>
</table>
</div>
<div id="workingLine" class="working-line"></div>
<div id="answerBanner" class="answer-banner hidden">Type a binary number above and press Convert.</div>
<div class="controls-row">
<button id="revealBtn">Hide Answer</button>
<button id="hideChartBtn">Hide Chart</button>
</div>
<div class="footer-note">
<strong>For students:</strong> solve on paper <em>first</em> using the chart in your worksheet. Type the binary number here only to <em>check</em>. The lesson is in the chart, not the click.
</div>
</div>
<script>
(function() {
const input = document.getElementById('binaryInput');
const convertBtn = document.getElementById('convertBtn');
const clearBtn = document.getElementById('clearBtn');
const randomBtn = document.getElementById('randomBtn');
const revealBtn = document.getElementById('revealBtn');
const hideChartBtn = document.getElementById('hideChartBtn');
const chartBody = document.getElementById('chartBody');
const chartWrapper = document.querySelector('.chart-wrapper');
const workingLine = document.getElementById('workingLine');
const answerBanner = document.getElementById('answerBanner');
const errorMsg = document.getElementById('errorMsg');
let answerHidden = false;
let chartHidden = false;
function clearError() {
errorMsg.style.display = 'none';
errorMsg.textContent = '';
}
function showError(msg) {
errorMsg.textContent = msg;
errorMsg.style.display = 'block';
}
function powerOfTwo(n) {
let v = 1;
for (let i = 0; i < n; i++) v *= 2;
return v;
}
function buildChartFor(binaryStr) {
const n = binaryStr.length;
const powerRow = document.createElement('tr');
const valueRow = document.createElement('tr');
const digitRow = document.createElement('tr');
const contribRow = document.createElement('tr');
powerRow.className = '';
for (let i = 0; i < n; i++) {
const exponent = n - 1 - i;
const digit = binaryStr[i];
const placeVal = powerOfTwo(exponent);
const contrib = parseInt(digit, 10) * placeVal;
const pTd = document.createElement('td');
pTd.className = 'row-power';
pTd.innerHTML = '2<sup>' + exponent + '</sup>';
powerRow.appendChild(pTd);
const vTd = document.createElement('td');
vTd.className = 'row-value';
vTd.textContent = placeVal;
valueRow.appendChild(vTd);
const dTd = document.createElement('td');
dTd.className = 'row-digit ' + (digit === '1' ? 'is-one' : 'is-zero');
dTd.textContent = digit;
digitRow.appendChild(dTd);
const cTd = document.createElement('td');
cTd.className = 'row-contrib ' + (digit === '1' ? 'is-one' : 'is-zero');
cTd.textContent = contrib;
contribRow.appendChild(cTd);
}
chartBody.innerHTML = '';
chartBody.appendChild(powerRow);
chartBody.appendChild(valueRow);
chartBody.appendChild(digitRow);
chartBody.appendChild(contribRow);
}
function renderEmpty() {
chartBody.innerHTML = '';
const powerRow = document.createElement('tr');
const valueRow = document.createElement('tr');
const digitRow = document.createElement('tr');
const contribRow = document.createElement('tr');
for (let exp = 5; exp >= 0; exp--) {
const placeVal = powerOfTwo(exp);
const pTd = document.createElement('td');
pTd.className = 'row-power';
pTd.innerHTML = '2<sup>' + exp + '</sup>';
powerRow.appendChild(pTd);
const vTd = document.createElement('td');
vTd.className = 'row-value';
vTd.textContent = placeVal;
valueRow.appendChild(vTd);
const dTd = document.createElement('td');
dTd.className = 'row-digit is-zero';
dTd.textContent = '_';
digitRow.appendChild(dTd);
const cTd = document.createElement('td');
cTd.className = 'row-contrib is-zero';
cTd.textContent = '_';
contribRow.appendChild(cTd);
}
chartBody.appendChild(powerRow);
chartBody.appendChild(valueRow);
chartBody.appendChild(digitRow);
chartBody.appendChild(contribRow);
workingLine.textContent = '';
setBanner('Type a binary number above and press Convert.', true);
}
function setBanner(text, hidden) {
answerBanner.textContent = text;
if (hidden) answerBanner.classList.add('hidden');
else answerBanner.classList.remove('hidden');
}
function convert() {
clearError();
const raw = input.value.trim();
if (raw.length === 0) {
showError('Type a binary number first (only 0s and 1s).');
renderEmpty();
return;
}
if (!/^[01]+$/.test(raw)) {
showError('Binary numbers use only 0 and 1. Found another digit.');
renderEmpty();
return;
}
if (raw.length > 8) {
showError('Keep it to 8 digits or fewer for this lesson.');
return;
}
buildChartFor(raw);
const n = raw.length;
let total = 0;
const ones = [];
const allTerms = [];
for (let i = 0; i < n; i++) {
const exponent = n - 1 - i;
const digit = parseInt(raw[i], 10);
const placeVal = powerOfTwo(exponent);
allTerms.push(digit + '×' + placeVal);
if (digit === 1) {
ones.push(placeVal);
total += placeVal;
}
}
const fullExpansion = allTerms.join(' + ');
const onesOnly = ones.length > 0 ? ones.join(' + ') + ' = ' + total : '0';
workingLine.innerHTML = fullExpansion + '<br>= ' + onesOnly;
if (answerHidden) {
setBanner(raw + '₂ = ? (press Show Answer)', true);
} else {
setBanner(raw + '₂ = ' + total + ' in denary', false);
}
}
input.addEventListener('input', function() {
input.value = input.value.replace(/[^01]/g, '');
});
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') convert();
});
convertBtn.addEventListener('click', convert);
clearBtn.addEventListener('click', function() {
input.value = '';
clearError();
renderEmpty();
input.focus();
});
randomBtn.addEventListener('click', function() {
const len = 3 + Math.floor(Math.random() * 4);
let s = '1';
for (let i = 1; i < len; i++) {
s += (Math.random() < 0.5 ? '0' : '1');
}
input.value = s;
convert();
});
document.querySelectorAll('.preset-row button[data-preset]').forEach(function(btn) {
btn.addEventListener('click', function() {
input.value = btn.getAttribute('data-preset');
convert();
});
});
revealBtn.addEventListener('click', function() {
answerHidden = !answerHidden;
revealBtn.textContent = answerHidden ? 'Show Answer' : 'Hide Answer';
if (input.value.trim().length > 0) convert();
});
hideChartBtn.addEventListener('click', function() {
chartHidden = !chartHidden;
chartWrapper.style.display = chartHidden ? 'none' : 'block';
hideChartBtn.textContent = chartHidden ? 'Show Chart' : 'Hide Chart';
});
renderEmpty();
})();
</script>
</body>
</html>