Spaces:
Running
Running
| // Initialize GSAP and ScrollTrigger | |
| gsap.registerPlugin(ScrollTrigger); | |
| // Loading Animation | |
| window.addEventListener('load', function() { | |
| setTimeout(function() { | |
| document.getElementById('loading').classList.add('hidden'); | |
| }, 1500); | |
| }); | |
| // Parallax Effect | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const parallaxLayers = document.querySelectorAll('.parallax-layer'); | |
| window.addEventListener('scroll', function() { | |
| const scrollPosition = window.pageYOffset; | |
| parallaxLayers.forEach(layer => { | |
| const depth = layer.getAttribute('data-depth') || 0; | |
| const translateY = -(scrollPosition * depth); | |
| layer.style.transform = `translateY(${translateY}px)`; | |
| }); | |
| }); | |
| }); | |
| // Driver Slider | |
| const driverTrack = document.querySelector('.driver-track'); | |
| const driverSlides = document.querySelectorAll('.driver-slide'); | |
| const prevBtn = document.querySelector('.driver-prev'); | |
| const nextBtn = document.querySelector('.driver-next'); | |
| let currentIndex = 0; | |
| const slideCount = driverSlides.length; | |
| function updateSlider() { | |
| const slideWidth = driverSlides[0].offsetWidth; | |
| driverTrack.style.transform = `translateX(-${currentIndex * slideWidth}px)`; | |
| } | |
| nextBtn.addEventListener('click', () => { | |
| currentIndex = (currentIndex + 1) % slideCount; | |
| updateSlider(); | |
| }); | |
| prevBtn.addEventListener('click', () => { | |
| currentIndex = (currentIndex - 1 + slideCount) % slideCount; | |
| updateSlider(); | |
| }); | |
| // Race Timeline Animations | |
| gsap.utils.toArray('.race-item').forEach((item, i) => { | |
| gsap.fromTo(item, | |
| { opacity: 0, y: 20 }, | |
| { | |
| opacity: 1, | |
| y: 0, | |
| scrollTrigger: { | |
| trigger: item, | |
| start: "top 85%", | |
| toggleActions: "play none none reverse" | |
| }, | |
| duration: 0.6, | |
| delay: i * 0.1 | |
| } | |
| ); | |
| }); | |
| // Standings Table Animation | |
| gsap.from('.standings-table tbody tr', { | |
| opacity: 0, | |
| y: 15, | |
| stagger: 0.1, | |
| duration: 0.5, | |
| scrollTrigger: { | |
| trigger: '.standings-table', | |
| start: "top 80%" | |
| } | |
| }); | |
| // Count-up Animation | |
| const countUpElements = document.querySelectorAll('[data-countup]'); | |
| const observerOptions = { | |
| root: null, | |
| rootMargin: '0px', | |
| threshold: 0.5 | |
| }; | |
| const observer = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| const element = entry.target; | |
| const endValue = parseInt(element.getAttribute('data-countup')); | |
| let startValue = 0; | |
| const duration = 2000; // ms | |
| const increment = endValue / (duration / 16); // 16ms per frame | |
| const counter = setInterval(() => { | |
| startValue += increment; | |
| if (startValue >= endValue) { | |
| startValue = endValue; | |
| clearInterval(counter); | |
| } | |
| element.textContent = Math.floor(startValue); | |
| }, 16); | |
| observer.unobserve(element); | |
| } | |
| }); | |
| }, observerOptions); | |
| countUpElements.forEach(el => { | |
| observer.observe(el); | |
| }); | |
| // Sound Toggle | |
| const soundToggle = document.getElementById('soundToggle'); | |
| const soundIcon = soundToggle.querySelector('i'); | |
| soundToggle.addEventListener('click', () => { | |
| // In a real implementation, this would toggle actual sound | |
| if (soundIcon.getAttribute('data-feather') === 'volume-2') { | |
| soundIcon.setAttribute('data-feather', 'volume-x'); | |
| } else { | |
| soundIcon.setAttribute('data-feather', 'volume-2'); | |
| } | |
| feather.replace(); | |
| }); |