timer.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. define(function(require, exports, module) {
  2. "use strict";
  3. var Util = require('./util');
  4. var Base = require('./base');
  5. var Easing = require('./easing');
  6. var RAF = window.requestAnimationFrame ||
  7. window.webkitRequestAnimationFrame ||
  8. window.mozRequestAnimationFrame ||
  9. window.oRequestAnimationFrame ||
  10. window.msRequestAnimationFrame ||
  11. function(callback) {
  12. window.setTimeout(callback, 1000 / 60);
  13. };
  14. var vendors = ['webkit', 'moz', 'ms', 'o'];
  15. var cancelRAF = window.cancelAnimationFrame;
  16. if (!cancelRAF) {
  17. for (var i = 0; i < vendors.length; i++) {
  18. if (window[vendors[i] + 'CancelAnimationFrame'] || window[vendors[i] + 'CancelRequestAnimationFrame']) {
  19. cancelRAF = window[vendors[i] + 'CancelAnimationFrame'] || window[vendors[i] + 'CancelRequestAnimationFrame'];
  20. }
  21. }
  22. }
  23. cancelRAF = cancelRAF || window.clearTimeout;
  24. function Bezier(x1, y1, x2, y2, epsilon) {
  25. var curveX = function(t) {
  26. var v = 1 - t;
  27. return 3 * v * v * t * x1 + 3 * v * t * t * x2 + t * t * t;
  28. };
  29. var curveY = function(t) {
  30. var v = 1 - t;
  31. return 3 * v * v * t * y1 + 3 * v * t * t * y2 + t * t * t;
  32. };
  33. var derivativeCurveX = function(t) {
  34. var v = 1 - t;
  35. return 3 * (2 * (t - 1) * t + v * v) * x1 + 3 * (-t * t * t + 2 * v * t) * x2;
  36. };
  37. return function(t) {
  38. var x = t,
  39. t0, t1, t2, x2, d2, i;
  40. // First try a few iterations of Newton's method -- normally very fast.
  41. for (t2 = x, i = 0; i < 8; i++) {
  42. x2 = curveX(t2) - x;
  43. if (Math.abs(x2) < epsilon) return curveY(t2);
  44. d2 = derivativeCurveX(t2);
  45. if (Math.abs(d2) < 1e-6) break;
  46. t2 = t2 - x2 / d2;
  47. }
  48. t0 = 0, t1 = 1, t2 = x;
  49. if (t2 < t0) return curveY(t0);
  50. if (t2 > t1) return curveY(t1);
  51. // Fallback to the bisection method for reliability.
  52. while (t0 < t1) {
  53. x2 = curveX(t2);
  54. if (Math.abs(x2 - x) < epsilon) return curveY(t2);
  55. if (x > x2) t0 = t2;
  56. else t1 = t2;
  57. t2 = (t1 - t0) * .5 + t0;
  58. }
  59. // Failure
  60. return curveY(t2);
  61. };
  62. };
  63. function Timer(cfg) {
  64. var self = this;
  65. self.cfg = Util.mix({
  66. easing: "linear"
  67. }, cfg)
  68. }
  69. Timer.MIN_DURATION = 1;
  70. Util.extend(Timer, Base, {
  71. reset: function(cfg) {
  72. var self = this;
  73. Util.mix(self.cfg, cfg);
  74. self.isfinished = false;
  75. self.percent = 0;
  76. self._stop = null;
  77. },
  78. run: function() {
  79. var self = this;
  80. var duration = self.cfg.duration;
  81. if (duration <= Timer.MIN_DURATION) {
  82. self.isfinished = true;
  83. self.trigger("run", {
  84. percent: 1
  85. });
  86. self.trigger("end", {
  87. percent: 1
  88. });
  89. }
  90. if (self.isfinished) return;
  91. self._hasFinishedPercent = self._stop && self._stop.percent || 0;
  92. self._stop = null;
  93. self.start = Date.now();
  94. self.percent = 0;
  95. // epsilon determines the precision of the solved values
  96. var epsilon = (1000 / 60 / duration) / 4;
  97. var b = Easing[self.cfg.easing];
  98. self.easingFn = Bezier(b[0], b[1], b[2], b[3], epsilon);
  99. self._run();
  100. },
  101. _run: function() {
  102. var self = this;
  103. cancelRAF(self._raf);
  104. self._raf = RAF(function() {
  105. self.now = Date.now();
  106. self.duration = self.now - self.start >= self.cfg.duration ? self.cfg.duration : self.now - self.start;
  107. self.progress = self.easingFn(self.duration / self.cfg.duration);
  108. self.percent = self.duration / self.cfg.duration + self._hasFinishedPercent;
  109. if (self.percent >= 1 || self._stop) {
  110. self.percent = self._stop && self._stop.percent ? self._stop.percent : 1;
  111. self.duration = self._stop && self._stop.duration ? self._stop.duration : self.duration;
  112. var param = {
  113. percent: self.percent
  114. };
  115. self.trigger("stop", param);
  116. if (self.percent >= 1) {
  117. self.isfinished = true;
  118. self.trigger("end", {
  119. percent: 1
  120. });
  121. }
  122. return;
  123. }
  124. self.trigger("run", {
  125. percent: self.progress,
  126. originPercent:self.percent
  127. });
  128. self._run();
  129. })
  130. },
  131. stop: function() {
  132. var self = this;
  133. self._stop = {
  134. percent: self.percent,
  135. now: self.now
  136. };
  137. cancelRAF(self._raf)
  138. }
  139. });
  140. if (typeof module == 'object' && module.exports) {
  141. module.exports = Timer;
  142. }
  143. /** ignored by jsdoc **/
  144. else {
  145. return Timer;
  146. }
  147. });