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.
		
		
		
		
		
			
		
			
				
					
					
						
							261 lines
						
					
					
						
							7.7 KiB
						
					
					
				
			
		
		
	
	
							261 lines
						
					
					
						
							7.7 KiB
						
					
					
				
 | 
						|
(function(root, factory) { | 
						|
  if (typeof define === 'function' && define.amd) { | 
						|
    define(factory); | 
						|
  } else if (typeof exports === 'object') { | 
						|
    module.exports = factory(require, exports, module); | 
						|
  } else { | 
						|
    root.CountUp = factory(); | 
						|
  } | 
						|
}(this, function(require, exports, module) { | 
						|
 | 
						|
/* | 
						|
 | 
						|
	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); | 
						|
}; | 
						|
 | 
						|
return CountUp; | 
						|
 | 
						|
}));
 | 
						|
 |