Mohsen Jalali
Mohsen Jalali

Reputation: 1

Intersection observer and Animated Number Counter

The problem with the code below is that the Counters do not stop at the same time. Is there any way to adjust the duration of the Counters? As far as I know, by using animate function JQuery it is possible to adjust the duration, but I wonder how to combine that with Intersection Observer in order to run animated numbers just as they become visible.

const counterElements = document.querySelectorAll(".count");

// Counters
function counter(target, start, stop) {
  target.innerText = 0.1;
  const counterInterval = setInterval(() => {
    start += 0.1;
    const valueConverted = (Math.round(start * 100) / 100).toFixed(1);
    target.innerText = valueConverted;
    if (valueConverted == stop) {
      clearInterval(counterInterval);
    }
  }, 30);
}

function obCallBack(entries) {
  entries.forEach((entry) => {
    const { target } = entry;
    const stopValue = target.innerText;
    const startValue = 0;
    if (!entry.isIntersecting) return;
    counter(target, startValue, stopValue);
    counterObserver.unobserve(target);
  });
}

const counterObserver = new IntersectionObserver(obCallBack, { threshold: 1 });
counterElements.forEach((counterElem) => counterObserver.observe(counterElem));
.emptyspace{
  height:400px;
  }
<div class="emptyspace"></div>
<p class="count">5.2</p>
<p class="count">50.9</p>
</div>

Upvotes: 0

Views: 834

Answers (1)

DanOne
DanOne

Reputation: 1

You should use a ratio rather than a fixed number.

const speed = 100;
const inc = Number(stop / speed);

const counterElements = document.querySelectorAll(".count");
const speed = 100; // the lower the slower

// Counters
function counter(target, start, stop) {
  target.innerText = 0.1;
  const counterInterval = setInterval(() => {
    const inc = Number(stop / speed);
    start += inc;
    const valueConverted = (Math.round(start * 100) / 100).toFixed(1);
    target.innerText = valueConverted;
    if (valueConverted == stop) {
      clearInterval(counterInterval);
    }
  }, 30);
}

function obCallBack(entries) {
  entries.forEach((entry) => {
    const { target } = entry;
    const stopValue = target.innerText;
    const startValue = 0;
    if (!entry.isIntersecting) return;
    counter(target, startValue, stopValue);
    counterObserver.unobserve(target);
  });
}

const counterObserver = new IntersectionObserver(obCallBack, { threshold: 1 });
counterElements.forEach((counterElem) => counterObserver.observe(counterElem));
.emptyspace{
  height:400px;
  }
<div class="emptyspace"></div>
<p class="count">5.2</p>
<p class="count">50.9</p>
</div>

Upvotes: 0

Related Questions