export default class Counter { constructor(element) { this.element = element this.target = parseFloat(element.dataset.target) this.decimal = element.dataset.decimal === 'true' this.duration = 2000 this.startTime = null this.init() } init() { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { this.animate() observer.unobserve(this.element) } }) }, { threshold: 0.5 }) observer.observe(this.element) } animate() { const startValue = 0 const startTime = performance.now() const updateCounter = (currentTime) => { const elapsedTime = currentTime - startTime const progress = Math.min(elapsedTime / this.duration, 1) // Easing function for smooth animation const easeOutQuart = 1 - Math.pow(1 - progress, 4) let currentValue = startValue + (this.target - startValue) * easeOutQuart if (this.decimal && this.target < 10) { currentValue = currentValue.toFixed(1) } else { currentValue = Math.floor(currentValue) } this.element.textContent = currentValue if (progress < 1) { requestAnimationFrame(updateCounter) } else { this.element.textContent = this.decimal && this.target < 10 ? this.target.toFixed(1) : this.target } } requestAnimationFrame(updateCounter) } } // Initialize all counters document.addEventListener('DOMContentLoaded', () => { const counters = document.querySelectorAll('.counter') counters.forEach(counter => new Counter(counter)) })