|
|
class CinematicNumbersApp { |
|
|
constructor() { |
|
|
this.currentNumber = 1; |
|
|
this.currentAnimation = 'zoom'; |
|
|
this.isLooping = true; |
|
|
this.isPlaying = true; |
|
|
this.animationTimeout = null; |
|
|
|
|
|
this.initializeElements(); |
|
|
this.setupEventListeners(); |
|
|
this.startAnimation(); |
|
|
} |
|
|
|
|
|
initializeElements() { |
|
|
this.numberDisplay = document.getElementById('numberDisplay'); |
|
|
this.currentNumberSpan = document.getElementById('currentNumber'); |
|
|
this.animationTypeSelect = document.getElementById('animationType'); |
|
|
this.loopCheckbox = document.getElementById('loopAnimation'); |
|
|
this.playPauseButton = document.getElementById('playPause'); |
|
|
this.prevButton = document.getElementById('prevNumber'); |
|
|
this.nextButton = document.getElementById('nextNumber'); |
|
|
this.particlesContainer = document.getElementById('particles'); |
|
|
} |
|
|
|
|
|
setupEventListeners() { |
|
|
this.animationTypeSelect.addEventListener('change', (e) => { |
|
|
this.currentAnimation = e.target.value; |
|
|
this.applyAnimation(); |
|
|
}); |
|
|
|
|
|
this.loopCheckbox.addEventListener('change', (e) => { |
|
|
this.isLooping = e.target.checked; |
|
|
if (this.isLooping && this.isPlaying) { |
|
|
this.startAnimation(); |
|
|
} |
|
|
}); |
|
|
|
|
|
this.playPauseButton.addEventListener('click', () => { |
|
|
this.isPlaying = !this.isPlaying; |
|
|
if (this.isPlaying) { |
|
|
this.startAnimation(); |
|
|
} else { |
|
|
this.stopAnimation(); |
|
|
} |
|
|
}); |
|
|
|
|
|
this.prevButton.addEventListener('click', () => { |
|
|
this.changeNumber(-1); |
|
|
}); |
|
|
|
|
|
this.nextButton.addEventListener('click', () => { |
|
|
this.changeNumber(1); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('keydown', (e) => { |
|
|
if (e.key === 'ArrowLeft') this.changeNumber(-1); |
|
|
if (e.key === 'ArrowRight') this.changeNumber(1); |
|
|
if (e.key === ' ') { |
|
|
this.isPlaying = !this.isPlaying; |
|
|
if (this.isPlaying) this.startAnimation(); |
|
|
else this.stopAnimation(); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
changeNumber(direction) { |
|
|
this.currentNumber += direction; |
|
|
|
|
|
if (this.currentNumber < 1) this.currentNumber = 10; |
|
|
if (this.currentNumber > 10) this.currentNumber = 1; |
|
|
|
|
|
this.updateDisplay(); |
|
|
this.applyAnimation(); |
|
|
} |
|
|
|
|
|
updateDisplay() { |
|
|
this.numberDisplay.textContent = this.currentNumber; |
|
|
this.numberDisplay.setAttribute('data-number', this.currentNumber); |
|
|
this.currentNumberSpan.textContent = this.currentNumber; |
|
|
} |
|
|
|
|
|
applyAnimation() { |
|
|
|
|
|
this.numberDisplay.className = 'cinematic-number text-9xl md:text-[20rem] font-black tracking-tighter'; |
|
|
|
|
|
|
|
|
switch(this.currentAnimation) { |
|
|
case 'zoom': |
|
|
this.numberDisplay.classList.add('zoom-animation'); |
|
|
break; |
|
|
case 'bounce': |
|
|
this.numberDisplay.classList.add('bounce-animation'); |
|
|
break; |
|
|
case 'smoke': |
|
|
this.numberDisplay.classList.add('smoke-animation'); |
|
|
this.createParticles(); |
|
|
break; |
|
|
case 'glitch': |
|
|
this.numberDisplay.classList.add('glitch-animation'); |
|
|
break; |
|
|
case 'pulse': |
|
|
this.numberDisplay.classList.add('pulse-animation'); |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
createParticles() { |
|
|
|
|
|
this.particlesContainer.innerHTML = ''; |
|
|
|
|
|
|
|
|
for (let i = 0; i < 30; i++) { |
|
|
const particle = document.createElement('div'); |
|
|
particle.classList.add('particle'); |
|
|
|
|
|
const angle = Math.random() * Math.PI * 2; |
|
|
const distance = 100 + Math.random() * 200; |
|
|
const tx = Math.cos(angle) * distance; |
|
|
const ty = Math.sin(angle) * distance; |
|
|
|
|
|
particle.style.setProperty('--tx', `${tx}px`); |
|
|
particle.style.setProperty('--ty', `${ty}px`); |
|
|
particle.style.left = '50%'; |
|
|
particle.style.top = '50%'; |
|
|
particle.style.animationDelay = `${Math.random() * 0.5}s`; |
|
|
|
|
|
this.particlesContainer.appendChild(particle); |
|
|
} |
|
|
} |
|
|
|
|
|
startAnimation() { |
|
|
this.stopAnimation(); |
|
|
|
|
|
if (this.isLooping && this.isPlaying) { |
|
|
this.animationTimeout = setTimeout(() => { |
|
|
this.changeNumber(1); |
|
|
this.startAnimation(); |
|
|
}, 3000); |
|
|
} |
|
|
} |
|
|
|
|
|
stopAnimation() { |
|
|
if (this.animationTimeout) { |
|
|
clearTimeout(this.animationTimeout); |
|
|
this.animationTimeout = null; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
new CinematicNumbersApp(); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
if (typeof feather !== 'undefined') { |
|
|
feather.replace(); |
|
|
} |
|
|
}); |