Scientific Calculator: Extreme Premium Edition.
<
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CYBERPUNK CALCULATOR v3.0</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chart.js/3.9.1/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.8.0/math.min.js"></script>
<style>
:root {
--primary: #0a0a1a;
--secondary: #121432;
--accent: #00ffd5;
--accent-alt: #ff2a6d;
--text: #e0f7ff;
--display-bg: #050510;
--neon-glow: 0 0 10px rgba(0, 255, 213, 0.7), 0 0 20px rgba(0, 255, 213, 0.5), 0 0 30px rgba(0, 255, 213, 0.3);
--pink-glow: 0 0 10px rgba(255, 42, 109, 0.7), 0 0 20px rgba(255, 42, 109, 0.5), 0 0 30px rgba(255, 42, 109, 0.3);
}
@font-face {
font-family: 'Cyberpunk';
src: url('https://fonts.cdnfonts.com/css/blender-pro') format('woff2');
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Courier New', monospace;
background: linear-gradient(135deg, #000428, #082546);
margin: 0;
padding: 20px;
min-height: 100vh;
color: var(--text);
position: relative;
overflow-x: hidden;
}
body::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
linear-gradient(90deg, rgba(0, 255, 213, 0.07) 1px, transparent 1px),
linear-gradient(rgba(0, 255, 213, 0.07) 1px, transparent 1px);
background-size: 40px 40px;
z-index: -1;
}
.glitch-text {
position: relative;
text-shadow: 0 0 5px var(--accent);
animation: glitch 3s infinite;
}
@keyframes glitch {
0% { text-shadow: 0 0 5px var(--accent); }
1% { text-shadow: -2px 0 var(--accent-alt); }
2% { text-shadow: 2px 0 var(--accent); }
3% { text-shadow: 0 0 5px var(--accent); }
50% { text-shadow: 0 0 5px var(--accent); }
51% { text-shadow: 1px 0 var(--accent-alt); }
52% { text-shadow: -1px 0 var(--accent); }
53% { text-shadow: 0 0 5px var(--accent); }
100% { text-shadow: 0 0 5px var(--accent); }
}
.container {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
max-width: 1200px;
margin: 0 auto;
}
.header {
width: 100%;
text-align: center;
margin-bottom: 20px;
}
.header h1 {
font-size: 2.5rem;
color: var(--accent);
text-transform: uppercase;
letter-spacing: 2px;
margin-bottom: 5px;
}
.header p {
color: var(--accent-alt);
font-size: 1rem;
opacity: 0.8;
}
.calculator {
width: 400px;
background: var(--primary);
border-radius: 10px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.7);
border: 1px solid rgba(0, 255, 213, 0.3);
overflow: hidden;
position: relative;
}
.calculator::before {
content: "";
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, var(--accent), var(--accent-alt), var(--accent));
z-index: -1;
border-radius: 12px;
opacity: 0.5;
animation: border-flow 3s linear infinite;
}
@keyframes border-flow {
0% { background-position: 0 0; }
100% { background-position: 400% 0; }
}
.graph-container {
width: 600px;
background: var(--primary);
border-radius: 10px;
padding: 15px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.7);
border: 1px solid rgba(0, 255, 213, 0.3);
position: relative;
}
.graph-container::before {
content: "";
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, var(--accent-alt), var(--accent), var(--accent-alt));
z-index: -1;
border-radius: 12px;
opacity: 0.5;
animation: border-flow 3s linear infinite;
animation-delay: -1.5s;
}
.display {
padding: 25px;
background: var(--display-bg);
min-height: 120px;
text-align: right;
position: relative;
border-bottom: 1px solid rgba(0, 255, 213, 0.2);
}
.display::after {
content: "SYS//CALC-QBIT-V3";
position: absolute;
top: 5px;
left: 10px;
font-size: 10px;
color: var(--accent);
opacity: 0.6;
}
#input {
font-size: 20px;
color: var(--accent);
min-height: 28px;
font-family: 'Courier New', monospace;
position: relative;
overflow-wrap: break-word;
word-break: break-all;
}
#output {
font-size: 36px;
margin-top: 15px;
overflow-wrap: break-word;
word-break: break-all;
transition: all 0.2s ease;
}
.button-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 8px;
padding: 15px;
}
.btn {
border: none;
border-radius: 5px;
padding: 18px 0;
font-size: 18px;
cursor: pointer;
background: var(--secondary);
color: var(--text);
transition: all 0.15s;
position: relative;
overflow: hidden;
text-shadow: 0 0 3px rgba(224, 247, 255, 0.7);
}
.btn::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, var(--accent), transparent);
opacity: 0;
transition: opacity 0.3s;
}
.btn:hover::after {
opacity: 1;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.btn:active {
transform: translateY(1px);
}
.btn-operator { background: #1a1a4a; color: var(--accent); }
.btn-advanced { background: #25254a; color: var(--accent); font-size: 16px; }
.btn-equals {
background: var(--accent);
color: #000;
font-weight: bold;
box-shadow: var(--neon-glow);
}
.btn-clear { background: #3d0f22; color: var(--accent-alt); }
.btn-const { background: #2a206c; color: #c792ea; }
.btn-complex { background: #381f72; color: #ff9edb; }
.btn-rpn { background: #622a00; color: #ffae00; }
.btn-matrix { background: #432b63; color: #c77dff; }
.history-panel {
max-height: 100px;
overflow-y: auto;
margin-top: 10px;
padding: 10px;
background: rgba(0, 0, 0, 0.3);
border-radius: 5px;
border: 1px solid rgba(0, 255, 213, 0.1);
font-size: 14px;
}
.history-panel::-webkit-scrollbar {
width: 5px;
}
.history-panel::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.2);
}
.history-panel::-webkit-scrollbar-thumb {
background: var(--accent);
border-radius: 5px;
}
.history-item {
padding: 5px;
cursor: pointer;
border-bottom: 1px solid rgba(0, 255, 213, 0.1);
transition: all 0.2s;
}
.history-item:hover {
background: rgba(0, 255, 213, 0.1);
padding-left: 10px;
}
.tabs {
display: flex;
margin-bottom: 10px;
}
.tab {
padding: 10px 15px;
background: var(--secondary);
cursor: pointer;
border-radius: 5px 5px 0 0;
margin-right: 5px;
position: relative;
overflow: hidden;
transition: all 0.3s;
}
.tab::before {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 2px;
background: var(--accent);
transform: scaleX(0);
transition: transform 0.3s;
}
.tab:hover::before {
transform: scaleX(0.8);
}
.tab.active {
background: var(--accent);
color: #000;
}
.tab.active::before {
transform: scaleX(1);
background: var(--accent-alt);
}
.mode-indicator {
position: absolute;
top: 10px;
right: 10px;
font-size: 12px;
padding: 3px 6px;
border-radius: 3px;
background: rgba(0, 0, 0, 0.3);
border: 1px solid var(--accent);
color: var(--accent);
opacity: 0;
transition: opacity 0.3s;
}
.mode-indicator.active {
opacity: 1;
}
#matrixInput {
width: 100%;
background: #16213e;
color: var(--text);
border: 1px solid rgba(0, 255, 213, 0.3);
padding: 10px;
border-radius: 5px;
font-family: 'Courier New', monospace;
resize: vertical;
margin-bottom: 10px;
}
#matrixInput:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 2px rgba(0, 255, 213, 0.2);
}
#matrixResult {
margin-top: 10px;
padding: 10px;
background: rgba(0, 0, 0, 0.2);
border-radius: 5px;
border: 1px solid rgba(0, 255, 213, 0.1);
}
/* Logo and decorative elements */
.logo {
position: absolute;
top: 10px;
left: 10px;
font-size: 14px;
color: var(--accent);
z-index: 100;
}
.decoration {
position: fixed;
bottom: 20px;
right: 20px;
font-size: 10px;
color: var(--accent);
opacity: 0.3;
z-index: -1;
}
@media (max-width: 992px) {
.calculator, .graph-container {
width: 90%;
margin: 0 auto;
}
}
</style>
</head>
<body>
<div class="header">
<h1 class="glitch-text">CYBERPUNK CALCULATOR v3.0</h1>
<p>QUANTUM COMPUTATIONAL MATRIX SYSTEM</p>
</div>
<div class="container">
<div class="calculator">
<div class="mode-indicator" id="rpnIndicator">RPN</div>
<div class="display">
<div id="input"></div>
<div id="output">0</div>
<div class="history-panel" id="history"></div>
</div>
<div class="button-grid">
<button class="btn btn-clear" onclick="clearAll()">AC</button>
<button class="btn btn-clear" onclick="backspace()">⌫</button>
<button class="btn btn-advanced" onclick="addToInput('%')">%</button>
<button class="btn btn-advanced" onclick="addToInput('√(')">√</button>
<button class="btn btn-operator" onclick="addToInput('^')">^</button>
<button class="btn btn-advanced" onclick="addToInput('sin(')">sin</button>
<button class="btn btn-advanced" onclick="addToInput('cos(')">cos</button>
<button class="btn btn-advanced" onclick="addToInput('tan(')">tan</button>
<button class="btn btn-operator" onclick="addToInput('/')">/</button>
<button class="btn btn-const" onclick="addToInput('π')">π</button>
<button class="btn btn-advanced" onclick="addToInput('log(')">log</button>
<button class="btn btn-advanced" onclick="addToInput('ln(')">ln</button>
<button class="btn btn-advanced" onclick="addToInput('(')">(</button>
<button class="btn btn-advanced" onclick="addToInput(')')">)</button>
<button class="btn btn-operator" onclick="addToInput('*')">×</button>
<button class="btn btn-advanced" onclick="addToInput('!')">x!</button>
<button class="btn" onclick="addToInput('7')">7</button>
<button class="btn" onclick="addToInput('8')">8</button>
<button class="btn" onclick="addToInput('9')">9</button>
<button class="btn btn-operator" onclick="addToInput('-')">−</button>
<button class="btn btn-complex" onclick="addToInput('i')">i</button>
<button class="btn" onclick="addToInput('4')">4</button>
<button class="btn" onclick="addToInput('5')">5</button>
<button class="btn" onclick="addToInput('6')">6</button>
<button class="btn btn-operator" onclick="addToInput('+')">+</button>
<button class="btn btn-rpn" onclick="toggleRPN()" id="rpnButton">RPN</button>
<button class="btn" onclick="addToInput('1')">1</button>
<button class="btn" onclick="addToInput('2')">2</button>
<button class="btn" onclick="addToInput('3')">3</button>
<button class="btn btn-equals" onclick="calculate()">=</button>
<button class="btn btn-matrix" onclick="addToInput('[')">[ ]</button>
<button class="btn" onclick="addToInput('0')">0</button>
<button class="btn" onclick="addToInput('.')">.</button>
<button class="btn btn-advanced" onclick="addToInput('e')">e</button>
<button class="btn btn-advanced" onclick="openPlot()">PLOT</button>
</div>
</div>
<div class="graph-container">
<div class="tabs">
<div class="tab active" id="graphTab" onclick="switchTab('graph')">Visualizer</div>
<div class="tab" id="matrixTab" onclick="switchTab('matrix')">Matrix Lab</div>
<div class="tab" id="plotTab" onclick="switchTab('plot')">Function Plot</div>
</div>
<div id="graphPanel" style="display:block;">
<canvas id="graphCanvas" style="width:100%; height:400px;"></canvas>
</div>
<div id="matrixEditor" style="display:none;">
<textarea id="matrixInput" rows="5" placeholder="Enter matrix operations (Example: [[1,2],[3,4]] * [[5,6],[7,8]])"></textarea>
<div class="button-grid" style="grid-template-columns: repeat(3, 1fr);">
<button class="btn btn-matrix" onclick="insertMatrixTemplate('identity')">Identity</button>
<button class="btn btn-matrix" onclick="insertMatrixTemplate('zero')">Zero</button>
<button class="btn btn-matrix" onclick="insertMatrixTemplate('random')">Random</button>
<button class="btn btn-matrix" onclick="insertMatrixOp('det')">Determinant</button>
<button class="btn btn-matrix" onclick="insertMatrixOp('inv')">Inverse</button>
<button class="btn btn-matrix" onclick="insertMatrixOp('transpose')">Transpose</button>
</div>
<button class="btn btn-equals" style="margin-top:10px; width:100%;" onclick="calculateMatrix()">Compute</button>
<div id="matrixResult"></div>
</div>
<div id="plotEditor" style="display:none;">
<div style="display:flex; margin-bottom:10px;">
<input type="text" id="functionInput" placeholder="Enter function of x (e.g., sin(x) + cos(x))"
style="flex:1; padding:10px; background:#16213e; color:var(--text); border:1px solid rgba(0,255,213,0.3); border-radius:5px;">
</div>
<div style="display:flex; gap:10px; margin-bottom:10px;">
<div style="flex:1;">
<label for="xMin" style="display:block; margin-bottom:5px; font-size:12px;">X Min</label>
<input type="number" id="xMin" value="-10" style="width:100%; padding:8px; background:#16213e; color:var(--text); border:1px solid rgba(0,255,213,0.3); border-radius:5px;">
</div>
<div style="flex:1;">
<label for="xMax" style="display:block; margin-bottom:5px; font-size:12px;">X Max</label>
<input type="number" id="xMax" value="10" style="width:100%; padding:8px; background:#16213e; color:var(--text); border:1px solid rgba(0,255,213,0.3); border-radius:5px;">
</div>
</div>
<button class="btn btn-equals" style="width:100%;" onclick="plotUserFunction()">Generate Plot</button>
</div>
</div>
</div>
<div class="decoration">
NETRUNNER//SYS-ACCESS::GRANTED<br>
QUANTUM-CORE::ACTIVATED<br>
CRYPTO-MATRIX::INITIALIZED<br>
CYB0X//V3.0::RUNNING
</div>
<script>
// Initialize Math.js with proper configuration
math.config({
number: 'number', // Use regular JavaScript numbers for better performance
precision: 64 // High precision for accurate calculations
});
// Global Variables
let input = "";
let isRPN = false;
let rpnStack = [];
let currentPlot = null;
// DOM elements
const inputElement = document.getElementById("input");
const outputElement = document.getElementById("output");
const historyElement = document.getElementById("history");
const rpnIndicator = document.getElementById("rpnIndicator");
const canvasContext = document.getElementById("graphCanvas").getContext('2d');
// Initialize the calculator
function initialize() {
loadHistory();
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
}
// Resize the canvas to fit its container
function resizeCanvas() {
const canvas = document.getElementById("graphCanvas");
const container = canvas.parentElement;
canvas.width = container.clientWidth;
canvas.height = 400;
if (currentPlot) {
redrawPlot();
}
}
// Load calculation history from localStorage
function loadHistory() {
try {
const history = JSON.parse(localStorage.getItem('cyberCalcHistory')) || [];
historyElement.innerHTML = history.map(item =>
`<div class="history-item" onclick="useHistory('${item.input.replace(/'/g, "\\'")}')">${item.input} = ${item.result}</div>`
).join('');
} catch (error) {
console.error("Error loading history:", error);
localStorage.removeItem('cyberCalcHistory');
historyElement.innerHTML = "";
}
}
// Save calculation to history
function saveToHistory(expr, result) {
try {
const history = JSON.parse(localStorage.getItem('cyberCalcHistory')) || [];
// Add to start of array, and convert complex results to string
history.unshift({
input: expr,
result: typeof result === 'object' && result.hasOwnProperty('re') ?
`${result.re} + ${result.im}i` : String(result)
});
// Keep only the most recent 100 entries
if (history.length > 100) history.pop();
localStorage.setItem('cyberCalcHistory', JSON.stringify(history));
loadHistory();
} catch (error) {
console.error("Error saving to history:", error);
}
}
// Use an item from history
function useHistory(expr) {
input = expr;
inputElement.textContent = input;
}
// Toggle RPN mode
function toggleRPN() {
isRPN = !isRPN;
rpnIndicator.classList.toggle('active', isRPN);
document.getElementById("rpnButton").style.boxShadow = isRPN ?
'0 0 10px #ffae00, 0 0 20px rgba(255, 174, 0, 0.5)' : 'none';
inputElement.textContent = isRPN ? "RPN Mode: " + rpnStack.join(" ") : input;
}
// RPN calculation
function calculateRPN() {
try {
if (rpnStack.length < 2) {
outputElement.textContent = "Need at least 2 numbers";
return;
}
// Parse the last input as an operator
const operator = input.trim();
// Need at least two operands
if (rpnStack.length < 2) {
outputElement.textContent = "Need more operands";
return;
}
// Pop the last two operands
const b = rpnStack.pop();
const a = rpnStack.pop();
let result;
// Perform operation
switch (operator) {
case '+': result = math.add(math.bignumber(a), math.bignumber(b)); break;
case '-': result = math.subtract(math.bignumber(a), math.bignumber(b)); break;
case '*': result = math.multiply(math.bignumber(a), math.bignumber(b)); break;
case '/': result = math.divide(math.bignumber(a), math.bignumber(b)); break;
case '^': result = math.pow(math.bignumber(a), math.bignumber(b)); break;
default:
outputElement.textContent = "Unknown operator";
return;
}
// Convert result to string and push back to stack
result = result.toString();
rpnStack.push(result);
// Display result
outputElement.textContent = result;
inputElement.textContent = "RPN Mode: " + rpnStack.join(" ");
// Save to history
saveToHistory(`${a} ${b} ${operator}`, result);
input = "";
} catch (error) {
console.error("RPN Error:", error);
outputElement.textContent = "RPN Error: " + error.message;
}
}
// Standard calculation
function calculate() {
if (isRPN) {
// In RPN mode and we have a new operator
if (input.trim() === "+" || input.trim() === "-" ||
input.trim() === "*" || input.trim() === "/" ||
input.trim() === "^") {
calculateRPN();
}
return;
}
if (!input.trim()) {
return; // Nothing to calculate
}
try {
// Normalize input for math.js
let expr = input
.replace(/×/g, "*")
.replace(/÷/g, "/")
.replace(/\^/g, "**")
.replace(/√\(/g, "sqrt(")
.replace(/π/g, "pi");
// Handle factorial separately as math.js doesn't support postfix notation
expr = expr.replace(/(\d+)!/g, (match, number) => {
return `factorial(${number})`;
});
// Handle special case for plotting
if (expr.startsWith("plot(")) {
plotFunction();
return;
}
// Evaluate expression
const result = math.evaluate(expr);
// Format and display result
if (typeof result === 'object' && result.hasOwnProperty('re')) {
// Handle complex numbers
outputElement.textContent = `${result.re} + ${result.im}i`;
} else if (Array.isArray(result)) {
// Handle matrices
outputElement.textContent = "Matrix result in Matrix tab";
switchTab('matrix');
document.getElementById('matrixResult').innerHTML =
`<strong>Result:</strong><br>${math.format(result, {precision: 4})}`;
} else {
// Handle scalars
outputElement.textContent = result;
}
// Save to history and clear input
saveToHistory(input, result);
input = "";
inputElement.textContent = "";
} catch (error) {
console.error("Calculation Error:", error);
outputElement.textContent = "Error: " + error.message;
}
}
// Plot a function defined in the input field
function plotFunction() {
try {
// Extract function and range from input
const regex = /plot\(\s*([^,]+),\s*([^,]+),\s*([^)]+)\s*\)/;
const match = input.match(regex);
if (!match || match.length < 4) {
throw new Error("Invalid plot format. Use: plot(f(x), xMin, xMax)");
}
const expr = match[1].trim();
const xMin = parseFloat(match[2]);
const xMax = parseFloat(match[3]);
if (isNaN(xMin) || isNaN(xMax)) {
throw new Error("Invalid range values");
}
// Create the plot
createFunctionPlot(expr, xMin, xMax);
// Display confirmation
outputElement.textContent = `Plotted: ${expr}`;
// Switch to graph tab
switchTab('graph');
} catch (error) {
console.error("Plot Error:", error);
outputElement.textContent = "Plot Error: " + error.message;
}
}
// Open the plot tab with current input as the function
function openPlot() {
document.getElementById('functionInput').value = input;
switchTab('plot');
}
// Plot a user function from the plot panel
function plotUserFunction() {
const functionExpr = document.getElementById('functionInput').value;
const xMin = parseFloat(document.getElementById('xMin').value);
const xMax = parseFloat(document.getElementById('xMax').value);
if (!functionExpr) {
document.getElementById('graphResult').innerHTML =
'<div style="color:var(--accent-alt)">Please enter a function</div>';
return;
}
if (isNaN(xMin) || isNaN(xMax)) {
document.getElementById('graphResult').innerHTML =
'<div style="color:var(--accent-alt)">Invalid range values</div>';
return;
}
try {
createFunctionPlot(functionExpr, xMin, xMax);
switchTab('graph');
} catch (error) {
document.getElementById('graphResult').innerHTML =
`<div style="color:var(--accent-alt)">Error: ${error.message}</div>`;
}
}
// Create a function plot with the specified expression and range
function createFunctionPlot(expr, xMin, xMax) {
try {
// Generate data points
const points = generatePoints(expr, xMin, xMax);
// Store current plot configuration
currentPlot = {
expr: expr,
xMin: xMin,
xMax: xMax,
points: points
};
// Create the plot
createPlot(points, expr);
} catch (error) {
console.error("Plot creation error:", error);
throw error;
}
}
// Generate points for the function
function generatePoints(expr, xMin, xMax, numPoints = 500) {
const points = [];
const step = (xMax - xMin) / numPoints;
const scope = {};
try {
// Pre-compile the expression for efficiency
const compiledExpr = math.compile(expr);
for (let x = xMin; x <= xMax; x += step) {
scope.x = x;
try {
const y = compiledExpr.evaluate(scope);
// Skip infinity, NaN or extremely large values
if (isFinite(y) && Math.abs(y) < 1e12) {
points.push({ x, y });
}
} catch (e) {
// Skip points that can't be evaluated
continue;
}
}
return points;
} catch (error) {
console.error("Error generating points:", error);
throw error;
}
}
// Create a plot using Chart.js
function createPlot(points, expr) {
const ctx = document.getElementById('graphCanvas').getContext('2d');
// Destroy existing chart if there is one
if (window.functionPlot instanceof Chart) {
window.functionPlot.destroy();
}
// Extract x and y values
const xValues = points.map(p => p.x);
const yValues = points.map(p => p.y);
// Create a new chart
window.functionPlot = new Chart(ctx, {
type: 'line',
data: {
labels: xValues,
datasets: [{
label: expr,
data: yValues,
borderColor: 'rgba(0, 255, 213, 1)',
backgroundColor: 'rgba(0, 255, 213, 0.1)',
borderWidth: 2,
tension: 0.1,
pointRadius: 0,
fill: false
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
type: 'linear',
position: 'bottom',
grid: {
color: 'rgba(0, 255, 213, 0.1)'
},
ticks: {
color: 'rgba(224, 247, 255, 0.7)'
},
title: {
display: true,
text: 'x',
color: 'rgba(224, 247, 255, 0.9)'
}
},
y: {
grid: {
color: 'rgba(0, 255, 213, 0.1)'
},
ticks: {
color: 'rgba(224, 247, 255, 0.7)'
},
title: {
display: true,
text: 'f(x)',
color: 'rgba(224, 247, 255, 0.9)'
}
}
},
plugins: {
legend: {
labels: {
color: 'rgba(224, 247, 255, 0.9)'
}
},
tooltip: {
backgroundColor: 'rgba(0, 0, 26, 0.8)',
borderColor: 'rgba(0, 255, 213, 0.8)',
borderWidth: 1,
titleColor: 'rgba(0, 255, 213, 1)',
bodyColor: 'rgba(224, 247, 255, 1)',
displayColors: false,
callbacks: {
title: function(tooltipItems) {
const x = tooltipItems[0].parsed.x;
return `x = ${x.toFixed(4)}`;
},
label: function(context) {
const y = context.parsed.y;
return `f(x) = ${y.toFixed(6)}`;
}
}
}
},
animation: {
duration: 1000,
easing: 'easeOutQuart'
}
}
});
}
// Redraw the current plot (used after resize)
function redrawPlot() {
if (currentPlot) {
createPlot(currentPlot.points, currentPlot.expr);
}
}
// Matrix operations
function calculateMatrix() {
try {
const matrixExpr = document.getElementById("matrixInput").value;
if (!matrixExpr.trim()) {
document.getElementById("matrixResult").innerHTML =
'<div style="color:var(--accent-alt)">Please enter a matrix expression</div>';
return;
}
// Evaluate the expression
const result = math.evaluate(matrixExpr);
// Format the result
let formattedResult;
if (Array.isArray(result)) {
// Format as a matrix
formattedResult = formatMatrix(result);
} else if (typeof result === 'number' || typeof result === 'object') {
// Format scalar or complex number
formattedResult = math.format(result, { precision: 6 });
} else {
formattedResult = String(result);
}
// Display the result
document.getElementById("matrixResult").innerHTML =
`<div style="margin-top:10px;"><strong style="color:var(--accent)">Result:</strong>
<div style="margin-top:5px;font-family:monospace;white-space:pre;">${formattedResult}</div></div>`;
} catch (error) {
console.error("Matrix calculation error:", error);
document.getElementById("matrixResult").innerHTML =
`<div style="color:var(--accent-alt)">Error: ${error.message}</div>`;
}
}
// Format a matrix for display
function formatMatrix(matrix) {
if (!Array.isArray(matrix)) return String(matrix);
// Check if it's a vector
if (!Array.isArray(matrix[0])) {
return '[ ' + matrix.map(val => math.format(val, { precision: 4 })).join(', ') + ' ]';
}
// It's a 2D matrix
let result = '';
for (let i = 0; i < matrix.length; i++) {
result += '[ ' + matrix[i].map(val => math.format(val, { precision: 4 })).join(', ') + ' ]\n';
}
return result;
}
// Insert matrix templates
function insertMatrixTemplate(type) {
let template = '';
switch (type) {
case 'identity':
template = 'identity(3)'; // 3x3 identity matrix
break;
case 'zero':
template = 'zeros(3, 3)'; // 3x3 zero matrix
break;
case 'random':
template = 'random(3, 3)'; // 3x3 random matrix
break;
default:
return;
}
const matrixInput = document.getElementById('matrixInput');
matrixInput.value = template;
matrixInput.focus();
}
// Insert matrix operations
function insertMatrixOp(op) {
let template = '';
const placeholder = '[[1,2],[3,4]]';
switch (op) {
case 'det':
template = `det(${placeholder})`;
break;
case 'inv':
template = `inv(${placeholder})`;
break;
case 'transpose':
template = `transpose(${placeholder})`;
break;
default:
return;
}
const matrixInput = document.getElementById('matrixInput');
matrixInput.value = template;
matrixInput.focus();
}
// Switch between tabs (graph/matrix/plot)
function switchTab(tab) {
// Update tab appearance
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.getElementById(`${tab}Tab`).classList.add('active');
// Hide all panels
document.getElementById('graphPanel').style.display = 'none';
document.getElementById('matrixEditor').style.display = 'none';
document.getElementById('plotEditor').style.display = 'none';
// Show selected panel
switch(tab) {
case 'graph':
document.getElementById('graphPanel').style.display = 'block';
if (currentPlot) redrawPlot();
break;
case 'matrix':
document.getElementById('matrixEditor').style.display = 'block';
break;
case 'plot':
document.getElementById('plotEditor').style.display = 'block';
break;
}
}
// Add to input display
function addToInput(value) {
// Special case for RPN mode
if (isRPN) {
if (/^[\d.e]+$/.test(value)) {
// Number input in RPN mode
rpnStack.push(value);
input = "";
inputElement.textContent = "RPN Mode: " + rpnStack.join(" ");
} else if (['+', '-', '*', '/', '^'].includes(value)) {
// Operator in RPN mode, store it for calculation
input = value;
inputElement.textContent = "RPN Mode: " + rpnStack.join(" ") + " " + value;
}
return;
}
// Handle opening bracket for matrices with automatic closing bracket
if (value === '[') {
input += '[]';
inputElement.textContent = input;
// Set cursor position inside brackets
const range = document.createRange();
const sel = window.getSelection();
range.setStart(inputElement.firstChild || inputElement, input.length - 1);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
return;
}
// Normal input handling
input += value;
inputElement.textContent = input;
// Show live preview calculation for simple expressions
if (/^[\d+\-*/.()^]+$/.test(input)) {
try {
const result = math.evaluate(input);
if (!isNaN(result)) {
outputElement.textContent = result;
outputElement.style.opacity = '0.7';
}
} catch {
// Ignore errors in live preview
}
}
}
// Clear all input and output
function clearAll() {
input = "";
inputElement.textContent = "";
outputElement.textContent = "0";
outputElement.style.opacity = '1';
if (isRPN) {
rpnStack = [];
inputElement.textContent = "RPN Mode: ";
}
}
// Backspace (delete last character)
function backspace() {
if (isRPN && rpnStack.length > 0) {
rpnStack.pop();
input = "";
inputElement.textContent = "RPN Mode: " + rpnStack.join(" ");
} else {
input = input.slice(0, -1);
inputElement.textContent = input;
}
}
// Add keyboard support
document.addEventListener('keydown', (e) => {
// Prevent default for calculator keys to avoid page scrolling
if (/[0-9+\-*/().^]/.test(e.key) ||
e.key === 'Enter' ||
e.key === 'Backspace' ||
e.key === 'Escape') {
e.preventDefault();
}
// Handle key presses
if (/[0-9+\-*/().^]/.test(e.key)) {
addToInput(e.key);
} else if (e.key === 'Enter') {
calculate();
} else if (e.key === 'Backspace') {
backspace();
} else if (e.key === 'Escape') {
clearAll();
}
});
// Add cyberpunk typing effect to outputs
function applyTypingEffect(element, text, speed = 30) {
const originalText = text;
element.textContent = '';
let i = 0;
function type() {
if (i < originalText.length) {
element.textContent += originalText.charAt(i);
i++;
setTimeout(type, speed);
}
}
type();
}
// Add visual feedback when a button is clicked
document.querySelectorAll('.btn').forEach(button => {
button.addEventListener('click', function() {
this.style.transform = 'scale(0.95)';
setTimeout(() => {
this.style.transform = '';
}, 100);
});
});
// Add glowing effect on calculator startup
function startupAnimation() {
const calculator = document.querySelector('.calculator');
const graph = document.querySelector('.graph-container');
calculator.style.opacity = '0';
graph.style.opacity = '0';
setTimeout(() => {
calculator.style.transition = 'all 1s ease';
graph.style.transition = 'all 1s ease';
calculator.style.opacity = '1';
graph.style.opacity = '1';
}, 300);
setTimeout(() => {
applyTypingEffect(outputElement, '0', 50);
}, 800);
}
// Initialize everything
window.addEventListener('load', () => {
initialize();
startupAnimation();
});
Comments
Post a Comment