97 lines
2.5 KiB
JavaScript
97 lines
2.5 KiB
JavaScript
/**
|
|
* About Us 2 — achievements stats count-up animation.
|
|
*/
|
|
(function () {
|
|
var SECTION_SELECTOR = "#about-us-2 .au2-stats";
|
|
var VALUE_SELECTOR = ".au2-stats__value[data-au2-count]";
|
|
var DURATION_MS = 1800;
|
|
|
|
function easeOutCubic(t) {
|
|
return 1 - Math.pow(1 - t, 3);
|
|
}
|
|
|
|
function formatValue(value, useGrouping) {
|
|
if (!useGrouping) return String(value);
|
|
return value.toLocaleString("en-US");
|
|
}
|
|
|
|
function parseCountOptions(el) {
|
|
var raw = el.getAttribute("data-au2-count");
|
|
var to = raw ? Number(raw) : NaN;
|
|
if (!Number.isFinite(to)) return null;
|
|
|
|
return {
|
|
to: to,
|
|
prefix: el.getAttribute("data-au2-prefix") || "",
|
|
suffix: el.getAttribute("data-au2-suffix") || "",
|
|
grouping: el.getAttribute("data-au2-grouping") === "true",
|
|
};
|
|
}
|
|
|
|
function renderValue(el, value, options) {
|
|
el.textContent =
|
|
options.prefix + formatValue(value, options.grouping) + options.suffix;
|
|
}
|
|
|
|
function animateValue(el, options) {
|
|
if (el.dataset.au2Counted === "true") return;
|
|
el.dataset.au2Counted = "true";
|
|
|
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
renderValue(el, options.to, options);
|
|
return;
|
|
}
|
|
|
|
var start = performance.now();
|
|
|
|
function tick(now) {
|
|
var progress = Math.min((now - start) / DURATION_MS, 1);
|
|
var current = Math.round(easeOutCubic(progress) * options.to);
|
|
renderValue(el, current, options);
|
|
|
|
if (progress < 1) {
|
|
requestAnimationFrame(tick);
|
|
} else {
|
|
renderValue(el, options.to, options);
|
|
}
|
|
}
|
|
|
|
renderValue(el, 0, options);
|
|
requestAnimationFrame(tick);
|
|
}
|
|
|
|
function initSection(section) {
|
|
var values = section.querySelectorAll(VALUE_SELECTOR);
|
|
if (!values.length) return;
|
|
|
|
var observer = new IntersectionObserver(
|
|
function (entries, obs) {
|
|
entries.forEach(function (entry) {
|
|
if (!entry.isIntersecting) return;
|
|
|
|
values.forEach(function (el) {
|
|
var options = parseCountOptions(el);
|
|
if (options) animateValue(el, options);
|
|
});
|
|
|
|
obs.unobserve(entry.target);
|
|
});
|
|
},
|
|
{ threshold: 0.35, rootMargin: "0px 0px -40px 0px" }
|
|
);
|
|
|
|
observer.observe(section);
|
|
}
|
|
|
|
function init() {
|
|
var section = document.querySelector(SECTION_SELECTOR);
|
|
if (section) initSection(section);
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|