UNPKG

7.45 kBJavaScriptView Raw
1
2(function(root, factory) {
3 if (typeof define === 'function' && define.amd) {
4 define(factory);
5 } else if (typeof exports === 'object') {
6 module.exports = factory(require, exports, module);
7 } else {
8 root.CountUp = factory();
9 }
10}(this, function(require, exports, module) {
11
12/*
13
14 countUp.js
15 by @inorganik
16
17*/
18
19// target = id of html element or var of previously selected html element where counting occurs
20// startVal = the value you want to begin at
21// endVal = the value you want to arrive at
22// decimals = number of decimal places, default 0
23// duration = duration of animation in seconds, default 2
24// options = optional object of options (see below)
25
26var CountUp = function(target, startVal, endVal, decimals, duration, options) {
27
28 // make sure requestAnimationFrame and cancelAnimationFrame are defined
29 // polyfill for browsers without native support
30 // by Opera engineer Erik Möller
31 var lastTime = 0;
32 var vendors = ['webkit', 'moz', 'ms', 'o'];
33 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
34 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
35 window.cancelAnimationFrame =
36 window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
37 }
38 if (!window.requestAnimationFrame) {
39 window.requestAnimationFrame = function(callback, element) {
40 var currTime = new Date().getTime();
41 var timeToCall = Math.max(0, 16 - (currTime - lastTime));
42 var id = window.setTimeout(function() { callback(currTime + timeToCall); },
43 timeToCall);
44 lastTime = currTime + timeToCall;
45 return id;
46 };
47 }
48 if (!window.cancelAnimationFrame) {
49 window.cancelAnimationFrame = function(id) {
50 clearTimeout(id);
51 };
52 }
53
54 var self = this;
55
56 // default options
57 self.options = {
58 useEasing : true, // toggle easing
59 useGrouping : true, // 1,000,000 vs 1000000
60 separator : ',', // character to use as a separator
61 decimal : '.', // character to use as a decimal
62 easingFn: null, // optional custom easing closure function, default is Robert Penner's easeOutExpo
63 formattingFn: null // optional custom formatting function, default is self.formatNumber below
64 };
65 // extend default options with passed options object
66 for (var key in options) {
67 if (options.hasOwnProperty(key)) {
68 self.options[key] = options[key];
69 }
70 }
71 if (self.options.separator === '') { self.options.useGrouping = false; }
72 if (!self.options.prefix) self.options.prefix = '';
73 if (!self.options.suffix) self.options.suffix = '';
74
75 self.d = (typeof target === 'string') ? document.getElementById(target) : target;
76 self.startVal = Number(startVal);
77 self.endVal = Number(endVal);
78 self.countDown = (self.startVal > self.endVal);
79 self.frameVal = self.startVal;
80 self.decimals = Math.max(0, decimals || 0);
81 self.dec = Math.pow(10, self.decimals);
82 self.duration = Number(duration) * 1000 || 2000;
83
84 self.formatNumber = function(nStr) {
85 nStr = nStr.toFixed(self.decimals);
86 nStr += '';
87 var x, x1, x2, rgx;
88 x = nStr.split('.');
89 x1 = x[0];
90 x2 = x.length > 1 ? self.options.decimal + x[1] : '';
91 rgx = /(\d+)(\d{3})/;
92 if (self.options.useGrouping) {
93 while (rgx.test(x1)) {
94 x1 = x1.replace(rgx, '$1' + self.options.separator + '$2');
95 }
96 }
97 return self.options.prefix + x1 + x2 + self.options.suffix;
98 };
99 // Robert Penner's easeOutExpo
100 self.easeOutExpo = function(t, b, c, d) {
101 return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
102 };
103
104 self.easingFn = self.options.easingFn ? self.options.easingFn : self.easeOutExpo;
105 self.formattingFn = self.options.formattingFn ? self.options.formattingFn : self.formatNumber;
106
107 self.version = function () { return '1.7.1'; };
108
109 // Print value to target
110 self.printValue = function(value) {
111 var result = self.formattingFn(value);
112
113 if (self.d.tagName === 'INPUT') {
114 this.d.value = result;
115 }
116 else if (self.d.tagName === 'text' || self.d.tagName === 'tspan') {
117 this.d.textContent = result;
118 }
119 else {
120 this.d.innerHTML = result;
121 }
122 };
123
124 self.count = function(timestamp) {
125
126 if (!self.startTime) { self.startTime = timestamp; }
127
128 self.timestamp = timestamp;
129 var progress = timestamp - self.startTime;
130 self.remaining = self.duration - progress;
131
132 // to ease or not to ease
133 if (self.options.useEasing) {
134 if (self.countDown) {
135 self.frameVal = self.startVal - self.easingFn(progress, 0, self.startVal - self.endVal, self.duration);
136 } else {
137 self.frameVal = self.easingFn(progress, self.startVal, self.endVal - self.startVal, self.duration);
138 }
139 } else {
140 if (self.countDown) {
141 self.frameVal = self.startVal - ((self.startVal - self.endVal) * (progress / self.duration));
142 } else {
143 self.frameVal = self.startVal + (self.endVal - self.startVal) * (progress / self.duration);
144 }
145 }
146
147 // don't go past endVal since progress can exceed duration in the last frame
148 if (self.countDown) {
149 self.frameVal = (self.frameVal < self.endVal) ? self.endVal : self.frameVal;
150 } else {
151 self.frameVal = (self.frameVal > self.endVal) ? self.endVal : self.frameVal;
152 }
153
154 // decimal
155 self.frameVal = Math.round(self.frameVal*self.dec)/self.dec;
156
157 // format and print value
158 self.printValue(self.frameVal);
159
160 // whether to continue
161 if (progress < self.duration) {
162 self.rAF = requestAnimationFrame(self.count);
163 } else {
164 if (self.callback) { self.callback(); }
165 }
166 };
167 // start your animation
168 self.start = function(callback) {
169 self.callback = callback;
170 self.rAF = requestAnimationFrame(self.count);
171 return false;
172 };
173 // toggles pause/resume animation
174 self.pauseResume = function() {
175 if (!self.paused) {
176 self.paused = true;
177 cancelAnimationFrame(self.rAF);
178 } else {
179 self.paused = false;
180 delete self.startTime;
181 self.duration = self.remaining;
182 self.startVal = self.frameVal;
183 requestAnimationFrame(self.count);
184 }
185 };
186 // reset to startVal so animation can be run again
187 self.reset = function() {
188 self.paused = false;
189 delete self.startTime;
190 self.startVal = startVal;
191 cancelAnimationFrame(self.rAF);
192 self.printValue(self.startVal);
193 };
194 // pass a new endVal and start animation
195 self.update = function (newEndVal) {
196 cancelAnimationFrame(self.rAF);
197 self.paused = false;
198 delete self.startTime;
199 self.startVal = self.frameVal;
200 self.endVal = Number(newEndVal);
201 self.countDown = (self.startVal > self.endVal);
202 self.rAF = requestAnimationFrame(self.count);
203 };
204
205 // format startVal on initialization
206 self.printValue(self.startVal);
207};
208
209return CountUp;
210
211}));