/*



    countUp.js

    by @inorganik

    v 1.0.3



*/



// target = id of html element or var of previously selected html element where counting occurs

// startVal = the value you want to begin at

// endVal = the value you want to arrive at

// decimals = number of decimal places in number, default 0

// duration = duration in seconds, default 2



function countUp(target, startVal, endVal, decimals, duration) {

    

    // make sure requestAnimationFrame and cancelAnimationFrame are defined

    // polyfill for browsers without native support

    // by Opera engineer Erik M?śller

    var lastTime = 0;

    var vendors = ['webkit', 'moz', 'ms'];

    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {

        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];

        window.cancelAnimationFrame =

          window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];

    }

    if (!window.requestAnimationFrame) {

        window.requestAnimationFrame = function(callback, element) {

            var currTime = new Date().getTime();

            var timeToCall = Math.max(0, 16 - (currTime - lastTime));

            var id = window.setTimeout(function() { callback(currTime + timeToCall); },

              timeToCall);

            lastTime = currTime + timeToCall;

            return id;

        }

    }

    if (!window.cancelAnimationFrame) {

        window.cancelAnimationFrame = function(id) {

            clearTimeout(id);

        }

    }



    var self = this;



    // toggle easing

    this.useEasing = true;

    

    this.d = (typeof target === 'string') ? document.getElementById(target) : target;

    self.startVal = Number(startVal);

    endVal = Number(endVal);

    this.countDown = (startVal > endVal) ? true : false;

    decimals = Math.max(0, decimals || 0);

    this.dec = Math.pow(10, decimals);

    this.duration = duration * 1000 || 2000;

    this.startTime = null;

    this.timestamp = null;

    this.remaining = null;

    this.frameVal = self.startVal;

    this.rAF = null;

    

    // Robert Penner's easeOutExpo

    this.easeOutExpo = function(t, b, c, d) {

        return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;

    }

    this.count = function(timestamp) {

        

        if (self.startTime === null) self.startTime = timestamp;



        self.timestamp = timestamp;



        var progress = timestamp - self.startTime;

        self.remaining = self.duration - progress;

        

        // to ease or not to ease

        if (self.useEasing) {

            if (self.countDown) {

                var i = self.easeOutExpo(progress, 0, self.startVal - endVal, self.duration);

                self.frameVal = self.startVal - i;

            } else {

                self.frameVal = self.easeOutExpo(progress, self.startVal, endVal - self.startVal, self.duration);

            }

        } else {

            if (self.countDown) {

                var i = (self.startVal - endVal) * (progress / self.duration);

                self.frameVal = self.startVal - i;

            } else {

                self.frameVal = self.startVal + (endVal - self.startVal) * (progress / self.duration);

            }

        }

        

        // decimal

        self.frameVal = Math.round(self.frameVal*self.dec)/self.dec;

        

        // don't go past endVal since progress can exceed duration in the last frame

        if (self.countDown) {

            self.frameVal = (self.frameVal < endVal) ? endVal : self.frameVal;

        } else {

            self.frameVal = (self.frameVal > endVal) ? endVal : self.frameVal;

        }

        

        // format and print value

        self.d.innerHTML = self.addCommas(self.frameVal.toFixed(decimals));

               

        // whether to continue

        if (progress < self.duration) {

            self.rAF = requestAnimationFrame(self.count);

        } else {

            if (self.callback != null) self.callback();

        }

    }  

    this.start = function(callback) {

        self.callback = callback;

        // make sure values are valid

        if (!isNaN(endVal) && !isNaN(startVal)) {

            self.rAF = requestAnimationFrame(self.count);

        } else {

            console.log('countUp error: startVal or endVal is not a number');

            self.d.innerHTML = '--';

        }

        return false;

    }

    this.stop = function() {

        cancelAnimationFrame(self.rAF);

    }

    this.reset = function() {

        self.startTime = null;

        cancelAnimationFrame(self.rAF);

        self.d.innerHTML = self.addCommas(startVal.toFixed(decimals));

    }

    this.resume = function() {

        self.startTime = null;

        self.duration = self.remaining;

        self.startVal = self.frameVal;

        requestAnimationFrame(self.count);

    }

    this.addCommas = function(nStr) {

        nStr += '';

        var x, x1, x2, rgx;

        x = nStr.split('.');

        x1 = x[0];

        x2 = x.length > 1 ? '.' + x[1] : '';

        rgx = /(\d+)(\d{3})/;

        while (rgx.test(x1)) {

            x1 = x1.replace(rgx, '$1' + ',' + '$2');

        }

        return x1 + x2;

    }



    // format startVal on initialization

    self.d.innerHTML = self.addCommas(startVal.toFixed(decimals));

}



// Example:

// var numAnim = new countUp("SomeElementYouWantToAnimate", 0, 99.99, 2, 1.5);

// numAnim.start();

// with optional callback:

// numAnim.start(someMethodToCallOnComplete);