1document.addEventListener('DOMContentLoaded', function() { 2 // Initialisation de Lenis 3 const lenis = new Lenis({ 4 duration: 1.2, 5 easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), 6 direction: 'vertical', 7 gestureDirection: 'vertical', 8 smooth: true, 9 smoothTouch: false, 10 syncScroll: true 11 }); 12 13 lenis.prevent = (node) => { 14 const computedStyle = window.getComputedStyle(node); 15 const overflow = computedStyle.overflow; 16 const overflowY = computedStyle.overflowY; 17 const overflowX = computedStyle.overflowX; 18 19 if ( 20 overflow === 'scroll' || overflow === 'auto' || 21 overflowY === 'scroll' || overflowY === 'auto' || 22 overflowX === 'scroll' || overflowX === 'auto' 23 ) { 24 node.setAttribute('data-lenis-prevent', 'true'); 25 } 26 }; 27 28 // Fonction pour appliquer les effets parallax, fade, slide-in, scale et déplacement 29 function applyScrollEffects() { 30 const windowHeight = window.innerHeight; 31 const midPoint = windowHeight / 2; 32 33 document.querySelectorAll('.parallax-effect').forEach((element) => { 34 const minWidth = parseInt(element.getAttribute('data-parallax-min-width')) || 0; 35 if (window.innerWidth < minWidth) return; 36 37 const parallaxSpeed = parseFloat(element.getAttribute('data-parallax-speed')) || 0.5; 38 const parallaxAnchor = element.getAttribute('data-parallax-anchor'); 39 const rect = element.getBoundingClientRect(); 40 const offsetTop = rect.top; 41 42 if (!element.hasAttribute('data-parallax-initialized') && (parallaxAnchor === 'top' || parallaxAnchor === 'bottom')) { 43 if (offsetTop < windowHeight && offsetTop > -rect.height) { // Vérifie si l'élément est visible 44 const transformValue = (windowHeight - offsetTop) * parallaxSpeed; 45 element.style.position = 'relative'; 46 element.style[parallaxAnchor] = `${-transformValue}px`; 47 element.setAttribute('data-parallax-initialized', 'true'); 48 } 49 } 50 51 if (offsetTop < windowHeight && offsetTop > -rect.height) { 52 const transformValue = (windowHeight - offsetTop) * parallaxSpeed; 53 element.style.transform = `translateY(${transformValue}px)`; 54 } 55 }); 56 57 document.querySelectorAll('.fade-effect').forEach((element) => { 58 const rect = element.getBoundingClientRect(); 59 const offsetTop = rect.top; 60 const startFadePoint = windowHeight; 61 const endFadePoint = midPoint; 62 63 if (offsetTop < startFadePoint && offsetTop > endFadePoint) { 64 const fadeValue = 1 - (offsetTop - endFadePoint) / (startFadePoint - endFadePoint); 65 element.style.opacity = fadeValue; 66 } else if (offsetTop <= endFadePoint) { 67 element.style.opacity = 1; 68 } else { 69 element.style.opacity = 0; 70 } 71 }); 72 73 document.querySelectorAll('.slide-effect').forEach((element) => { 74 const rect = element.getBoundingClientRect(); 75 const offsetTop = rect.top; 76 const slideDirection = element.getAttribute('data-slide-direction') || 'left'; 77 const slideSpeed = parseFloat(element.getAttribute('data-slide-speed')) || 100; 78 const windowHeight = window.innerHeight; 79 80 // Valeur par défaut si data-slide-final n'est pas défini 81 const defaultFinalSetting = 'middle'; 82 const dataSlideFinalAttr = element.getAttribute('data-slide-final') || defaultFinalSetting; 83 let finalSetting = defaultFinalSetting; 84 85 // Traitement multi-règles pour data-slide-final 86 if (dataSlideFinalAttr.indexOf(':') > -1) { 87 // Format attendu : "minWidth:position,minWidth:position,..." 88 const finalRules = dataSlideFinalAttr.split(',').map(rule => { 89 const parts = rule.split(':'); 90 return { minWidth: parseInt(parts[0].trim(), 10), position: parts[1].trim() }; 91 }); 92 // Trie des règles par largeur minimale décroissante 93 finalRules.sort((a, b) => b.minWidth - a.minWidth); 94 for (let rule of finalRules) { 95 if (window.innerWidth >= rule.minWidth) { 96 finalSetting = rule.position; 97 break; 98 } 99 } 100 } else { 101 finalSetting = dataSlideFinalAttr; 102 } 103 104 // Définition du point final pour l'effet slide selon la position choisie 105 let endSlidePoint; 106 switch(finalSetting) { 107 case 'top': 108 endSlidePoint = 0; 109 break; 110 case 'quarter': 111 endSlidePoint = windowHeight / 4; 112 break; 113 case 'three-quarters': 114 endSlidePoint = windowHeight * 0.75; 115 break; 116 case 'middle': 117 default: 118 endSlidePoint = windowHeight / 2; 119 break; 120 } 121 122 const startSlidePoint = windowHeight; 123 let translateValue = ''; 124 125 if (offsetTop < startSlidePoint && offsetTop > endSlidePoint) { 126 const slideFactor = 1 - (offsetTop - endSlidePoint) / (startSlidePoint - endSlidePoint); 127 switch (slideDirection) { 128 case 'top': 129 translateValue = `translateY(${(1 - slideFactor) * slideSpeed}px)`; 130 break; 131 case 'bottom': 132 translateValue = `translateY(${(slideFactor - 1) * slideSpeed}px)`; 133 break; 134 case 'left': 135 translateValue = `translateX(${(1 - slideFactor) * slideSpeed}px)`; 136 break; 137 case 'right': 138 translateValue = `translateX(${(slideFactor - 1) * slideSpeed}px)`; 139 break; 140 } 141 element.style.transform = translateValue; 142 } else if (offsetTop <= endSlidePoint) { 143 element.style.transform = 'translate(0, 0)'; 144 } else { 145 element.style.transform = translateValue; 146 } 147 }); 148 149 document.querySelectorAll('.scale-effect').forEach((element) => { 150 const rect = element.getBoundingClientRect(); 151 const offsetTop = rect.top; 152 const scaleOrigin = element.getAttribute('data-scale-origin') || 'center center';
153 const windowHeight = window.innerHeight; 154 const defaultFinalSetting = 'middle'; 155 156 // Traitement multi-règles pour data-scale-intensity 157 let scaleIntensity = 1; // valeur par défaut 158 const dataScaleIntensityAttr = element.getAttribute('data-scale-intensity'); 159 if (dataScaleIntensityAttr) { 160 if (dataScaleIntensityAttr.indexOf(':') > -1) { 161 // Format multi-règles : "minWidth:intensity,minWidth:intensity,..." 162 const intensityRules = dataScaleIntensityAttr.split(',').map(rule => { 163 const parts = rule.split(':'); 164 return { minWidth: parseInt(parts[0].trim(), 10), intensity: parseFloat(parts[1].trim()) }; 165 }); 166 // On trie par largeur minimale décroissante 167 intensityRules.sort((a, b) => b.minWidth - a.minWidth); 168 // Sélection de la première règle respectée 169 for (let rule of intensityRules) { 170 if (window.innerWidth >= rule.minWidth) { 171 scaleIntensity = rule.intensity; 172 break; 173 } 174 } 175 } else { 176 scaleIntensity = parseFloat(dataScaleIntensityAttr) || 1; 177 } 178 } 179 180 // Traitement multi-règles pour data-scale-final 181 const dataScaleFinalAttr = element.getAttribute('data-scale-final') || defaultFinalSetting; 182 let finalSetting = defaultFinalSetting; 183 if (dataScaleFinalAttr.indexOf(':') > -1) { 184 // Format multi-règles : "minWidth:position,minWidth:position,..." 185 const finalRules = dataScaleFinalAttr.split(',').map(rule => { 186 const parts = rule.split(':'); 187 return { minWidth: parseInt(parts[0].trim(), 10), position: parts[1].trim() }; 188 }); 189 // On trie par largeur minimale décroissante 190 finalRules.sort((a, b) => b.minWidth - a.minWidth); 191 for (let rule of finalRules) { 192 if (window.innerWidth >= rule.minWidth) { 193 finalSetting = rule.position; 194 break; 195 } 196 } 197 } else { 198 finalSetting = dataScaleFinalAttr; 199 } 200 201 // Définition du point final d'échelle en fonction de la position choisie 202 let finalScalePoint; 203 switch(finalSetting) { 204 case 'top': 205 finalScalePoint = 0; 206 break; 207 case 'quarter': 208 finalScalePoint = windowHeight / 4; 209 break; 210 case 'three-quarters': 211 finalScalePoint = windowHeight * 0.75; 212 break; 213 case 'middle': 214 default: 215 finalScalePoint = windowHeight / 2; 216 break; 217 } 218 219 const startScalePoint = windowHeight; 220 let scaleValue = 1; 221 222 element.style.transformOrigin = scaleOrigin; 223 224 if (offsetTop < startScalePoint && offsetTop > finalScalePoint) { 225 const scaleFactor = 1 - (offsetTop - finalScalePoint) / (startScalePoint - finalScalePoint); 226 scaleValue = Math.max(0, 1 - scaleIntensity * (1 - scaleFactor)); 227 element.style.transform = `scale(${scaleValue})`; 228 } else if (offsetTop <= finalScalePoint) { 229 element.style.transform = 'scale(1)'; 230 } else { 231 element.style.transform = `scale(${Math.max(0, 1 - scaleIntensity)})`; 232 } 233 }); 234 235 236 requestAnimationFrame(applyScrollEffects); 237 } 238 239 requestAnimationFrame(applyScrollEffects); 240 241 // Fonction raf pour Lenis 242 function raf(time) { 243 lenis.raf(time); 244 requestAnimationFrame(raf); 245 } 246 247 requestAnimationFrame(raf); 248 249 // Observer les ajouts dynamiques d'éléments 250 const observer = new MutationObserver((mutations) => { 251 mutations.forEach((mutation) => { 252 mutation.addedNodes.forEach((node) => { 253 if (node.nodeType === 1) { // Assurez-vous que c'est un élément 254 const computedStyle = window.getComputedStyle(node); 255 const overflow = computedStyle.overflow; 256 const overflowY = computedStyle.overflowY; 257 const overflowX = computedStyle.overflowX; 258 259 if ( 260 overflow === 'scroll' || overflow === 'auto' || 261 overflowY === 'scroll' || overflowY === 'auto' || 262 overflowX === 'scroll' || overflowX === 'auto' 263 ) { 264 lenis.prevent(node); 265 node.setAttribute('data-lenis-prevent', 'true'); // Ajout de l'attribut 266 } 267 } 268 }); 269 }); 270 }); 271 272 observer.observe(document.body, { childList: true, subtree: true }); 273});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.