2024-10-17 22:48:50 +02:00
|
|
|
|
// This file is responsible for all calculator animations and logic.
|
|
|
|
|
|
2024-10-16 22:46:58 +02:00
|
|
|
|
const buttons = document.querySelectorAll('.button');
|
|
|
|
|
const displayText = document.querySelector('.display-text');
|
|
|
|
|
let currentInput = '';
|
|
|
|
|
let characterSpans = []; // Array to track all spans for proper positioning
|
|
|
|
|
let isResultDisplayed = false; // Track if the result is displayed
|
|
|
|
|
let resultSpan; // For showing the result
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// Add on-click event listeners to the buttons.
|
2024-10-16 22:46:58 +02:00
|
|
|
|
buttons.forEach(button => {
|
|
|
|
|
button.addEventListener('click', () => {
|
|
|
|
|
const value = button.textContent;
|
|
|
|
|
|
|
|
|
|
if (value === 'AC') {
|
|
|
|
|
resetCalculator();
|
2024-10-17 09:05:34 +02:00
|
|
|
|
} else if (value === 'H') {
|
|
|
|
|
toggleHistory();
|
2024-10-18 08:31:29 +02:00
|
|
|
|
} else if (value === 'settings') {
|
2024-10-17 16:38:32 +02:00
|
|
|
|
toggleSettings();
|
2024-11-07 16:42:19 +01:00
|
|
|
|
} else if (value === 'backspace') {
|
|
|
|
|
popCharacter();
|
2024-10-16 22:46:58 +02:00
|
|
|
|
} else if (value === '=') {
|
|
|
|
|
calculateResult();
|
|
|
|
|
} else {
|
|
|
|
|
if (isResultDisplayed) {
|
|
|
|
|
resetCalculator(); // Reset after "=" is pressed
|
|
|
|
|
}
|
|
|
|
|
if (currentInput === 'Error') currentInput = ''; // Clear on error
|
|
|
|
|
currentInput += value;
|
|
|
|
|
appendCharacter(value); // Append with animation
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// This function is used to append a character to the calculator display. It's called when user clicks a button.
|
2024-10-16 22:46:58 +02:00
|
|
|
|
function appendCharacter(char) {
|
|
|
|
|
// Create new span element for the character
|
|
|
|
|
const newChar = document.createElement('span');
|
|
|
|
|
newChar.textContent = char;
|
|
|
|
|
displayText.appendChild(newChar);
|
|
|
|
|
characterSpans.push(newChar); // Add the new span to the array
|
|
|
|
|
|
|
|
|
|
// Move all characters smoothly
|
|
|
|
|
updateCharacterPositions();
|
|
|
|
|
|
|
|
|
|
// Animate the new character in from the right
|
|
|
|
|
anime({
|
|
|
|
|
targets: newChar,
|
|
|
|
|
opacity: [0, 1],
|
|
|
|
|
translateY: [0, -25], // Animating into place
|
|
|
|
|
scale: [0, 1],
|
|
|
|
|
duration: 500,
|
|
|
|
|
easing: 'easeOutExpo'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// This function moves already input characters to left to make space for a new one.
|
2024-10-16 22:46:58 +02:00
|
|
|
|
function updateCharacterPositions() {
|
|
|
|
|
const totalWidth = displayText.offsetWidth; // Width of the display
|
|
|
|
|
let currentOffset = totalWidth; // Start from the rightmost edge
|
|
|
|
|
|
|
|
|
|
// Loop through characters in reverse (so newest appears at the right)
|
|
|
|
|
for (let i = characterSpans.length - 1; i >= 0; i--) {
|
|
|
|
|
const span = characterSpans[i];
|
|
|
|
|
const spanWidth = span.offsetWidth; // Get the width of each character
|
2024-10-17 09:05:34 +02:00
|
|
|
|
currentOffset -= spanWidth; // Move left by the width of the character + some margin
|
2024-10-16 22:46:58 +02:00
|
|
|
|
|
|
|
|
|
anime({
|
|
|
|
|
targets: span,
|
|
|
|
|
right: (totalWidth - currentOffset - spanWidth) + 'px', // Keep them aligned right
|
|
|
|
|
duration: 300,
|
|
|
|
|
easing: 'easeOutQuint'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// This function calculates the result based on characters input.
|
2024-10-16 22:46:58 +02:00
|
|
|
|
function calculateResult() {
|
|
|
|
|
const equation = characterSpans.map(span => span.textContent).join('');
|
|
|
|
|
let result;
|
|
|
|
|
try {
|
2024-11-07 16:42:19 +01:00
|
|
|
|
result = eval(equation.replaceAll('÷', '/').replaceAll('×', '*').replaceAll('−', '-')).toString();
|
2024-10-16 22:46:58 +02:00
|
|
|
|
} catch (error) {
|
|
|
|
|
result = 'Error';
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// We should add 'result' to the history here.
|
|
|
|
|
|
2024-10-16 22:46:58 +02:00
|
|
|
|
characterSpans.forEach(span => {
|
|
|
|
|
span.style.fontSize = '1.5rem';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const totalWidth = displayText.offsetWidth; // Width of the display
|
|
|
|
|
let currentOffset = totalWidth; // Start from the rightmost edge
|
|
|
|
|
// Animate the equation upwards
|
|
|
|
|
// Loop through characters in reverse (so newest appears at the right)
|
|
|
|
|
for (let i = characterSpans.length - 1; i >= 0; i--) {
|
|
|
|
|
const span = characterSpans[i];
|
|
|
|
|
const spanWidth = span.offsetWidth; // Get the width of each character
|
2024-10-17 09:05:34 +02:00
|
|
|
|
currentOffset -= spanWidth; // Move left by the width of the character + some margin
|
2024-10-16 22:46:58 +02:00
|
|
|
|
|
|
|
|
|
anime({
|
|
|
|
|
targets: span,
|
|
|
|
|
translateY: -45,
|
|
|
|
|
opacity: [1, 0.4],
|
|
|
|
|
right: (totalWidth - currentOffset - spanWidth) + 'px', // Keep them aligned right
|
|
|
|
|
duration: 800,
|
|
|
|
|
easing: 'easeOutExpo'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resultSpan = document.createElement('span'); // Create a new span for the result
|
|
|
|
|
resultSpan.textContent = `= ${result}`;
|
|
|
|
|
displayText.appendChild(resultSpan);
|
|
|
|
|
|
|
|
|
|
// Animate the result to appear from below
|
|
|
|
|
anime({
|
|
|
|
|
targets: resultSpan,
|
|
|
|
|
opacity: [0, 1],
|
|
|
|
|
translateY: [50, -10], // Animating upwards
|
|
|
|
|
translateX: -5,
|
|
|
|
|
scale: [0, 1],
|
|
|
|
|
duration: 500,
|
|
|
|
|
easing: 'easeOutExpo'
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Set a flag to reset on the next key press
|
|
|
|
|
isResultDisplayed = true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// This function toggles the history menu.
|
2024-10-17 09:05:34 +02:00
|
|
|
|
function toggleHistory() {
|
|
|
|
|
$('body').toggleClass('history-open');
|
|
|
|
|
|
|
|
|
|
if ($('body').hasClass('history-open')) { // If the history was just opened
|
|
|
|
|
// Animate it's elements
|
|
|
|
|
anime({
|
|
|
|
|
targets: '.history-container span',
|
|
|
|
|
translateY: [-100, 0],
|
|
|
|
|
opacity: [0, 1],
|
|
|
|
|
duration: 400,
|
|
|
|
|
delay: anime.stagger(100, { start: 200, direction: 'reverse' }),
|
|
|
|
|
easing: 'easeOutQuart'
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// This function toggles the settings menu.
|
2024-10-17 16:38:32 +02:00
|
|
|
|
function toggleSettings() {
|
|
|
|
|
$('body').toggleClass('settings-open');
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-17 09:05:34 +02:00
|
|
|
|
$('#history').on('click', toggleHistory);
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// Resets everything, the result and display.
|
2024-10-16 22:46:58 +02:00
|
|
|
|
function resetCalculator() {
|
|
|
|
|
currentInput = '';
|
|
|
|
|
characterSpans = [];
|
|
|
|
|
displayText.innerHTML = ''; // Clear the display
|
|
|
|
|
isResultDisplayed = false; // Reset the result display flag
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-07 16:42:19 +01:00
|
|
|
|
// popLock (funny name) is true when a cbaracter pop animation is being progress.
|
|
|
|
|
let popLock = false;
|
2024-11-24 12:06:49 +01:00
|
|
|
|
// This function pops the last character input to the calculator.
|
2024-11-07 16:42:19 +01:00
|
|
|
|
function popCharacter() {
|
|
|
|
|
if (popLock) return;
|
|
|
|
|
popLock = true;
|
|
|
|
|
|
|
|
|
|
if (isResultDisplayed) {
|
|
|
|
|
resetCalculator();
|
|
|
|
|
popLock = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentInput = currentInput.slice(0, -1);
|
|
|
|
|
characterSpans.pop();
|
|
|
|
|
if (displayText.innerHTML.length === 0) {
|
|
|
|
|
isResultDisplayed = false;
|
|
|
|
|
popLock = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Animate character disappearing
|
|
|
|
|
anime({
|
|
|
|
|
targets: displayText.lastChild,
|
|
|
|
|
opacity: [1, 0],
|
|
|
|
|
duration: 150,
|
|
|
|
|
easing: 'easeInExpo',
|
|
|
|
|
complete: () => {
|
|
|
|
|
displayText.removeChild(displayText.lastChild);
|
|
|
|
|
updateCharacterPositions();
|
|
|
|
|
popLock = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 12:06:49 +01:00
|
|
|
|
|
|
|
|
|
// This sets the calculator display value to some string. I'm pretty sure it's not used, but I'll leave it here just in case.
|
2024-10-16 22:46:58 +02:00
|
|
|
|
function updateDisplay(value) {
|
|
|
|
|
// Clear existing spans and reset positions
|
|
|
|
|
displayText.innerHTML = '';
|
|
|
|
|
characterSpans = [];
|
|
|
|
|
[...value].forEach(char => {
|
|
|
|
|
appendCharacter(char); // Append each character
|
|
|
|
|
});
|
|
|
|
|
}
|