countUp.js 7.3 KB

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