factories/timer-factory.js

/**
 * AngularJS Factory for tracking time instances
 *
 * @class Timer
 * @see https://docs.angularjs.org/api/ng/type/angular.Module#factory
 */
angular.module('tgaApp').factory('Timer', ['$timeout',
  function TimerFactory($timeout) {
    /**
     * @constructs
     * @lends Timer
     */
    function Timer() {
      let timerValue = 0;
      let paused = true;

      /**
       * Current timer progress, in % (0-100).
       *
       * @type {number}
       */
      this.percentComplete = 0;

      /**
       * Set (and optionally start) the timer.
       *
       * @param {number} timeValue - Time to wait, in seconds.
       * @param {boolean} autoplay - Whether to start the timer immediately.
       * @param {function} callback - Callback to run when timer completes.
       */
      this.set = (timeValue, autoplay, callback) => {
        if (this.timeout) this.clear();
        this.startTime = this.stopTime = Date.now();
        timerValue = timeValue * 1000;
        this.percentComplete = 0;
        paused = true;
        this.callback = callback;

        if (autoplay) this.start();
      };

      /**
       * Update the timer.
       */
      this.update = () => {
        if (paused) return;
        const diff = Date.now() - this.startTime;
        this.percentComplete = (diff / timerValue) * 100;
        if (this.percentComplete < 100) {
          this.timeout = $timeout(this.update, 10);
        } else {
          if (this.callback) {
            this.callback();
            this.callback = undefined;
          }
          this.clear();
        }
      };

      /**
       * Start the timer.
       */
      this.start = () => {
        const diff = Date.now() - this.stopTime;
        this.startTime += diff;
        paused = false;
        this.timeout = $timeout(this.update, 10);
      };

      /**
       * Stop and clear the timer.
       */
      this.stop = () => {
        paused = true;
        this.stopTime = Date.now();
        this.clear();
      };

      /**
       * Clear the timer's `$timeout` loop.
       */
      this.clear = () => {
        $timeout.cancel(this.timeout);
        this.timeout = undefined;
      };

      /**
       * Clear, reset, and stop the timer.
       */
      this.reset = () => {
        this.clear();
        timerValue = 0;
        paused = true;
        this.percentComplete = 0;
      };
    }
    return Timer;
  },
]);