2024-09-13 19:04:35 +02:00
|
|
|
function applyScrambleEffect() {
|
|
|
|
const glitchTextOnceElements = document.querySelectorAll('.glitch-text');
|
|
|
|
const glitchTextRepeatElements = document.querySelectorAll('.glitch-text-interval');
|
2024-09-16 18:13:20 +02:00
|
|
|
const glitchTextHoverElements = document.querySelectorAll('.glitch-text-hover');
|
2024-09-13 19:04:35 +02:00
|
|
|
|
2024-09-16 18:13:20 +02:00
|
|
|
const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
|
|
|
2024-09-13 19:04:35 +02:00
|
|
|
function animateScramble(element, text, duration = 1000) {
|
2024-09-16 18:13:20 +02:00
|
|
|
const chars = [];
|
|
|
|
element.innerHTML = '';
|
|
|
|
const preScrambleWidth = element.offsetWidth;
|
|
|
|
element.style.width = `${preScrambleWidth}px`;
|
|
|
|
|
|
|
|
for (let t = 0; t < text.length; t++) {
|
|
|
|
const span = document.createElement('span');
|
|
|
|
span.innerHTML = text[t] === ' ' ? ' ' : text[t];
|
|
|
|
chars[t] = span;
|
|
|
|
span.style.display = 'inline-block';
|
|
|
|
element.appendChild(span);
|
2024-09-13 19:04:35 +02:00
|
|
|
}
|
2024-09-16 18:13:20 +02:00
|
|
|
|
|
|
|
const rand = Math.random;
|
|
|
|
const SECONDS = 1000;
|
|
|
|
const FPS = 30;
|
|
|
|
const animationLength = duration;
|
|
|
|
|
|
|
|
function animate3(k) {
|
|
|
|
const kk = k * text.length;
|
|
|
|
for (let i = 0; i < text.length; i++) {
|
|
|
|
if (kk < i) {
|
|
|
|
chars[i].innerHTML = charset[Math.floor(rand() * charset.length)];
|
|
|
|
} else {
|
|
|
|
chars[i].innerHTML = text[i] === ' ' ? ' ' : text[i];
|
|
|
|
}
|
|
|
|
}
|
2024-09-13 19:04:35 +02:00
|
|
|
}
|
2024-09-16 18:13:20 +02:00
|
|
|
|
|
|
|
let start = Date.now();
|
|
|
|
function animate() {
|
|
|
|
const current = Date.now();
|
|
|
|
const time = current - start;
|
|
|
|
const k = time / animationLength;
|
|
|
|
|
|
|
|
if (k < 1) {
|
|
|
|
setTimeout(animate, SECONDS / FPS);
|
|
|
|
animate3(k);
|
|
|
|
} else {
|
|
|
|
for (let i = 0; i < text.length; i++) {
|
|
|
|
chars[i].innerHTML = text[i] === ' ' ? ' ' : text[i];
|
|
|
|
}
|
|
|
|
element.style.width = 'auto';
|
|
|
|
element.isAnimating = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
animate();
|
2024-09-13 19:04:35 +02:00
|
|
|
}
|
2024-09-16 18:13:20 +02:00
|
|
|
|
|
|
|
// Use IntersectionObserver for once-only animation
|
2024-09-13 19:04:35 +02:00
|
|
|
const observer = new IntersectionObserver((entries, observer) => {
|
2024-09-16 18:13:20 +02:00
|
|
|
entries.forEach(entry => {
|
|
|
|
if (entry.isIntersecting) {
|
|
|
|
const element = entry.target;
|
|
|
|
const text = element.innerText;
|
|
|
|
animateScramble(element, text);
|
|
|
|
observer.unobserve(element);
|
|
|
|
}
|
|
|
|
});
|
2024-09-13 19:04:35 +02:00
|
|
|
}, {
|
2024-09-16 18:13:20 +02:00
|
|
|
threshold: 0.1
|
2024-09-13 19:04:35 +02:00
|
|
|
});
|
2024-09-16 18:13:20 +02:00
|
|
|
|
2024-09-13 19:04:35 +02:00
|
|
|
glitchTextOnceElements.forEach((element) => {
|
2024-09-16 18:13:20 +02:00
|
|
|
observer.observe(element);
|
2024-09-13 19:04:35 +02:00
|
|
|
});
|
2024-09-16 18:13:20 +02:00
|
|
|
|
2024-09-13 19:04:35 +02:00
|
|
|
glitchTextRepeatElements.forEach((element) => {
|
2024-09-16 18:13:20 +02:00
|
|
|
const text = element.innerText;
|
|
|
|
|
|
|
|
animateScramble(element, text);
|
|
|
|
|
|
|
|
const intervalId = setInterval(() => {
|
|
|
|
if (!element.isAnimating) {
|
|
|
|
animateScramble(element, text);
|
|
|
|
}
|
|
|
|
}, 5000);
|
2024-09-13 19:04:35 +02:00
|
|
|
});
|
2024-09-16 18:13:20 +02:00
|
|
|
|
|
|
|
// Hover functionality for `.glitch-text-hover` elements
|
|
|
|
glitchTextHoverElements.forEach((element) => {
|
|
|
|
const text = element.innerText;
|
|
|
|
|
|
|
|
element.addEventListener('mouseenter', () => {
|
|
|
|
// Only start the animation if it isn't already in progress
|
|
|
|
if (!element.isAnimating) {
|
|
|
|
element.isAnimating = true;
|
|
|
|
animateScramble(element, text, 800);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// No need for 'mouseleave' as the animation will complete even if the mouse leaves
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', applyScrambleEffect);
|