1/* 2 3 countUp.js 4 by @inorganik 5 6*/ 7 8// target = id of html element or var of previously selected html element where counting occurs 9// startVal = the value you want to begin at 10// endVal = the value you want to arrive at 11// decimals = number of decimal places, default 0 12// duration = duration of animation in seconds, default 2 13// options = optional object of options (see below) 14 15var CountUp = function(target, startVal, endVal, decimals, duration, options) { 16 17 var self = this; 18 self.version = function () { return '1.9.3'; }; 19 20 // default options 21 self.options = { 22 useEasing: true, // toggle easing 23 useGrouping: true, // 1,000,000 vs 1000000 24 separator: ',', // character to use as a separator 25 decimal: '.', // character to use as a decimal 26 easingFn: easeOutExpo, // optional custom easing function, default is Robert Penner's easeOutExpo 27 formattingFn: formatNumber, // optional custom formatting function, default is formatNumber above 28 prefix: '', // optional text before the result 29 suffix: '', // optional text after the result 30 numerals: [] // optionally pass an array of custom numerals for 0-9 31 }; 32 33 // extend default options with passed options object 34 if (options && typeof options === 'object') { 35 for (var key in self.options) { 36 if (options.hasOwnProperty(key) && options[key] !== null) { 37 self.options[key] = options[key]; 38 } 39 } 40 } 41 42 if (self.options.separator === '') { 43 self.options.useGrouping = false; 44 } 45 else { 46 // ensure the separator is a string (formatNumber assumes this) 47 self.options.separator = '' + self.options.separator; 48 } 49 50 // make sure requestAnimationFrame and cancelAnimationFrame are defined 51 // polyfill for browsers without native support 52 // by Opera engineer Erik Möller 53 var lastTime = 0; 54 var vendors = ['webkit', 'moz', 'ms', 'o']; 55 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 56 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 57 window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; 58 } 59 if (!window.requestAnimationFrame) { 60 window.requestAnimationFrame = function(callback, element) { 61 var currTime = new Date().getTime(); 62 var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 63 var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); 64 lastTime = currTime + timeToCall; 65 return id; 66 }; 67 } 68 if (!window.cancelAnimationFrame) { 69 window.cancelAnimationFrame = function(id) { 70 clearTimeout(id); 71 }; 72 } 73 74 function formatNumber(num) { 75 var neg = (num < 0), 76 x, x1, x2, x3, i, len; 77 num = Math.abs(num).toFixed(self.decimals); 78 num += ''; 79 x = num.split('.'); 80 x1 = x[0]; 81 x2 = x.length > 1 ? self.options.decimal + x[1] : ''; 82 if (self.options.useGrouping) { 83 x3 = ''; 84 for (i = 0, len = x1.length; i < len; ++i) { 85 if (i !== 0 && ((i % 3) === 0)) { 86 x3 = self.options.separator + x3; 87 } 88 x3 = x1[len - i - 1] + x3; 89 } 90 x1 = x3; 91 } 92 // optional numeral substitution 93 if (self.options.numerals.length) { 94 x1 = x1.replace(/[0-9]/g, function(w) { 95 return self.options.numerals[+w]; 96 }) 97 x2 = x2.replace(/[0-9]/g, function(w) { 98 return self.options.numerals[+w]; 99 }) 100 } 101 return (neg ? '-' : '') + self.options.prefix + x1 + x2 + self.options.suffix; 102 } 103 // Robert Penner's easeOutExpo 104 function easeOutExpo(t, b, c, d) { 105 return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b; 106 } 107 function ensureNumber(n) { 108 return (typeof n === 'number' && !isNaN(n)); 109 } 110 111 self.initialize = function() { 112 if (self.initialized) return true; 113 114 self.error = ''; 115 self.d = (typeof target === 'string') ? document.getElementById(target) : target; 116 if (!self.d) { 117 self.error = '[CountUp] target is null or undefined' 118 return false; 119 } 120 self.startVal = Number(startVal); 121 self.endVal = Number(endVal); 122 // error checks 123 if (ensureNumber(self.startVal) && ensureNumber(self.endVal)) { 124 self.decimals = Math.max(0, decimals || 0); 125 self.dec = Math.pow(10, self.decimals); 126 self.duration = Number(duration) * 1000 || 2000; 127 self.countDown = (self.startVal > self.endVal); 128 self.frameVal = self.startVal; 129 self.initialized = true; 130 return true; 131 } 132 else { 133 self.error = '[CountUp] startVal ('+startVal+') or endVal ('+endVal+') is not a number'; 134 return false;
135 } 136 }; 137 138 // Print value to target 139 self.printValue = function(value) { 140 var result = self.options.formattingFn(value); 141 142 if (self.d.tagName === 'INPUT') { 143 this.d.value = result; 144 } 145 else if (self.d.tagName === 'text' || self.d.tagName === 'tspan') { 146 this.d.textContent = result; 147 } 148 else { 149 this.d.innerHTML = result; 150 } 151 }; 152 153 self.count = function(timestamp) { 154 155 if (!self.startTime) { self.startTime = timestamp; } 156 157 self.timestamp = timestamp; 158 var progress = timestamp - self.startTime; 159 self.remaining = self.duration - progress; 160 161 // to ease or not to ease 162 if (self.options.useEasing) { 163 if (self.countDown) { 164 self.frameVal = self.startVal - self.options.easingFn(progress, 0, self.startVal - self.endVal, self.duration); 165 } else { 166 self.frameVal = self.options.easingFn(progress, self.startVal, self.endVal - self.startVal, self.duration); 167 } 168 } else { 169 if (self.countDown) { 170 self.frameVal = self.startVal - ((self.startVal - self.endVal) * (progress / self.duration)); 171 } else { 172 self.frameVal = self.startVal + (self.endVal - self.startVal) * (progress / self.duration); 173 } 174 } 175 176 // don't go past endVal since progress can exceed duration in the last frame 177 if (self.countDown) { 178 self.frameVal = (self.frameVal < self.endVal) ? self.endVal : self.frameVal; 179 } else { 180 self.frameVal = (self.frameVal > self.endVal) ? self.endVal : self.frameVal; 181 } 182 183 // decimal 184 self.frameVal = Math.round(self.frameVal*self.dec)/self.dec; 185 186 // format and print value 187 self.printValue(self.frameVal); 188 189 // whether to continue 190 if (progress < self.duration) { 191 self.rAF = requestAnimationFrame(self.count); 192 } else { 193 if (self.callback) self.callback(); 194 } 195 }; 196 // start your animation 197 self.start = function(callback) { 198 if (!self.initialize()) return; 199 self.callback = callback; 200 self.rAF = requestAnimationFrame(self.count); 201 }; 202 // toggles pause/resume animation 203 self.pauseResume = function() { 204 if (!self.paused) { 205 self.paused = true; 206 cancelAnimationFrame(self.rAF); 207 } else { 208 self.paused = false; 209 delete self.startTime; 210 self.duration = self.remaining; 211 self.startVal = self.frameVal; 212 requestAnimationFrame(self.count); 213 } 214 }; 215 // reset to startVal so animation can be run again 216 self.reset = function() { 217 self.paused = false; 218 delete self.startTime; 219 self.initialized = false; 220 if (self.initialize()) { 221 cancelAnimationFrame(self.rAF); 222 self.printValue(self.startVal); 223 } 224 }; 225 // pass a new endVal and start animation 226 self.update = function (newEndVal) { 227 if (!self.initialize()) return; 228 newEndVal = Number(newEndVal); 229 if (!ensureNumber(newEndVal)) { 230 self.error = '[CountUp] update() - new endVal is not a number: '+newEndVal; 231 return; 232 } 233 self.error = ''; 234 if (newEndVal === self.frameVal) return; 235 cancelAnimationFrame(self.rAF); 236 self.paused = false; 237 delete self.startTime; 238 self.startVal = self.frameVal; 239 self.endVal = newEndVal; 240 self.countDown = (self.startVal > self.endVal); 241 self.rAF = requestAnimationFrame(self.count); 242 }; 243 244 // format startVal on initialization 245 if (self.initialize()) self.printValue(self.startVal); 246};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.