// DOM Element's document.addEventListener('DOMContentLoaded', () => { const counters = document.querySelectorAll('.counter'); // "42,000" -> "42000", "10,5" -> "10.5", "10.5" -> "10.5" const clean = s => { s = String(s || '').replace(/[^\d.,]/g, ''); if (/^\d{1,3}(,\d{3})+(\.\d+)?$/.test(s)) return s.replace(/,/g, ''); return s.replace(',', '.'); }; for (let n of counters) { let raw = clean(n.getAttribute('data-target')); if (raw === '' || isNaN(parseFloat(raw))) raw = clean(n.innerText); // fallback: typed number const target = parseFloat(raw); if (isNaN(target)) continue; const decimals = (raw.split('.')[1] || '').length; // 10.5 -> 1 decimal const fmt = v => v.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); const duration = 2000; // ms const start = performance.now(); n.innerText = fmt(0); const updateCount = now => { const p = Math.min((now - start) / duration, 1); n.innerText = fmt(target * p); if (p < 1) requestAnimationFrame(updateCount); }; requestAnimationFrame(updateCount); } });