Hey guys,
Here is a simple javascript counter animation that I created...
- Triggered if counters are inview (scrolling down otherwise)
- Optional abriviation on the numbers
- Optional extra symbol (+, $, % etc..)
- Optional decimal places ( 0, 1, 2, 3 etc)
- Optional starting number
Here is the html (ignore the bootstrap styling if you need to set your own classes):
<div class="py-4 container-fluid">
<div id="counterElements" class="row row-cols-1 row-cols-md-4 row-cols-sm-2 border-top border-primary border-2 pt-3">
<div class="col p-3 text-center txt-shadow-black-bold">
<i class="fas fa-layer-group fa-3x text-body txt-shadow-secondary-wide w-100"></i>
<p class="counter text-center h1 text-primary fw-bold mb-0 lh-base w-auto d-inline" data-count="1254738" data-decimals="2" data-abr="">0</p>
<span class="d-inline-block h4 text-primary fw-light"></span>
<p class="text-center mb-0 small text-body">POSTS</p>
</div>
<div class="col p-3 text-center txt-shadow-black-bold">
<i class="fas fa-tasks fa-3x text-body txt-shadow-secondary-wide w-100"></i>
<p class="counter text-center h1 text-primary fw-bold mb-0 lh-base w-auto d-inline" data-count="285" data-decimals="0" data-abr="">0</p>
<span class="d-inline-block h4 text-primary fw-light">+</span>
<p class="text-center mb-0 small text-body">TASKS</p>
</div>
<div class="col p-3 text-center txt-shadow-black-bold">
<i class="far fa-id-card fa-3x text-body txt-shadow-secondary-wide w-100"></i>
<p class="counter text-center h1 text-primary fw-bold mb-0 lh-base w-auto d-inline" data-count="24592" data-decimals="2" data-abr="">0</p>
<span class="d-inline-block h4 text-primary fw-light"></span>
<p class="text-center mb-0 small text-body">MEMBERS</p>
</div>
<div class="col p-3 text-center txt-shadow-black-bold">
<i class="far fa-calendar-check fa-3x text-body txt-shadow-secondary-wide w-100"></i>
<p class="counter text-center h1 text-primary fw-bold mb-0 lh-base w-auto d-inline" data-count="1296" data-decimals="0" data-abr="no">0</p>
<span class="d-inline-block h4 text-primary fw-light">%</span>
<p class="text-center mb-0 small text-body">SUCCESS</p>
</div>
</div>
</div>
and here is the javascript:
$(document).ready(function () {
const counts = document.querySelectorAll('.counter');
var element = document.getElementById('counterElements');
var elementHeight = element.clientHeight;
// check if counters are already inView on page load
if (inView()) {
// element is in view, start animation
startCountAnimation();
}
// listen for scroll event and call animate function
document.addEventListener('scroll', animate);
// check if element is in view
function inView() {
// get window height
var windowHeight = window.innerHeight;
// get number of pixels that the document is scrolled
var scrollY = window.scrollY || window.pageYOffset;
// get current scroll position (distance from the top of the page to the bottom of the current viewport)
var scrollPosition = scrollY + windowHeight;
// get element position (distance from the top of the page to the bottom of the element)
var elementPosition = element.getBoundingClientRect().top + scrollY + elementHeight;
// is scroll position greater than element position? (is element in view?)
if (scrollPosition > elementPosition) {
document.removeEventListener('scroll', animate);
return true;
}
return false;
}
// animate element when it is in view
function animate() {
// is element in view?
if (inView()) {
// element is in view, start animation
startCountAnimation();
}
}
function startCountAnimation() {
counts.forEach((counter) => {
function upDate() {
// get the data attributes for .counters elements
const countAbr = counter.getAttribute('data-abr') == "no" ? false : true;
const countNumber = Number(counter.getAttribute('data-count'));
const countDecimals = (Number(counter.getAttribute('data-decimals')) ? Number(counter.getAttribute('data-decimals')) : 0);
// get the starting number for the counter
const count = Number(counter.innerText);
// set the speed ( the higher value the slower animation)
const speed = 60;
// set the suffix symbol for thousands and millions
let smbl = ((countNumber < 1000 && countAbr) ? "" : (countNumber < 1000000 && countAbr) ? "K" : (countNumber >= 1000000 && countAbr) ? "M" : "");
// set the multiplier for calculating the new number
let sess = ((countNumber < 1000 && countAbr) ? 1 : (countNumber < 1000000 && countAbr) ? 1000 : (countNumber >= 1000000 && countAbr) ? 1000000 : 1);
// set the symbol to .counter style properties
counter.style.setProperty("--symbl", '"' + smbl + '"');
// calculating the target/end number of the .counter animation
target = (countNumber / sess);
// set the increasing step
const inc = (target / speed);
// if the current number is lower than the target then set the new number and set the timer
if (count < target) {
counter.innerText = Number((inc + count)).toFixed(countDecimals);
setTimeout(upDate, speed);
}
// else set the exact end number as in the data-count attribute
else {
counter.innerText = target.toFixed(countDecimals);
}
}
upDate();
})
}
});