class countUp {
  constructor(el) {
    this.el = el;
    this.setVars();
    this.init();
  }

  setVars() {
    this.number = this.el.querySelectorAll("[data-countup-number]");
    this.observerOptions = { root: null, rootMargin: "0px 0px", threshold: 0 };
    this.observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        const end = parseFloat(
          entry.target.dataset.countupNumber.replace(/,/g, "")
        );
        const decimals = this.countDecimals(end);
        if (entry.isIntersecting) {
          this.iterateValue(entry.target, end, decimals);
        }
      });
    }, this.observerOptions);
  }

  init() {
    if (this.number.length > 0) {
      this.number.forEach((el) => {
        this.observer.observe(el);
      });
    }
  }

  iterateValue(el, end, decimals) {
    const start = 0;
    const duration = 2500;
    let startTimestamp = null;

    const step = (timestamp) => {
      if (!startTimestamp) startTimestamp = timestamp;
      const elapsedPercent = (timestamp - startTimestamp) / duration;
      const easedProgress = Math.min(this.easeOutQuint(elapsedPercent), 1);
      let interimNumber = Math.abs(easedProgress * (end - start) + start);
      el.innerHTML = this.formatNumber(interimNumber, decimals);
      if (easedProgress < 1) {
        window.requestAnimationFrame(step);
      }
    };

    // requestAnimationFrame returns DOMHighResTimeStamp as a callback (used as timestamp)
    window.requestAnimationFrame(step);
  }

  easeOutQuad(x) {
    return 1 - Math.pow(1 - x, 3);
  }

  easeOutQuint(x) {
    return 1 - Math.pow(1 - x, 5);
  }

  countDecimals(val) {
    if (Math.floor(val) === val) return 0;
    return val.toString().split(".")[1].length || 0;
  }

  formatNumber(val, decimals) {
    return val.toLocaleString("en-US", {
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals,
    });
  }
}

// Simplifed version of Viget dynamic modules to attach instances for this demo
// https://www.viget.com/articles/how-does-viget-javascript/
// You CAN use this pattern, but it's single purpose right now
const dataModules = [...document.querySelectorAll('[data-module="countup"]')];

dataModules.forEach((element) => {
  element.dataset.module.split(" ").forEach(function () {
    new countUp(element);
  });
});
