kalkulator/static/assets/js/calculator-logic.js

208 lines
6.6 KiB
JavaScript
Raw Normal View History

// 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') {
toggleSettings();
} 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 {
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.
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
}
// 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.
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
});
}