Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>Scientific Calculator</title> | |
<!-- Math.js for evaluation --> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/browser/math.min.js"></script> | |
<!-- KaTeX for rendering math --> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-" crossorigin="anonymous"> | |
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-" crossorigin="anonymous"></script> | |
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-" crossorigin="anonymous"></script> | |
<style> | |
body { | |
font-family: sans-serif; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
height: 100vh; | |
background: #f2f2f2; | |
} | |
.calculator { | |
background: white; | |
border-radius: 8px; | |
box-shadow: 0 4px 12px rgba(0,0,0,0.1); | |
padding: 16px; | |
width: 360px; | |
} | |
.display { | |
width: 100%; | |
height: 48px; | |
font-size: 1.25rem; | |
padding: 8px; | |
border: 1px solid #ccc; | |
border-radius: 4px; | |
box-sizing: border-box; | |
} | |
#preview { | |
min-height: 32px; | |
margin: 8px 0 12px; | |
padding: 4px; | |
background: #fafafa; | |
border: 1px solid #ddd; | |
border-radius: 4px; | |
} | |
.tabs { display: flex; margin-bottom: 8px; } | |
.tab { | |
flex: 1; | |
text-align: center; | |
padding: 8px; | |
cursor: pointer; | |
border-bottom: 2px solid transparent; | |
} | |
.tab.active { border-color: #007bff; color: #007bff; } | |
.buttons { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; } | |
button { padding: 12px; font-size: 1rem; border: 1px solid #aaa; border-radius: 4px; background: #e6e6e6; cursor: pointer; transition: background 0.2s; } | |
button:hover { background: #d4d4d4; } | |
.op { background: #bbb; } | |
.wide { grid-column: span 2; } | |
</style> | |
</head> | |
<body> | |
<div class="calculator"> | |
<input type="text" class="display" id="display" readonly /> | |
<div id="preview"></div> | |
<div class="tabs"> | |
<div class="tab active" data-mode="main">main</div> | |
<div class="tab" data-mode="abc">abc</div> | |
<div class="tab" data-mode="func">func</div> | |
<div class="tab" id="toggle-mode">RAD</div> | |
</div> | |
<div class="buttons" id="buttons-container"> | |
<!-- main grid --> | |
<button data-cmd="7">7</button><button data-cmd="8">8</button><button data-cmd="9">9</button><button data-cmd="/" class="op">÷</button> | |
<button data-cmd="4">4</button><button data-cmd="5">5</button><button data-cmd="6">6</button><button data-cmd="*" class="op">×</button> | |
<button data-cmd="1">1</button><button data-cmd="2">2</button><button data-cmd="3">3</button><button data-cmd="-" class="op">−</button> | |
<button data-cmd="0">0</button><button data-cmd=".">.</button><button data-cmd="ans">ans</button><button data-cmd="+" class="op">+</button> | |
<button data-cmd="%">%</button><button data-cmd="frac">a/b</button><button data-cmd="back">←</button><button data-cmd="forward">→</button> | |
<button class="wide" data-cmd="clear">C</button><button data-cmd="del">DEL</button><button class="wide" data-cmd="enter">=</button> | |
</div> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', () => { | |
const display = document.getElementById('display'); | |
const preview = document.getElementById('preview'); | |
let ans = ''; | |
let mode = 'main'; | |
let angleMode = 'deg'; | |
// update KaTeX preview | |
function updatePreview() { | |
try { | |
katex.render(display.value || ' ', preview, {throwOnError:false}); | |
} catch {} | |
} | |
// evaluate with math.js | |
function evaluate(expr) { | |
try { | |
math.config({}); | |
if (angleMode === 'deg') { | |
expr = expr.replace(/(sin|cos|tan)\(/g, match => `(${match}"deg", `); | |
} | |
const result = math.evaluate(expr); | |
ans = result.toString(); | |
return ans; | |
} catch { | |
return 'Error'; | |
} | |
} | |
// button logic | |
document.getElementById('buttons-container').addEventListener('click', e => { | |
if (!e.target.matches('button')) return; | |
const cmd = e.target.dataset.cmd; | |
switch (cmd) { | |
case 'clear': display.value = ''; break; | |
case 'del': display.value = display.value.slice(0, -1); break; | |
case 'ans': display.value += ans; break; | |
case 'enter': display.value = evaluate(display.value); break; | |
case 'frac': display.value += '/'; break; | |
case 'square': display.value += '^(2)'; break; | |
case '^': display.value += '^('; break; | |
case 'sqrt(': case 'nthroot(': case 'abs(': case 'sin(': case 'cos(': case 'tan(': case '(': case ')': case ',': case 'pi': | |
display.value += cmd === 'pi' ? 'pi' : cmd; | |
break; | |
default: | |
if (/^[0-9.+\-*/%^]$/.test(cmd)) display.value += cmd; | |
} | |
updatePreview(); | |
}); | |
// keyboard shortcuts | |
document.addEventListener('keydown', e => { | |
const k = e.key; | |
if (k === 'Enter') { display.value = evaluate(display.value); updatePreview(); e.preventDefault(); } | |
else if (k === 'Backspace') { display.value = display.value.slice(0, -1); updatePreview(); e.preventDefault(); } | |
else if (k === 'p') { display.value += 'pi'; updatePreview(); e.preventDefault(); } | |
else if (k === 's') { display.value += 'sin('; updatePreview(); e.preventDefault(); } | |
else if (k === 'c') { display.value += 'cos('; updatePreview(); e.preventDefault(); } | |
else if (k === 't') { display.value += 'tan('; updatePreview(); e.preventDefault(); } | |
}); | |
// modes & toggle | |
const modeButtons = { | |
abc: [{label:'a²',cmd:'square'},{label:'a^b',cmd:'^'},{label:'|a|',cmd:'abs('},{label:'√',cmd:'sqrt('},{label:'ⁿ√',cmd:'nthroot('},{label:'π',cmd:'pi'}], | |
func: [{label:'sin',cmd:'sin('},{label:'cos',cmd:'cos('},{label:'tan',cmd:'tan('},{label:'(',cmd:'('},{label:')',cmd:')'},{label:',',cmd:','}] | |
}; | |
function renderMode() { | |
const c = document.getElementById('buttons-container'); | |
while (c.children.length > 20) c.removeChild(c.lastChild); | |
if (mode !== 'main') modeButtons[mode].forEach(b=>{ const btn=document.createElement('button');btn.textContent=b.label;btn.dataset.cmd=b.cmd;c.insertBefore(btn,c.firstChild); }); | |
} | |
document.querySelectorAll('.tab[data-mode]').forEach(tab => tab.addEventListener('click', () => { | |
document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active')); | |
tab.classList.add('active'); mode=tab.dataset.mode; renderMode(); updatePreview(); | |
})); | |
document.getElementById('toggle-mode').addEventListener('click', e => { angleMode = angleMode==='deg'?'rad':'deg'; e.target.textContent = angleMode.toUpperCase(); }); | |
renderMode(); updatePreview(); | |
}); | |
</script> | |
</body> | |
</html> | |