197 lines
6.8 KiB
JavaScript
197 lines
6.8 KiB
JavaScript
/*
|
||
|
||
countUp.js
|
||
by @inorganik
|
||
|
||
*/
|
||
|
||
// 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)
|
||
|
||
var CountUp = function(target, startVal, endVal, decimals, duration, options) {
|
||
|
||
// 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', 'o'];
|
||
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);
|
||
};
|
||
}
|
||
|
||
// default options
|
||
this.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
|
||
};
|
||
// extend default options with passed options object
|
||
for (var key in options) {
|
||
if (options.hasOwnProperty(key)) {
|
||
this.options[key] = options[key];
|
||
}
|
||
}
|
||
if (this.options.separator === '') this.options.useGrouping = false;
|
||
if (!this.options.prefix) this.options.prefix = '';
|
||
if (!this.options.suffix) this.options.suffix = '';
|
||
|
||
this.d = (typeof target === 'string') ? document.getElementById(target) : target;
|
||
this.startVal = Number(startVal);
|
||
this.endVal = Number(endVal);
|
||
this.countDown = (this.startVal > this.endVal);
|
||
this.frameVal = this.startVal;
|
||
this.decimals = Math.max(0, decimals || 0);
|
||
this.dec = Math.pow(10, this.decimals);
|
||
this.duration = Number(duration) * 1000 || 2000;
|
||
var self = this;
|
||
|
||
this.version = function () { return '1.6.0'; };
|
||
|
||
// Print value to target
|
||
this.printValue = function(value) {
|
||
var result = (!isNaN(value)) ? self.formatNumber(value) : '--';
|
||
if (self.d.tagName == 'INPUT') {
|
||
this.d.value = result;
|
||
}
|
||
else if (self.d.tagName == 'text' || self.d.tagName == 'tspan') {
|
||
this.d.textContent = result;
|
||
}
|
||
else {
|
||
this.d.innerHTML = result;
|
||
}
|
||
};
|
||
|
||
// 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) 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) {
|
||
self.frameVal = self.startVal - self.easeOutExpo(progress, 0, self.startVal - self.endVal, self.duration);
|
||
} else {
|
||
self.frameVal = self.easeOutExpo(progress, self.startVal, self.endVal - self.startVal, self.duration);
|
||
}
|
||
} else {
|
||
if (self.countDown) {
|
||
self.frameVal = self.startVal - ((self.startVal - self.endVal) * (progress / self.duration));
|
||
} else {
|
||
self.frameVal = self.startVal + (self.endVal - self.startVal) * (progress / self.duration);
|
||
}
|
||
}
|
||
|
||
// 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;
|
||
}
|
||
|
||
// decimal
|
||
self.frameVal = Math.round(self.frameVal*self.dec)/self.dec;
|
||
|
||
// format and print value
|
||
self.printValue(self.frameVal);
|
||
|
||
// whether to continue
|
||
if (progress < self.duration) {
|
||
self.rAF = requestAnimationFrame(self.count);
|
||
} else {
|
||
if (self.callback) self.callback();
|
||
}
|
||
};
|
||
// start your animation
|
||
this.start = function(callback) {
|
||
self.callback = callback;
|
||
self.rAF = requestAnimationFrame(self.count);
|
||
return false;
|
||
};
|
||
// toggles pause/resume animation
|
||
this.pauseResume = function() {
|
||
if (!self.paused) {
|
||
self.paused = true;
|
||
cancelAnimationFrame(self.rAF);
|
||
} else {
|
||
self.paused = false;
|
||
delete self.startTime;
|
||
self.duration = self.remaining;
|
||
self.startVal = self.frameVal;
|
||
requestAnimationFrame(self.count);
|
||
}
|
||
};
|
||
// reset to startVal so animation can be run again
|
||
this.reset = function() {
|
||
self.paused = false;
|
||
delete self.startTime;
|
||
self.startVal = startVal;
|
||
cancelAnimationFrame(self.rAF);
|
||
self.printValue(self.startVal);
|
||
};
|
||
// pass a new endVal and start animation
|
||
this.update = function (newEndVal) {
|
||
cancelAnimationFrame(self.rAF);
|
||
self.paused = false;
|
||
delete self.startTime;
|
||
self.startVal = self.frameVal;
|
||
self.endVal = Number(newEndVal);
|
||
self.countDown = (self.startVal > self.endVal);
|
||
self.rAF = requestAnimationFrame(self.count);
|
||
};
|
||
this.formatNumber = function(nStr) {
|
||
nStr = nStr.toFixed(self.decimals);
|
||
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 self.options.prefix + x1 + x2 + self.options.suffix;
|
||
};
|
||
|
||
// format startVal on initialization
|
||
self.printValue(self.startVal);
|
||
};
|
||
|
||
// Example:
|
||
// var numAnim = new countUp("SomeElementYouWantToAnimate", 0, 99.99, 2, 2.5);
|
||
// numAnim.start();
|
||
// numAnim.update(135);
|
||
// with optional callback:
|
||
// numAnim.start(someMethodToCallOnComplete);
|