62 lines
1.5 KiB
JavaScript
Executable File
62 lines
1.5 KiB
JavaScript
Executable File
import { Controller } from "@hotwired/stimulus"
|
|
|
|
export default class extends Controller {
|
|
static values = {
|
|
target: Number,
|
|
decimal: Boolean,
|
|
duration: { type: Number, default: 2000 }
|
|
}
|
|
|
|
connect() {
|
|
this.observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
this.animate()
|
|
this.observer.unobserve(this.element)
|
|
}
|
|
})
|
|
}, { threshold: 0.5 })
|
|
|
|
this.observer.observe(this.element)
|
|
}
|
|
|
|
disconnect() {
|
|
if (this.observer) {
|
|
this.observer.disconnect()
|
|
}
|
|
}
|
|
|
|
animate() {
|
|
const startValue = 0
|
|
const startTime = performance.now()
|
|
|
|
const updateCounter = (currentTime) => {
|
|
const elapsedTime = currentTime - startTime
|
|
const progress = Math.min(elapsedTime / this.durationValue, 1)
|
|
|
|
// Easing function for smooth animation
|
|
const easeOutQuart = 1 - Math.pow(1 - progress, 4)
|
|
|
|
let currentValue = startValue + (this.targetValue - startValue) * easeOutQuart
|
|
|
|
if (this.decimalValue && this.targetValue < 10) {
|
|
currentValue = currentValue.toFixed(1)
|
|
} else {
|
|
currentValue = Math.floor(currentValue)
|
|
}
|
|
|
|
this.element.textContent = currentValue
|
|
|
|
if (progress < 1) {
|
|
requestAnimationFrame(updateCounter)
|
|
} else {
|
|
this.element.textContent = this.decimalValue && this.targetValue < 10
|
|
? this.targetValue.toFixed(1)
|
|
: this.targetValue
|
|
}
|
|
}
|
|
|
|
requestAnimationFrame(updateCounter)
|
|
}
|
|
}
|