Imade defille
Sat Jan 11 2025 18:01:13 GMT+0000 (Coordinated Universal Time)
Saved by @Eden
<div class="pedal-path-container"> <div class="pedal-path"> <img src="https://d1yei2z3i6k35z.cloudfront.net/1970629/677599f123309_dsfgvdsv.png"> <img src="https://d1yei2z3i6k35z.cloudfront.net/1970629/677599f123309_dsfgvdsv.png"> <img src="https://d1yei2z3i6k35z.cloudfront.net/1970629/677599f123309_dsfgvdsv.png"> <img src="https://d1yei2z3i6k35z.cloudfront.net/1970629/677599f123309_dsfgvdsv.png"> <img src="https://d1yei2z3i6k35z.cloudfront.net/1970629/677599f123309_dsfgvdsv.png"> </div> <div class="road-overlay"></div> </div> <style> .pedal-path-container { width: 100%; height: 35px; overflow: hidden; position: relative; } .pedal-path { height: 100%; position: absolute; white-space: nowrap; will-change: transform; } .pedal-path img { height: 100%; width: auto; } .road-overlay { position: absolute; inset: 0; background: linear-gradient( to right, #140D3F 0%, transparent 10%, transparent 90%, #140D3F 100% ); pointer-events: none; } </style> <script> class PedalPathAnimation { constructor() { this.container = document.querySelector('.pedal-path-container'); this.path = document.querySelector('.pedal-path'); this.imgSrc = 'https://d1yei2z3i6k35z.cloudfront.net/1970629/677599f123309_dsfgvdsv.png'; this.wheelWidth = 0; this.animationId = null; this.position = 0; this.lastTime = null; this.speed = 0.3; // Bind methods this.init = this.init.bind(this); this.startRide = this.startRide.bind(this); this.stopRide = this.stopRide.bind(this); this.handleVisibilityChange = this.handleVisibilityChange.bind(this); this.handleResize = this.handleResize.bind(this); // Initialize if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', this.init); } else { this.init(); } } async init() { try { await this.setupPedalPath(); this.addEventListeners(); } catch (error) { console.error('Initialization error:', error); } } async loadWheelImage() { return new Promise((resolve, reject) => { const wheel = new Image(); wheel.onload = () => resolve(wheel); wheel.onerror = (error) => reject(error); wheel.src = this.imgSrc; }); } async setupPedalPath() { try { const wheel = await this.loadWheelImage(); this.wheelWidth = wheel.width * (this.container.offsetHeight / wheel.height); const roadWidth = this.container.offsetWidth; const wheelCount = Math.ceil(roadWidth / this.wheelWidth) + 1; // Clear existing content this.path.innerHTML = ''; // Add new images const fragment = document.createDocumentFragment(); for (let i = 0; i < wheelCount; i++) { fragment.appendChild(wheel.cloneNode()); } this.path.appendChild(fragment); this.startRide(); } catch (error) { console.error('Setup error:', error); } } startRide() { const animate = (timestamp) => { if (this.lastTime === null) { this.lastTime = timestamp; } const elapsed = timestamp - this.lastTime; this.lastTime = timestamp; this.position = (this.position - (this.speed * elapsed)) % this.wheelWidth; this.path.style.transform = `translateX(${this.position}px)`; this.animationId = requestAnimationFrame(animate); }; this.animationId = requestAnimationFrame(animate); } stopRide() { if (this.animationId) { cancelAnimationFrame(this.animationId); this.animationId = null; this.lastTime = null; } } handleVisibilityChange() { if (document.hidden) { this.stopRide(); } else { this.startRide(); } } handleResize() { this.stopRide(); this.setupPedalPath(); } addEventListeners() { document.addEventListener('visibilitychange', this.handleVisibilityChange); const resizeObserver = new ResizeObserver(this.handleResize); resizeObserver.observe(this.container); } cleanup() { this.stopRide(); document.removeEventListener('visibilitychange', this.handleVisibilityChange); // ResizeObserver will be automatically disconnected when the element is removed } } // Initialize the animation const pedalAnimation = new PedalPathAnimation(); </script>
Comments