/* countup.js by @inorganik v 1.1.0 */ // 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, default 0 // duration = duration of animation in seconds, default 2 // options = optional object of options (see below) function countup(target, startval, endval, decimals, duration, options) { // default options this.options = options || { useeasing : true, // toggle easing usegrouping : true, // 1,000,000 vs 1000000 separator : ',', // character to use as a separator decimal : '.' // character to use as a decimal } // 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; this.d = (typeof target === 'string') ? document.getelementbyid(target) : target; this.startval = number(startval); this.endval = number(endval); this.countdown = (this.startval > this.endval) ? true : false; this.starttime = null; this.timestamp = null; this.remaining = null; this.frameval = this.startval; this.raf = null; this.decimals = math.max(0, decimals || 0); this.dec = math.pow(10, this.decimals); this.duration = duration * 1000 || 2000; // 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.options.useeasing) { if (self.countdown) { var i = self.easeoutexpo(progress, 0, self.startval - self.endval, self.duration); self.frameval = self.startval - i; } else { self.frameval = self.easeoutexpo(progress, self.startval, self.endval - self.startval, self.duration); } } else { if (self.countdown) { var i = (self.startval - self.endval) * (progress / self.duration); self.frameval = self.startval - i; } else { self.frameval = self.startval + (self.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 < self.endval) ? self.endval : self.frameval; } else { self.frameval = (self.frameval > self.endval) ? self.endval : self.frameval; } // format and print value self.d.innerhtml = self.formatnumber(self.frameval.tofixed(self.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(self.endval) && !isnan(self.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.formatnumber(self.startval.tofixed(self.decimals)); } this.resume = function() { self.starttime = null; self.duration = self.remaining; self.startval = self.frameval; requestanimationframe(self.count); } this.formatnumber = function(nstr) { nstr += ''; var x, x1, x2, rgx; x = nstr.split('.'); x1 = x[0]; x2 = x.length > 1 ? self.options.decimal + x[1] : ''; rgx = /(\d+)(\d{3})/; if (self.options.usegrouping) { while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + self.options.separator + '$2'); } } return x1 + x2; } // format startval on initialization self.d.innerhtml = self.formatnumber(self.startval.tofixed(self.decimals)); } // example: // var numanim = new countup("someelementyouwanttoanimate", 0, 99.99, 2, 2.5); // numanim.start(); // with optional callback: // numanim.start(somemethodtocalloncomplete);