1const COUNTER_CONFIG = { 2 duration: 1000, 3 steps: 60, 4 threshold: 0.5 5}; 6 7function initializeCounters(sectionClass, itemClass, valueSelector) { 8 const { duration, steps, threshold } = COUNTER_CONFIG; 9 10 function animateCounter(element, targetValue, originalText) { 11 let currentValue = 0; 12 const increment = targetValue / steps; 13 const stepTime = duration / steps; 14 15 const symbols = originalText.replace(/[\d.]/g, ''); 16 17 const counter = setInterval(() => { 18 currentValue += increment; 19 20 if (Number.isInteger(targetValue)) { 21 element.textContent = Math.round(currentValue) + symbols; 22 } else { 23 element.textContent = currentValue.toFixed(3) + symbols; 24 } 25 26 if (currentValue >= targetValue) { 27 element.textContent = originalText; 28 clearInterval(counter); 29 } 30 }, stepTime); 31 } 32 33 const observer = new IntersectionObserver((entries) => { 34 entries.forEach(entry => { 35 if (entry.isIntersecting) { 36 const valueElement = entry.target.querySelector(valueSelector); 37 const originalText = valueElement.textContent; 38 const targetValue = parseFloat(originalText.replace(/[^\d.]/g, '')); 39 valueElement.textContent = '0' + originalText.replace(/[\d.]/g, ''); 40 animateCounter(valueElement, targetValue, originalText); 41 observer.unobserve(entry.target); 42 } 43 }); 44 }, { threshold }); 45 46 document.querySelectorAll(sectionClass).forEach(section => { 47 section.querySelectorAll(itemClass).forEach(item => { 48 observer.observe(item); 49 }); 50 }); 51} 52 53window.addEventListener('DOMContentLoaded', () => { 54 initializeCounters('.about', '.stats .info', '.counter'); 55});
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.