diff --git a/theme_3d_systems/static/src/js/widgets/widget_stats_counter.js b/theme_3d_systems/static/src/js/widgets/widget_stats_counter.js new file mode 100644 index 0000000..4948f26 --- /dev/null +++ b/theme_3d_systems/static/src/js/widgets/widget_stats_counter.js @@ -0,0 +1,43 @@ +/** @odoo-module **/ + +import publicWidget from '@web/legacy/js/public/public_widget'; + +publicWidget.registry.ThemeStatsCounter = publicWidget.Widget.extend({ + selector: '.s_stats_matrix', + + start: function () { + this._super.apply(this, arguments); + + const counters = this.el.querySelectorAll('.stat-number'); + if (!counters.length) return; + + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + counters.forEach((c) => this._animateCounter(c)); + observer.disconnect(); + } + }); + }, { threshold: 0.2 }); + + observer.observe(this.el); + }, + + _animateCounter: function (el) { + const target = parseFloat(el.dataset.target || el.textContent.replace(/[^0-9.]/g, '')); + const suffix = el.dataset.suffix || ''; + let current = 0; + const step = target / 40; + const timer = setInterval(() => { + current += step; + if (current >= target) { + el.textContent = (target % 1 === 0 ? target : target.toFixed(1)) + suffix; + clearInterval(timer); + } else { + el.textContent = (target % 1 === 0 ? Math.floor(current) : current.toFixed(1)) + suffix; + } + }, 30); + }, +}); + +export default publicWidget.registry.ThemeStatsCounter;