You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					247 lines
				
				7.4 KiB
			
		
		
			
		
	
	
					247 lines
				
				7.4 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								/*
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									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) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var self = this;
							 | 
						||
| 
								 | 
							
									self.version = function () { return '1.9.3'; };
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// default options
							 | 
						||
| 
								 | 
							
									self.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
							 | 
						||
| 
								 | 
							
										easingFn: easeOutExpo, // optional custom easing function, default is Robert Penner's easeOutExpo
							 | 
						||
| 
								 | 
							
										formattingFn: formatNumber, // optional custom formatting function, default is formatNumber above
							 | 
						||
| 
								 | 
							
										prefix: '', // optional text before the result
							 | 
						||
| 
								 | 
							
										suffix: '', // optional text after the result
							 | 
						||
| 
								 | 
							
										numerals: [] // optionally pass an array of custom numerals for 0-9
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// extend default options with passed options object
							 | 
						||
| 
								 | 
							
									if (options && typeof options === 'object') {
							 | 
						||
| 
								 | 
							
										for (var key in self.options) {
							 | 
						||
| 
								 | 
							
											if (options.hasOwnProperty(key) && options[key] !== null) {
							 | 
						||
| 
								 | 
							
												self.options[key] = options[key];
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (self.options.separator === '') {
							 | 
						||
| 
								 | 
							
										self.options.useGrouping = false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else {
							 | 
						||
| 
								 | 
							
										// ensure the separator is a string (formatNumber assumes this)
							 | 
						||
| 
								 | 
							
										self.options.separator = '' + self.options.separator;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// 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);
							 | 
						||
| 
								 | 
							
										};
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function formatNumber(num) {
							 | 
						||
| 
								 | 
							
										var neg = (num < 0),
							 | 
						||
| 
								 | 
							
								        	x, x1, x2, x3, i, len;
							 | 
						||
| 
								 | 
							
										num = Math.abs(num).toFixed(self.decimals);
							 | 
						||
| 
								 | 
							
										num += '';
							 | 
						||
| 
								 | 
							
										x = num.split('.');
							 | 
						||
| 
								 | 
							
										x1 = x[0];
							 | 
						||
| 
								 | 
							
										x2 = x.length > 1 ? self.options.decimal + x[1] : '';
							 | 
						||
| 
								 | 
							
										if (self.options.useGrouping) {
							 | 
						||
| 
								 | 
							
											x3 = '';
							 | 
						||
| 
								 | 
							
											for (i = 0, len = x1.length; i < len; ++i) {
							 | 
						||
| 
								 | 
							
												if (i !== 0 && ((i % 3) === 0)) {
							 | 
						||
| 
								 | 
							
													x3 = self.options.separator + x3;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												x3 = x1[len - i - 1] + x3;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											x1 = x3;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// optional numeral substitution
							 | 
						||
| 
								 | 
							
										if (self.options.numerals.length) {
							 | 
						||
| 
								 | 
							
											x1 = x1.replace(/[0-9]/g, function(w) {
							 | 
						||
| 
								 | 
							
												return self.options.numerals[+w];
							 | 
						||
| 
								 | 
							
											})
							 | 
						||
| 
								 | 
							
											x2 = x2.replace(/[0-9]/g, function(w) {
							 | 
						||
| 
								 | 
							
												return self.options.numerals[+w];
							 | 
						||
| 
								 | 
							
											})
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return (neg ? '-' : '') + self.options.prefix + x1 + x2 + self.options.suffix;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Robert Penner's easeOutExpo
							 | 
						||
| 
								 | 
							
									function easeOutExpo(t, b, c, d) {
							 | 
						||
| 
								 | 
							
										return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									function ensureNumber(n) {
							 | 
						||
| 
								 | 
							
										return (typeof n === 'number' && !isNaN(n));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									self.initialize = function() { 
							 | 
						||
| 
								 | 
							
										if (self.initialized) return true;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										self.error = '';
							 | 
						||
| 
								 | 
							
										self.d = (typeof target === 'string') ? document.getElementById(target) : target;
							 | 
						||
| 
								 | 
							
										if (!self.d) { 
							 | 
						||
| 
								 | 
							
											self.error = '[CountUp] target is null or undefined'
							 | 
						||
| 
								 | 
							
											return false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										self.startVal = Number(startVal);
							 | 
						||
| 
								 | 
							
										self.endVal = Number(endVal);
							 | 
						||
| 
								 | 
							
										// error checks
							 | 
						||
| 
								 | 
							
										if (ensureNumber(self.startVal) && ensureNumber(self.endVal)) {
							 | 
						||
| 
								 | 
							
											self.decimals = Math.max(0, decimals || 0);
							 | 
						||
| 
								 | 
							
											self.dec = Math.pow(10, self.decimals);
							 | 
						||
| 
								 | 
							
											self.duration = Number(duration) * 1000 || 2000;
							 | 
						||
| 
								 | 
							
											self.countDown = (self.startVal > self.endVal);
							 | 
						||
| 
								 | 
							
											self.frameVal = self.startVal;
							 | 
						||
| 
								 | 
							
											self.initialized = true;
							 | 
						||
| 
								 | 
							
											return true;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											self.error = '[CountUp] startVal ('+startVal+') or endVal ('+endVal+') is not a number';
							 | 
						||
| 
								 | 
							
											return false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Print value to target
							 | 
						||
| 
								 | 
							
									self.printValue = function(value) {
							 | 
						||
| 
								 | 
							
										var result = self.options.formattingFn(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;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									self.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.options.easingFn(progress, 0, self.startVal - self.endVal, self.duration);
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												self.frameVal = self.options.easingFn(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
							 | 
						||
| 
								 | 
							
									self.start = function(callback) {
							 | 
						||
| 
								 | 
							
										if (!self.initialize()) return;
							 | 
						||
| 
								 | 
							
										self.callback = callback;
							 | 
						||
| 
								 | 
							
										self.rAF = requestAnimationFrame(self.count);
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									// toggles pause/resume animation
							 | 
						||
| 
								 | 
							
									self.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
							 | 
						||
| 
								 | 
							
									self.reset = function() {
							 | 
						||
| 
								 | 
							
										self.paused = false;
							 | 
						||
| 
								 | 
							
										delete self.startTime;
							 | 
						||
| 
								 | 
							
										self.initialized = false;
							 | 
						||
| 
								 | 
							
										if (self.initialize()) {
							 | 
						||
| 
								 | 
							
											cancelAnimationFrame(self.rAF);
							 | 
						||
| 
								 | 
							
											self.printValue(self.startVal);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									// pass a new endVal and start animation
							 | 
						||
| 
								 | 
							
									self.update = function (newEndVal) {
							 | 
						||
| 
								 | 
							
										if (!self.initialize()) return;
							 | 
						||
| 
								 | 
							
										newEndVal = Number(newEndVal);
							 | 
						||
| 
								 | 
							
										if (!ensureNumber(newEndVal)) {
							 | 
						||
| 
								 | 
							
											self.error = '[CountUp] update() - new endVal is not a number: '+newEndVal;
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										self.error = '';
							 | 
						||
| 
								 | 
							
										if (newEndVal === self.frameVal) return;
							 | 
						||
| 
								 | 
							
										cancelAnimationFrame(self.rAF);
							 | 
						||
| 
								 | 
							
										self.paused = false;
							 | 
						||
| 
								 | 
							
										delete self.startTime;
							 | 
						||
| 
								 | 
							
										self.startVal = self.frameVal;
							 | 
						||
| 
								 | 
							
										self.endVal = newEndVal;
							 | 
						||
| 
								 | 
							
										self.countDown = (self.startVal > self.endVal);
							 | 
						||
| 
								 | 
							
										self.rAF = requestAnimationFrame(self.count);
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// format startVal on initialization
							 | 
						||
| 
								 | 
							
									if (self.initialize()) self.printValue(self.startVal);
							 | 
						||
| 
								 | 
							
								};
							 |