An engineering calculated

<!DOCTYPE html>

<html lang=”en”>

<head>

<meta charset=”UTF-8″>

<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>

<title>ENG-CALC PRO</title>

<style>

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {

–crt-green: #00ff41;

–crt-dim: #00c032;

–crt-dark: #003a0f;

–crt-bg: #020c03;

–amber: #ffb000;

–amber-dim: #cc8a00;

–red: #ff3a3a;

–blue: #00cfff;

–panel-bg: #0a0f0a;

–border: #1a2e1a;

–bezel: #1c1f1c;

}

html, body {

height: 100%;

background: #0e110e;

display: flex;

align-items: center;

justify-content: center;

font-family: ‘IBM Plex Mono’, monospace;

overflow: hidden;

}

body::before {

content: ”;

position: fixed; inset: 0;

background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,0.07) 2px, rgba(0,0,0,0.07) 4px);

pointer-events: none; z-index: 9999;

}

body::after {

content: ”;

position: fixed; inset: 0;

background: radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,0.7) 100%);

pointer-events: none; z-index: 9998;

}

/* BEZEL */

.bezel {

background: linear-gradient(145deg, #252825, #161916, #1e221e);

border-radius: 10px;

padding: 22px 18px 18px;

box-shadow:

0 0 0 2px #2e322e,

0 0 0 4px #111,

0 25px 80px rgba(0,0,0,0.9),

inset 0 1px 0 rgba(255,255,255,0.05);

width: 560px;

position: relative;

}

.bezel-label {

position: absolute;

top: 7px; left: 50%; transform: translateX(-50%);

font-family: ‘Orbitron’, monospace;

font-size: 8px; font-weight: 700;

letter-spacing: 6px; color: #2e342e;

white-space: nowrap;

}

/* SCREEN */

.screen-surround {

background: #070c07;

border-radius: 5px; padding: 3px;

box-shadow: inset 0 0 24px rgba(0,0,0,0.9), 0 0 20px rgba(0,255,65,0.04);

margin-bottom: 14px;

}

.screen {

background: var(–crt-bg);

border-radius: 3px;

padding: 13px 15px 10px;

position: relative; overflow: hidden;

min-height: 148px;

}

.screen::before {

content: ”;

position: absolute; inset: 0;

background: radial-gradient(ellipse at 50% 0%, rgba(0,255,65,0.07) 0%, transparent 70%);

pointer-events: none;

}

.screen-header {

display: flex; justify-content: space-between; align-items: center;

margin-bottom: 9px; padding-bottom: 7px;

border-bottom: 1px solid #0d1e0d;

}

.screen-id {

font-family: ‘VT323’, monospace; font-size: 14px;

color: var(–crt-dim); letter-spacing: 3px;

}

.screen-status { display: flex; gap: 10px; }

.st {

font-size: 9px; letter-spacing: 1px;

color: var(–crt-dark);

}

.st.on { color: var(–crt-dim); }

.st.amb { color: var(–amber-dim); }

.mode-row { display: flex; gap: 5px; margin-bottom: 8px; }

.mode-pill {

font-family: ‘VT323’, monospace; font-size: 13px;

padding: 1px 9px;

border: 1px solid var(–crt-dark); color: var(–crt-dark);

background: none; cursor: pointer; letter-spacing: 1px;

transition: all 0.1s;

}

.mode-pill:hover { color: var(–crt-dim); border-color: var(–crt-dim); }

.mode-pill.active {

border-color: var(–crt-green); color: var(–crt-green);

text-shadow: 0 0 8px var(–crt-green);

background: rgba(0,255,65,0.05);

}

.expr-line {

font-family: ‘VT323’, monospace; font-size: 16px;

color: var(–crt-dim); text-align: right;

min-height: 20px; letter-spacing: 1px;

white-space: nowrap; overflow: hidden; text-overflow: ellipsis;

}

.result-line {

font-family: ‘VT323’, monospace; font-size: 54px;

color: var(–crt-green); text-align: right; line-height: 1;

letter-spacing: 3px;

text-shadow: 0 0 10px rgba(0,255,65,0.8), 0 0 30px rgba(0,255,65,0.25);

transition: color 0.1s; word-break: break-all;

min-height: 58px; display: flex; align-items: center; justify-content: flex-end;

}

.result-line.error { color: var(–red); font-size: 22px; text-shadow: 0 0 10px rgba(255,58,58,0.5); }

.cursor-block {

display: inline-block; width: 3px; height: 40px;

background: var(–crt-green); margin-left: 3px; vertical-align: middle;

animation: blink 1s step-end infinite;

}

@keyframes blink { 0%,49%{opacity:1} 50%,100%{opacity:0} }

.mem-strip {

display: flex; gap: 14px; margin-top: 5px;

padding-top: 5px; border-top: 1px solid #0d1e0d;

}

.mem-lbl { font-size: 9px; letter-spacing: 1px; color: var(–crt-dark); }

.mem-lbl.lit { color: var(–amber); text-shadow: 0 0 6px var(–amber); }

/* BUTTON GRID */

.btn-grid {

display: grid;

grid-template-columns: repeat(5, 1fr);

gap: 3px;

}

.key { background: none; border: none; cursor: pointer; padding: 0; }

.key-face {

background: linear-gradient(155deg, #1e231e, #131713, #181c18);

border: 1px solid #262e26;

border-bottom: 3px solid #0c110c;

border-radius: 3px;

padding: 9px 4px 7px;

width: 100%; transition: all 0.06s;

box-shadow: 0 2px 0 #080b08;

}

.key:active .key-face {

transform: translateY(2px);

border-bottom-width: 1px; box-shadow: none;

}

.key:hover .key-face { filter: brightness(1.18); }

.key-top {

font-family: ‘VT323’, monospace; font-size: 9px;

color: var(–crt-dark); letter-spacing: 1px;

display: block; text-align: center; line-height: 1; margin-bottom: 2px;

}

.key-main {

font-family: ‘Orbitron’, monospace; font-size: 10px; font-weight: 600;

display: block; text-align: center; line-height: 1.2;

}

.key.num .key-main { color: #bccbbc; }

.key.op .key-main { color: var(–amber); }

.key.op .key-face { border-color: #2e2400; }

.key.fn .key-main { color: var(–blue); font-size: 9px; letter-spacing: 0.3px; }

.key.fn .key-face { border-color: #00253a; }

.key.eq .key-face { background: linear-gradient(155deg,#003a10,#002a0b,#003010); border-color: var(–crt-green); border-bottom-color: #001a06; }

.key.eq .key-main { color: var(–crt-green); font-size: 18px; text-shadow: 0 0 8px var(–crt-green); }

.key.clr .key-main { color: var(–red); }

.key.clr .key-face { border-color: #3a0000; }

.key.mem .key-main { color: var(–amber); font-size: 9px; }

.key.mem .key-face { background: linear-gradient(155deg,#1a1500,#110f00,#161200); }

.key.span2 { grid-column: span 2; }

/* CONVERTER */

.converter-panel { display: none; }

.converter-panel.active { display: block; }

.cat-strip { display: flex; flex-wrap: wrap; gap: 2px; margin-bottom: 9px; }

.cat-key {

font-family: ‘VT323’, monospace; font-size: 13px;

padding: 2px 10px;

background: #0c100c; border: 1px solid #1a251a;

color: #2a3e2a; cursor: pointer; letter-spacing: 1px; transition: all 0.1s;

}

.cat-key:hover { color: var(–crt-dim); }

.cat-key.active { border-color: var(–amber); color: var(–amber); background: #1a1200; }

.conv-fields {

display: grid;

grid-template-columns: 1fr 26px 1fr;

gap: 5px; align-items: end;

margin-bottom: 6px;

}

.conv-grp { display: flex; flex-direction: column; gap: 3px; }

.conv-lbl { font-family: ‘VT323’, monospace; font-size: 12px; color: var(–crt-dim); letter-spacing: 2px; }

.conv-sel, .conv-inp {

background: var(–crt-bg); border: 1px solid var(–crt-dark);

color: var(–crt-green); font-family: ‘VT323’, monospace; font-size: 18px;

padding: 6px 7px; outline: none; width: 100%;

}

.conv-sel:focus, .conv-inp:focus { border-color: var(–crt-green); }

.conv-sel option { background: #020c03; color: var(–crt-green); }

.conv-arrow-mid { font-family: ‘VT323’, monospace; font-size: 22px; color: var(–crt-dim); text-align: center; padding-bottom: 5px; }

/* FORMULAS */

.formulas-panel { display: none; max-height: 315px; overflow-y: auto; }

.formulas-panel.active { display: block; }

.formulas-panel::-webkit-scrollbar { width: 3px; }

.formulas-panel::-webkit-scrollbar-track { background: #0c100c; }

.formulas-panel::-webkit-scrollbar-thumb { background: var(–crt-dark); }

.fcard {

border: 1px solid #1a251a; margin-bottom: 4px;

cursor: pointer; background: #080c08; transition: border-color 0.15s;

}

.fcard:hover { border-color: var(–crt-dim); }

.fcard.open { border-color: var(–crt-green); }

.fcard-head {

display: flex; justify-content: space-between; align-items: baseline;

padding: 7px 10px;

}

.fcard-title { font-family: ‘Orbitron’, monospace; font-size: 8px; font-weight: 700; color: #7aaa7a; letter-spacing: 1px; text-transform: uppercase; }

.fcard-eq { font-family: ‘VT323’, monospace; font-size: 15px; color: var(–amber); letter-spacing: 1px; }

.fcard-cat { font-family: ‘VT323’, monospace; font-size: 11px; color: var(–blue); letter-spacing: 1px; }

.fcard-body { display: none; padding: 0 10px 10px; display: none; grid-template-columns: 1fr 1fr; gap: 5px; }

.fcard.open .fcard-body { display: grid; }

.finp-grp { display: flex; flex-direction: column; gap: 3px; }

.finp-lbl { font-family: ‘VT323’, monospace; font-size: 11px; color: var(–crt-dim); letter-spacing: 1px; }

.finp {

background: var(–crt-bg); border: 1px solid var(–crt-dark);

color: var(–crt-green); font-family: ‘VT323’, monospace; font-size: 15px;

padding: 4px 7px; outline: none; width: 100%;

}

.finp:focus { border-color: var(–crt-green); }

.fcard-go {

grid-column: span 2; padding: 6px;

background: #001a07; border: 1px solid var(–crt-green); color: var(–crt-green);

font-family: ‘Orbitron’, monospace; font-size: 8px; font-weight: 700;

letter-spacing: 3px; cursor: pointer; transition: all 0.1s;

}

.fcard-go:hover { background: #002e0e; }

.fcard-ans {

grid-column: span 2;

font-family: ‘VT323’, monospace; font-size: 18px; color: var(–amber);

background: #1a1200; border: 1px solid #3a2a00;

padding: 6px 8px; display: none; letter-spacing: 1px;

}

.fcard.has-ans .fcard-ans { display: block; }

/* FOOTER */

.footer {

display: flex; justify-content: space-between; align-items: center;

margin-top: 11px; padding-top: 8px;

border-top: 1px solid #1a221a;

}

.footer-info { font-family: ‘VT323’, monospace; font-size: 13px; color: #2a3e2a; letter-spacing: 2px; }

.angle-toggle { display: flex; gap: 2px; }

.ang-btn {

font-family: ‘VT323’, monospace; font-size: 13px; padding: 2px 10px;

background: #0c100c; border: 1px solid #1a251a; color: #2a3e2a;

cursor: pointer; letter-spacing: 1px; transition: all 0.1s;

}

.ang-btn.active { border-color: var(–crt-green); color: var(–crt-green); }

@keyframes flash { 0%{opacity:1}50%{opacity:0.5}100%{opacity:1} }

.flash { animation: flash 0.15s; }

</style>

</head>

<body>

<div class=”bezel”>

<div class=”bezel-label”>ENG CALC PRO MK-IV</div>

<!– Screen –>

<div class=”screen-surround”>

<div class=”screen”>

<div class=”screen-header”>

<span class=”screen-id”>ENGCALC::4.1</span>

<div class=”screen-status”>

<span class=”st on” id=”angleStatus”>DEG</span>

<span class=”st on”>FLOAT</span>

<span class=”st on” id=”memStatus”>MEM:0</span>

</div>

</div>

<div class=”mode-row”>

<button class=”mode-pill active” onclick=”switchTab(‘calc’)”>CALC</button>

<button class=”mode-pill” onclick=”switchTab(‘units’)”>UNITS</button>

<button class=”mode-pill” onclick=”switchTab(‘formulas’)”>FORMULAS</button>

</div>

<div class=”expr-line” id=”exprLine”> </div>

<div class=”result-line” id=”resultLine”>0<span class=”cursor-block”></span></div>

<div class=”mem-strip”>

<span class=”mem-lbl” id=”memInd”>MEM </span>

<span class=”mem-lbl” id=”ansInd”>ANS </span>

</div>

</div>

</div>

<!– CALCULATOR PANEL –>

<div id=”panel-calc”>

<div class=”btn-grid”>

<button class=”key mem” onclick=”ms()”><div class=”key-face”><span class=”key-top”>MEM</span><span class=”key-main”>MS</span></div></button>

<button class=”key mem” onclick=”mr()”><div class=”key-face”><span class=”key-top”>RCL</span><span class=”key-main”>MR</span></div></button>

<button class=”key mem” onclick=”mc()”><div class=”key-face”><span class=”key-top”>CLR</span><span class=”key-main”>MC</span></div></button>

<button class=”key mem” onclick=”mplus()”><div class=”key-face”><span class=”key-top”>ADD</span><span class=”key-main”>M+</span></div></button>

<button class=”key mem” onclick=”mminus()”><div class=”key-face”><span class=”key-top”>SUB</span><span class=”key-main”>M</span></div></button>

<button class=”key fn” onclick=”ins(‘sin(‘)”><div class=”key-face”><span class=”key-top”>TRIG</span><span class=”key-main”>SIN</span></div></button>

<button class=”key fn” onclick=”ins(‘cos(‘)”><div class=”key-face”><span class=”key-top”>TRIG</span><span class=”key-main”>COS</span></div></button>

<button class=”key fn” onclick=”ins(‘tan(‘)”><div class=”key-face”><span class=”key-top”>TRIG</span><span class=”key-main”>TAN</span></div></button>

<button class=”key fn” onclick=”ins(‘log(‘)”><div class=”key-face”><span class=”key-top”>BASE10</span><span class=”key-main”>LOG</span></div></button>

<button class=”key fn” onclick=”ins(‘ln(‘)”><div class=”key-face”><span class=”key-top”>NAT</span><span class=”key-main”>LN</span></div></button>

<button class=”key fn” onclick=”ins(‘(‘)”><div class=”key-face”><span class=”key-top”>ROOT</span><span class=”key-main”>x</span></div></button>

<button class=”key fn” onclick=”ins(‘^2’)”><div class=”key-face”><span class=”key-top”>SQ</span><span class=”key-main”>x</span></div></button>

<button class=”key fn” onclick=”ins(‘^’)”><div class=”key-face”><span class=”key-top”>PWR</span><span class=”key-main”>x</span></div></button>

<button class=”key fn” onclick=”ins(‘abs(‘)”><div class=”key-face”><span class=”key-top”>ABS</span><span class=”key-main”>|x|</span></div></button>

<button class=”key fn” onclick=”ins(”)”><div class=”key-face”><span class=”key-top”>CONST</span><span class=”key-main”></span></div></button>

<button class=”key clr” onclick=”clearAll()”><div class=”key-face”><span class=”key-top”>RESET</span><span class=”key-main”>AC</span></div></button>

<button class=”key clr” onclick=”ce()”><div class=”key-face”><span class=”key-top”>ENTRY</span><span class=”key-main”>CE</span></div></button>

<button class=”key fn” onclick=”bksp()”><div class=”key-face”><span class=”key-top”>DEL</span><span class=”key-main”></span></div></button>

<button class=”key fn” onclick=”ins(‘%’)”><div class=”key-face”><span class=”key-top”>MOD</span><span class=”key-main”>%</span></div></button>

<button class=”key op” onclick=”ins(‘/’)”><div class=”key-face”><span class=”key-top”>DIV</span><span class=”key-main”></span></div></button>

<button class=”key num” onclick=”ins(‘7’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>7</span></div></button>

<button class=”key num” onclick=”ins(‘8’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>8</span></div></button>

<button class=”key num” onclick=”ins(‘9’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>9</span></div></button>

<button class=”key fn” onclick=”ins(‘e’)”><div class=”key-face”><span class=”key-top”>EULER</span><span class=”key-main”>e</span></div></button>

<button class=”key op” onclick=”ins(‘*’)”><div class=”key-face”><span class=”key-top”>MUL</span><span class=”key-main”></span></div></button>

<button class=”key num” onclick=”ins(‘4’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>4</span></div></button>

<button class=”key num” onclick=”ins(‘5’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>5</span></div></button>

<button class=”key num” onclick=”ins(‘6’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>6</span></div></button>

<button class=”key fn” onclick=”ins(‘(‘)”><div class=”key-face”><span class=”key-top”>OPEN</span><span class=”key-main”>(</span></div></button>

<button class=”key op” onclick=”ins(‘-‘)”><div class=”key-face”><span class=”key-top”>SUB</span><span class=”key-main”></span></div></button>

<button class=”key num” onclick=”ins(‘1’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>1</span></div></button>

<button class=”key num” onclick=”ins(‘2’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>2</span></div></button>

<button class=”key num” onclick=”ins(‘3’)”><div class=”key-face”><span class=”key-top”> </span><span class=”key-main”>3</span></div></button>

<button class=”key fn” onclick=”ins(‘)’)”><div class=”key-face”><span class=”key-top”>CLOSE</span><span class=”key-main”>)</span></div></button>

<button class=”key op” onclick=”ins(‘+’)”><div class=”key-face”><span class=”key-top”>ADD</span><span class=”key-main”>+</span></div></button>

<button class=”key num span2″ onclick=”ins(‘0’)”><div class=”key-face” style=”text-align:left;padding-left:16px”><span class=”key-top”> </span><span class=”key-main”>0</span></div></button>

<button class=”key num” onclick=”ins(‘.’)”><div class=”key-face”><span class=”key-top”>DEC</span><span class=”key-main”>.</span></div></button>

<button class=”key fn” onclick=”ins(‘E’)”><div class=”key-face”><span class=”key-top”>SCI</span><span class=”key-main”>EXP</span></div></button>

<button class=”key eq” onclick=”calculate()”><div class=”key-face”><span class=”key-top”>EXEC</span><span class=”key-main”>=</span></div></button>

</div>

</div>

<!– UNIT CONVERTER –>

<div id=”panel-units” class=”converter-panel”>

<div class=”cat-strip” id=”catStrip”></div>

<div class=”conv-fields”>

<div class=”conv-grp”>

<span class=”conv-lbl”>FROM</span>

<select class=”conv-sel” id=”fromUnit” onchange=”doConvert()”></select>

<input class=”conv-inp” type=”number” id=”fromVal” value=”1″ oninput=”doConvert()”>

</div>

<div class=”conv-arrow-mid”></div>

<div class=”conv-grp”>

<span class=”conv-lbl”>TO</span>

<select class=”conv-sel” id=”toUnit” onchange=”doConvert()”></select>

<input class=”conv-inp” type=”text” id=”toVal” readonly>

</div>

</div>

</div>

<!– FORMULAS –>

<div id=”panel-formulas” class=”formulas-panel”></div>

<!– Footer –>

<div class=”footer”>

<span class=”footer-info” id=”statusBar”>READY </span>

<div class=”angle-toggle”>

<button class=”ang-btn active” id=”degBtn” onclick=”setAngle(‘deg’)”>DEG</button>

<button class=”ang-btn” id=”radBtn” onclick=”setAngle(‘rad’)”>RAD</button>

</div>

</div>

</div>

<script>

// STATE

let expr = ”, mem = 0, lastAns = null, angleMode = ‘deg’, hasResult = false;

// DISPLAY

function render() {

document.getElementById(‘memInd’).className = ‘mem-lbl’ + (mem!==0?’ lit’:”);

document.getElementById(‘memInd’).textContent = mem!==0?`MEM ${fmt(mem)}`:’MEM ‘;

document.getElementById(‘ansInd’).textContent = lastAns!==null?`ANS ${fmt(lastAns)}`:’ANS ‘;

document.getElementById(‘memStatus’).textContent = `MEM:${mem!==0?String(fmt(mem)).slice(0,8):’0′}`;

}

function showResult(val, isErr) {

const el = document.getElementById(‘resultLine’);

el.className = ‘result-line’ + (isErr?’ error’:”);

el.innerHTML = val + ‘<span class=”cursor-block”></span>’;

}

function fmt(n) {

if (!isFinite(n)) return ‘OVERFLOW’;

if (Math.abs(n)>=1e13||(Math.abs(n)<1e-7&&n!==0)) return n.toExponential(6).toUpperCase();

return parseFloat(n.toPrecision(10)).toString();

}

// INPUT

function ins(t) {

if (hasResult && /^[0-9e.]$/.test(t)) expr = ”;

hasResult = false;

expr += t;

showResult(expr.slice(-26)||’0′);

render();

}

function clearAll() { expr=”; hasResult=false; showResult(‘0’); render(); setStatus(‘CLEARED’); }

function ce() { expr=expr.slice(0,-1); showResult(expr||’0′); render(); }

function bksp() { ce(); }

// CALCULATE

function calculate() {

if (!expr.trim()) return;

try {

let e = expr;

e = e.replace(//g,’Math.PI’);

e = e.replace(/beb/g,’Math.E’);

if (angleMode===’deg’) {

e = e.replace(/sin(/g,’Math.sin(Math.PI/180*’);

e = e.replace(/cos(/g,’Math.cos(Math.PI/180*’);

e = e.replace(/tan(/g,’Math.tan(Math.PI/180*’);

} else {

e = e.replace(/sin(/g,’Math.sin(‘);

e = e.replace(/cos(/g,’Math.cos(‘);

e = e.replace(/tan(/g,’Math.tan(‘);

}

e = e.replace(/ln(/g,’Math.log(‘);

e = e.replace(/log(/g,’Math.log10(‘);

e = e.replace(/(/g,’Math.sqrt(‘);

e = e.replace(/abs(/g,’Math.abs(‘);

e = e.replace(/^/g,’**’);

e = e.replace(/(d+(?:.d+)?)E(-?d+)/g,(_,a,b)=>`(${a}*1e${b})`);

e = e.replace(/(d+(?:.d+)?)%/g,(_,n)=>`(${n}/100)`);

const r = Function(‘”use strict”;return(‘+e+’)’)();

if (!isFinite(r)) throw 0;

document.getElementById(‘exprLine’).textContent = expr + ‘ =’;

const f = fmt(r);

showResult(f);

lastAns = r; hasResult = true; expr = f;

render();

setStatus(‘OK ‘+new Date().toLocaleTimeString());

document.getElementById(‘resultLine’).classList.add(‘flash’);

setTimeout(()=>document.getElementById(‘resultLine’).classList.remove(‘flash’),180);

} catch(err) {

showResult(‘SYNTAX ERR’,true);

setStatus(‘ERR CHECK INPUT’);

hasResult = false;

}

}

document.addEventListener(‘keydown’, ev => {

const tag = document.activeElement.tagName;

if (tag===’INPUT’||tag===’SELECT’) return;

if (/^[0-9]$/.test(ev.key)) ins(ev.key);

else if (‘+-*/’.includes(ev.key)) ins(ev.key);

else if (ev.key===’.’) ins(‘.’);

else if (ev.key===’Enter’||ev.key===’=’) calculate();

else if (ev.key===’Backspace’) bksp();

else if (ev.key===’Escape’) clearAll();

else if (ev.key==='(‘) ins(‘(‘);

else if (ev.key===’)’) ins(‘)’);

else if (ev.key===’^’) ins(‘^’);

});

// MEMORY

function ms() { if(lastAns!==null){mem=lastAns;render();} }

function mr() { if(mem!==0) ins(String(mem)); }

function mc() { mem=0; render(); }

function mplus() { if(lastAns!==null){mem+=lastAns;render();} }

function mminus() { if(lastAns!==null){mem-=lastAns;render();} }

// ANGLE

function setAngle(m) {

angleMode = m;

document.getElementById(‘degBtn’).className=’ang-btn’+(m===’deg’?’ active’:”);

document.getElementById(‘radBtn’).className=’ang-btn’+(m===’rad’?’ active’:”);

document.getElementById(‘angleStatus’).textContent = m.toUpperCase();

}

function setStatus(msg) { document.getElementById(‘statusBar’).textContent = msg+’ ‘; }

// TABS

function switchTab(name) {

[‘calc’,’units’,’formulas’].forEach((n,i)=>{

document.querySelectorAll(‘.mode-pill’)[i].classList.toggle(‘active’,n===name);

});

document.getElementById(‘panel-calc’).style.display = name===’calc’?”:’none’;

const up = document.getElementById(‘panel-units’);

up.style.display = name===’units’?’block’:’none’;

up.className = name===’units’?’converter-panel active’:’converter-panel’;

const fp = document.getElementById(‘panel-formulas’);

fp.style.display = name===’formulas’?’block’:’none’;

fp.className = name===’formulas’?’formulas-panel active’:’formulas-panel’;

}

// UNIT CONVERTER

const UNITS = {

length: {label:’LENGTH’, u:[‘meter’,’kilometer’,’centimeter’,’millimeter’,’mile’,’yard’,’foot’,’inch’,’nautical mi’],b:[1,1000,.01,.001,1609.344,.9144,.3048,.0254,1852]},

mass: {label:’MASS’, u:[‘kilogram’,’gram’,’milligram’,’tonne’,’pound’,’ounce’],b:[1,.001,1e-6,1000,.453592,.0283495]},

temp: {label:’TEMP’, u:[‘Celsius’,’Fahrenheit’,’Kelvin’],b:null},

area: {label:’AREA’, u:[‘m’,’km’,’cm’,’hectare’,’acre’,’ft’],b:[1,1e6,1e-4,1e4,4046.86,.092903]},

pressure: {label:’PRESSURE’, u:[‘pascal’,’kPa’,’MPa’,’bar’,’psi’,’atm’],b:[1,1000,1e6,1e5,6894.76,101325]},

energy: {label:’ENERGY’, u:[‘joule’,’kJ’,’MJ’,’calorie’,’kcal’,’kWh’,’BTU’],b:[1,1000,1e6,4.184,4184,3.6e6,1055.06]},

power: {label:’POWER’, u:[‘watt’,’kilowatt’,’megawatt’,’horsepower’],b:[1,1000,1e6,745.7]},

speed: {label:’SPEED’, u:[‘m/s’,’km/h’,’mph’,’knot’,’ft/s’],b:[1,.277778,.44704,.514444,.3048]},

};

let curCat = ‘length’;

function buildCatStrip() {

document.getElementById(‘catStrip’).innerHTML = Object.keys(UNITS).map(k=>

`<button class=”cat-key${k===curCat?’ active’:”}” onclick=”setCat(‘${k}’)”>${UNITS[k].label}</button>`

).join(”);

}

function setCat(cat) { curCat=cat; buildCatStrip(); fillUnits(); doConvert(); }

function fillUnits() {

const u = UNITS[curCat].u;

const html = u.map((n,i)=>`<option value=”${i}”>${n}</option>`).join(”);

document.getElementById(‘fromUnit’).innerHTML = html;

document.getElementById(‘toUnit’).innerHTML = html;

document.getElementById(‘toUnit’).value = 1;

}

function doConvert() {

const val = parseFloat(document.getElementById(‘fromVal’).value);

if (isNaN(val)) { document.getElementById(‘toVal’).value=”; return; }

const fi = +document.getElementById(‘fromUnit’).value;

const ti = +document.getElementById(‘toUnit’).value;

const cat = UNITS[curCat];

let r;

if (curCat===’temp’) {

let c = fi===0?val:fi===1?(val-32)*5/9:val-273.15;

r = ti===0?c:ti===1?c*9/5+32:c+273.15;

} else {

r = val*cat.b[fi]/cat.b[ti];

}

document.getElementById(‘toVal’).value = parseFloat(r.toPrecision(8));

}

buildCatStrip(); fillUnits();

// FORMULAS

const FORMULAS = [

{name:”Ohm’s Law”,cat:”ELEC”,eq:”V = I R”,

f:[{id:’I’,l:’Current I (A)’},{id:’R’,l:’Resistance R ()’}],

fn:v=>`V = ${fmt(v.I*v.R)} V`},

{name:”Electric Power”,cat:”ELEC”,eq:”P = V I”,

f:[{id:’V’,l:’Voltage V (V)’},{id:’I’,l:’Current I (A)’}],

fn:v=>`P = ${fmt(v.V*v.I)} W`},

{name:”Capacitor Energy”,cat:”ELEC”,eq:”E = CV”,

f:[{id:’C’,l:’Capacitance C (F)’},{id:’V’,l:’Voltage V (V)’}],

fn:v=>`E = ${fmt(.5*v.C*v.V**2)} J`},

{name:”Kinetic Energy”,cat:”MECH”,eq:”KE = mv”,

f:[{id:’m’,l:’Mass m (kg)’},{id:’v’,l:’Velocity v (m/s)’}],

fn:v=>`KE = ${fmt(.5*v.m*v.v**2)} J`},

{name:”Gravitational PE”,cat:”MECH”,eq:”PE = mgh”,

f:[{id:’m’,l:’Mass m (kg)’},{id:’g’,l:’g (m/s)’},{id:’h’,l:’Height h (m)’}],

fn:v=>`PE = ${fmt(v.m*v.g*v.h)} J`},

{name:”Newton 2nd Law”,cat:”MECH”,eq:”F = ma”,

f:[{id:’m’,l:’Mass m (kg)’},{id:’a’,l:’Accel a (m/s)’}],

fn:v=>`F = ${fmt(v.m*v.a)} N`},

{name:”Torque”,cat:”MECH”,eq:” = F r”,

f:[{id:’F’,l:’Force F (N)’},{id:’r’,l:’Radius r (m)’}],

fn:v=>` = ${fmt(v.F*v.r)} Nm`},

{name:”Pressure”,cat:”FLUID”,eq:”P = F / A”,

f:[{id:’F’,l:’Force F (N)’},{id:’A’,l:’Area A (m)’}],

fn:v=>`P = ${fmt(v.F/v.A)} Pa`},

{name:”Reynolds Number”,cat:”FLUID”,eq:”Re = vL/”,

f:[{id:’rho’,l:’Density (kg/m)’},{id:’v’,l:’Velocity v’},{id:’L’,l:’Length L (m)’},{id:’mu’,l:’Viscosity (Pas)’}],

fn:v=>`Re = ${fmt(v.rho*v.v*v.L/v.mu)}`},

{name:”Stress”,cat:”STRUCT”,eq:” = F / A”,

f:[{id:’F’,l:’Force F (N)’},{id:’A’,l:’Area A (m)’}],

fn:v=>` = ${fmt(v.F/v.A)} Pa`},

{name:”Young’s Modulus”,cat:”STRUCT”,eq:”E = /”,

f:[{id:’sigma’,l:’Stress (Pa)’},{id:’eps’,l:’Strain ‘}],

fn:v=>`E = ${fmt(v.sigma/v.eps)} Pa`},

{name:”Ideal Gas Law”,cat:”THERMO”,eq:”PV = nRT”,

f:[{id:’n’,l:’Moles n’},{id:’T’,l:’Temp T (K)’},{id:’V’,l:’Volume V (m)’}],

fn:v=>`P = ${fmt(v.n*8.314*v.T/v.V)} Pa`},

{name:”Heat Transfer”,cat:”THERMO”,eq:”Q = mcT”,

f:[{id:’m’,l:’Mass m (kg)’},{id:’c’,l:’Sp. heat (J/kgK)’},{id:’dT’,l:’T (K)’}],

fn:v=>`Q = ${fmt(v.m*v.c*v.dT)} J`},

{name:”Decibels”,cat:”SIGNAL”,eq:”dB = 20log(V/V)”,

f:[{id:’V’,l:’Signal V’},{id:’V0′,l:’Reference V’}],

fn:v=>`${fmt(20*Math.log10(v.V/v.V0))} dB`},

];

function buildFormulas() {

document.getElementById(‘panel-formulas’).innerHTML = FORMULAS.map((f,i)=>`

<div class=”fcard” id=”fc${i}” onclick=”toggleF(${i})”>

<div class=”fcard-head”>

<span class=”fcard-title”>${f.name}</span>

<span class=”fcard-eq”>${f.eq}</span>

<span class=”fcard-cat”>${f.cat}</span>

</div>

<div class=”fcard-body” id=”fb${i}”>

${f.f.map(fi=>`

<div class=”finp-grp”>

<span class=”finp-lbl”>${fi.l}</span>

<input class=”finp” type=”number” id=”fi${i}_${fi.id}” onclick=”event.stopPropagation()” oninput=”calcF(${i})”>

</div>`).join(”)}

<button class=”fcard-go” onclick=”event.stopPropagation();calcF(${i})”>CALCULATE</button>

<div class=”fcard-ans” id=”fa${i}”></div>

</div>

</div>`).join(”);

}

function toggleF(i) { document.getElementById(‘fc’+i).classList.toggle(‘open’); }

function calcF(i) {

const f = FORMULAS[i]; const vals = {}; let ok = true;

f.f.forEach(fi=>{ const v=parseFloat(document.getElementById(`fi${i}_${fi.id}`).value); if(isNaN(v)){ok=false;}else vals[fi.id]=v; });

if (!ok) return;

try {

document.getElementById(‘fa’+i).textContent = ‘ ‘+f.fn(vals);

document.getElementById(‘fc’+i).classList.add(‘has-ans’);

} catch(e) {

document.getElementById(‘fa’+i).textContent = ‘ERROR’;

document.getElementById(‘fc’+i).classList.add(‘has-ans’);

}

}

buildFormulas();

render();

</script>

</body>

</html>

WRITE MY PAPER

Comments

Leave a Reply