<script>
class CounterUp {
constructor(element, options = {}) {
this.element = element;
let parent = element.parentElement;
let timeAttribute = parent ? parent.getAttribute('js-util-counterup-time') : null;
let time = timeAttribute ? parseInt(timeAttribute, 10) : options.time || 2000;
this.options = Object.assign(
{
time: time,
delay: 10,
},
options
);
this.origValue = element.textContent;
let loopElement = element.closest('[js-util-counterup-loop]');
let loopAttribute = loopElement ? loopElement.getAttribute('js-util-counterup-loop') : null;
this.shouldLoop = loopAttribute === 'true';
this.nums = [];
this.init();
}
counterUpper() {
this.nums = [];
const divisions = this.options.time / this.options.delay;
let num = this.origValue;
const isComma = /[0-9]+,[0-9]+/.test(num);
num = num.replace(/,/g, '');
const isInt = /^[0-9]+$/.test(num);
const isFloat = /^[0-9]+\.[0-9]+$/.test(num);
const decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
for (let i = divisions; i >= 1; i--) {
let newNum = parseInt((num / divisions) * i);
if (isFloat) {
newNum = parseFloat((num / divisions) * i).toFixed(decimalPlaces);
}
if (isComma) {
while (/\d+(\d{3})/.test(newNum.toString())) {
newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
}
}
this.nums.unshift(newNum);
}
this.element.textContent = this.origValue;
this.element.textContent = '0';
const updateNumber = () => {
this.element.textContent = this.nums.shift();
if (this.nums.length) {
setTimeout(updateNumber, this.options.delay);
}
};
setTimeout(updateNumber, this.options.delay);
}
init() {
const observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
this.counterUpper();
if (!this.shouldLoop && entry.isIntersecting) {
observer.disconnect();
}
}
});
},
{ threshold: 1.0 }
);
observer.observe(this.element);
}
}
document.addEventListener('DOMContentLoaded', function () {
let timeCounter = document
.querySelector('[js-util-counterup-time]')
.getAttribute('js-util-counterup-time');
document.querySelectorAll('[js-util-counterup]').forEach((element) => {
new CounterUp(element, { delay: 100, time: timeCounter });
});
});</script>
Etape 1 - Ajouter le script sur la page ou le projet Webflow
<!-- Scripts by Justa | Counter Up -->
<script src="https://cdn.jsdelivr.net/npm/@justaa/scripts/dist/util/counterup.js"></script>
<script>
class CounterUp {
constructor(element, options = {}) {
this.element = element;
let parent = element.parentElement;
let timeAttribute = parent ? parent.getAttribute('js-util-counterup-time') : null;
let time = timeAttribute ? parseInt(timeAttribute, 10) : options.time || 2000;
this.options = Object.assign(
{
time: time,
delay: 10,
},
options
);
this.origValue = element.textContent;
let loopElement = element.closest('[js-util-counterup-loop]');
let loopAttribute = loopElement ? loopElement.getAttribute('js-util-counterup-loop') : null;
this.shouldLoop = loopAttribute === 'true';
this.nums = [];
this.init();
}
counterUpper() {
this.nums = [];
const divisions = this.options.time / this.options.delay;
let num = this.origValue;
const isComma = /[0-9]+,[0-9]+/.test(num);
num = num.replace(/,/g, '');
const isInt = /^[0-9]+$/.test(num);
const isFloat = /^[0-9]+\.[0-9]+$/.test(num);
const decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
for (let i = divisions; i >= 1; i--) {
let newNum = parseInt((num / divisions) * i);
if (isFloat) {
newNum = parseFloat((num / divisions) * i).toFixed(decimalPlaces);
}
if (isComma) {
while (/\d+(\d{3})/.test(newNum.toString())) {
newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
}
}
this.nums.unshift(newNum);
}
this.element.textContent = this.origValue;
this.element.textContent = '0';
const updateNumber = () => {
this.element.textContent = this.nums.shift();
if (this.nums.length) {
setTimeout(updateNumber, this.options.delay);
}
};
setTimeout(updateNumber, this.options.delay);
}
init() {
const observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
this.counterUpper();
if (!this.shouldLoop && entry.isIntersecting) {
observer.disconnect();
}
}
});
},
{ threshold: 1.0 }
);
observer.observe(this.element);
}
}
document.addEventListener('DOMContentLoaded', function () {
let timeCounter = document
.querySelector('[js-util-counterup-time]')
.getAttribute('js-util-counterup-time');
document.querySelectorAll('[js-util-counterup]').forEach((element) => {
new CounterUp(element, { delay: 100, time: timeCounter });
});
});</script>
Etape 2 - Ajouter les attributes correspondants
Div - Définir la durée de l'animation
Nom
js-util-counterup-time
Valeur
[identifier]
Ajouter l'attribute à une div parente des éléments. Il ne doit être présent qu'une seule fois
Modifier l'identifier par un chiffre en ms
Paragraph - Identifier chaque chiffre dynamique
Nom
js-util-counterup
Valeur
Ajouter l'attribute à tous les éléments qui ont besoin d'être dynamique
Div - identifier si le compteur doit être joué en boucle
Nom
js-util-counterup-loop
Valeur
true
Ajouter l'attribute pour que l'animation se joue à chaque passage au sein de la section.
Possibilité de définir l'attribute de manière granulaire sur chaque nombre. Dans ce cas, ajouter l'attribute à l'élément parent le plus proche du nombre en question
Nom
Valeur
Nom
Valeur
Nom
Valeur
Nom
Valeur
Tuto, template & scripts
Tuto
Template
Script
<script>
class CounterUp {
constructor(element, options = {}) {
this.element = element;
let parent = element.parentElement;
let timeAttribute = parent ? parent.getAttribute('js-util-counterup-time') : null;
let time = timeAttribute ? parseInt(timeAttribute, 10) : options.time || 2000;
this.options = Object.assign(
{
time: time,
delay: 10,
},
options
);
this.origValue = element.textContent;
let loopElement = element.closest('[js-util-counterup-loop]');
let loopAttribute = loopElement ? loopElement.getAttribute('js-util-counterup-loop') : null;
this.shouldLoop = loopAttribute === 'true';
this.nums = [];
this.init();
}
counterUpper() {
this.nums = [];
const divisions = this.options.time / this.options.delay;
let num = this.origValue;
const isComma = /[0-9]+,[0-9]+/.test(num);
num = num.replace(/,/g, '');
const isInt = /^[0-9]+$/.test(num);
const isFloat = /^[0-9]+\.[0-9]+$/.test(num);
const decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
for (let i = divisions; i >= 1; i--) {
let newNum = parseInt((num / divisions) * i);
if (isFloat) {
newNum = parseFloat((num / divisions) * i).toFixed(decimalPlaces);
}
if (isComma) {
while (/\d+(\d{3})/.test(newNum.toString())) {
newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
}
}
this.nums.unshift(newNum);
}
this.element.textContent = this.origValue;
this.element.textContent = '0';
const updateNumber = () => {
this.element.textContent = this.nums.shift();
if (this.nums.length) {
setTimeout(updateNumber, this.options.delay);
}
};
setTimeout(updateNumber, this.options.delay);
}
init() {
const observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
this.counterUpper();
if (!this.shouldLoop && entry.isIntersecting) {
observer.disconnect();
}
}
});
},
{ threshold: 1.0 }
);
observer.observe(this.element);
}
}
document.addEventListener('DOMContentLoaded', function () {
let timeCounter = document
.querySelector('[js-util-counterup-time]')
.getAttribute('js-util-counterup-time');
document.querySelectorAll('[js-util-counterup]').forEach((element) => {
new CounterUp(element, { delay: 100, time: timeCounter });
});
});</script>