Tween.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. export class TweenManager {
  2. constructor() {
  3. this.activeTweens = [];
  4. this.tweenIdIndex = 0;
  5. }
  6. add(tween) {
  7. tween.setId(this.tweenIdIndex++)
  8. this.activeTweens.push(tween);
  9. return tween.getId();
  10. }
  11. remove(tween) {
  12. this.activeTweens.splice(this.activeTweens.findIndex(t => t == tween), 1);
  13. }
  14. cancel(tweenId) {
  15. let tweenIndex = this.activeTweens.findIndex(t => t.getId() == tweenId);
  16. if(tweenIndex != -1) {
  17. this.activeTweens.splice(tweenIndex, 1)
  18. }
  19. }
  20. update() {
  21. let completedTweens = [];
  22. for(let i = 0; i < this.activeTweens.length; i++) {
  23. let tween = this.activeTweens[i];
  24. tween.update();
  25. if(tween.isComplete()) {
  26. completedTweens.push(tween);
  27. }
  28. }
  29. for(let i = 0; i < completedTweens.length; i++) {
  30. let tween = completedTweens[i];
  31. tween.onFinish();
  32. this.remove(tween);
  33. }
  34. }
  35. }
  36. export class Tween {
  37. constructor(objToTween, targetProperties, duration, easing = Easing.Linear.EaseNone, onFinish = () => {}) {
  38. this.objectToTween = objToTween;
  39. this.startProperties = {};
  40. this.targetProperties = targetProperties;
  41. this.saveInitialValues(this.startProperties, objToTween, targetProperties);
  42. this.startTime = new Date().getTime()
  43. this.endTime = this.startTime + duration
  44. this.easing = easing;
  45. this.onFinish = onFinish;
  46. this.id = -1;
  47. }
  48. saveInitialValues(propertiesObj, obj, targetProperties) {
  49. for(let property in targetProperties) {
  50. let startValue = obj[property];
  51. if(typeof startValue == "object") {
  52. propertiesObj[property] = {};
  53. this.saveInitialValues(propertiesObj[property], obj[property], targetProperties[property]);
  54. continue;
  55. }
  56. propertiesObj[property] = startValue;
  57. }
  58. }
  59. update() {
  60. let currentTime = new Date().getTime();
  61. let runTime = currentTime - this.startTime;
  62. let duration = this.endTime - this.startTime;
  63. let percentageComplete = Math.min(1, runTime / duration);
  64. let valueToUpdate = this.easing(percentageComplete);
  65. this.updateProperties(this.objectToTween, this.startProperties, this.targetProperties, valueToUpdate);
  66. }
  67. updateProperties(obj, objStart, objTarget, valueToUpdate) {
  68. for(let property in objStart) {
  69. let startValue = objStart[property];
  70. if(typeof startValue == "object") {
  71. this.updateProperties(obj[property], objStart[property], objTarget[property], valueToUpdate);
  72. continue;
  73. }
  74. let endValue = objTarget[property];
  75. let delta = endValue - startValue;
  76. obj[property] = startValue + (delta * valueToUpdate);
  77. }
  78. }
  79. setId(newId){
  80. this.id = newId
  81. }
  82. getId() {
  83. return this.id
  84. }
  85. isComplete() {
  86. return this.endTime <= new Date().getTime()
  87. }
  88. }
  89. export class Easing {}
  90. Easing.Linear = {};
  91. Easing.Linear.EaseNone = (percentageComplete) => percentageComplete;
  92. Easing.Quadratic = {};
  93. Easing.Quadratic.EaseIn = (percentageComplete) => percentageComplete * percentageComplete;
  94. Easing.Quadratic.EaseOut = (percentageComplete) => -percentageComplete * ( percentageComplete - 2 );
  95. Easing.Quadratic.EaseInOut = (percentageComplete) => {
  96. if ( ( percentageComplete *= 2 ) < 1 ) return 0.5 * percentageComplete * percentageComplete;
  97. return - 0.5 * ( --percentageComplete * ( percentageComplete - 2 ) - 1 );
  98. };
  99. Easing.Cubic = {};
  100. Easing.Cubic.EaseIn = (percentageComplete) => percentageComplete * percentageComplete * percentageComplete;
  101. Easing.Cubic.EaseOut = (percentageComplete) => --percentageComplete * percentageComplete * percentageComplete + 1;
  102. Easing.Cubic.EaseInOut = (percentageComplete) => {
  103. if ( ( percentageComplete *= 2 ) < 1 ) return 0.5 * percentageComplete * percentageComplete * percentageComplete;
  104. return 0.5 * ( ( percentageComplete -= 2 ) * percentageComplete * percentageComplete + 2 );
  105. };
  106. Easing.Quartic = {};
  107. Easing.Quartic.EaseIn = (percentageComplete) => percentageComplete * percentageComplete * percentageComplete * percentageComplete;
  108. Easing.Quartic.EaseOut = (percentageComplete) => -( --percentageComplete * percentageComplete * percentageComplete * percentageComplete - 1 );
  109. Easing.Quartic.EaseInOut = (percentageComplete) => {
  110. if ( ( percentageComplete *= 2 ) < 1) return 0.5 * percentageComplete * percentageComplete * percentageComplete * percentageComplete;
  111. return - 0.5 * ( ( percentageComplete -= 2 ) * percentageComplete * percentageComplete * percentageComplete - 2 );
  112. };
  113. Easing.Quintic = {};
  114. Easing.Quintic.EaseIn = (percentageComplete) => percentageComplete * percentageComplete * percentageComplete * percentageComplete * percentageComplete;
  115. Easing.Quintic.EaseOut = (percentageComplete) => ( percentageComplete = percentageComplete - 1 ) * percentageComplete * percentageComplete * percentageComplete * percentageComplete + 1;
  116. Easing.Quintic.EaseInOut = (percentageComplete) => {
  117. if ( ( percentageComplete *= 2 ) < 1 ) return 0.5 * percentageComplete * percentageComplete * percentageComplete * percentageComplete * percentageComplete;
  118. return 0.5 * ( ( percentageComplete -= 2 ) * percentageComplete * percentageComplete * percentageComplete * percentageComplete + 2 );
  119. };
  120. Easing.Sinusoidal = {};
  121. Easing.Sinusoidal.EaseIn = (percentageComplete) => -Math.cos( percentageComplete * Math.PI / 2 ) + 1;
  122. Easing.Sinusoidal.EaseOut = (percentageComplete) => Math.sin( percentageComplete * Math.PI / 2 );
  123. Easing.Sinusoidal.EaseInOut = (percentageComplete) => -0.5 * ( Math.cos( Math.PI * percentageComplete ) - 1 );
  124. Easing.Exponential = {};
  125. Easing.Exponential.EaseIn = (percentageComplete) => {
  126. return percentageComplete == 0 ? 0 : Math.pow( 2, 10 * ( percentageComplete - 1 ) );
  127. };
  128. Easing.Exponential.EaseOut = (percentageComplete) => {
  129. return percentageComplete == 1 ? 1 : - Math.pow( 2, - 10 * percentageComplete ) + 1;
  130. };
  131. Easing.Exponential.EaseInOut = (percentageComplete) => {
  132. if ( percentageComplete == 0 ) return 0;
  133. if ( percentageComplete == 1 ) return 1;
  134. if ( ( percentageComplete *= 2 ) < 1 ) return 0.5 * Math.pow( 2, 10 * ( percentageComplete - 1 ) );
  135. return 0.5 * ( - Math.pow( 2, - 10 * ( percentageComplete - 1 ) ) + 2 );
  136. };
  137. Easing.Circular = {};
  138. Easing.Circular.EaseIn = (percentageComplete) => -(Math.sqrt( 1 - percentageComplete * percentageComplete ) - 1);
  139. Easing.Circular.EaseOut = (percentageComplete) => Math.sqrt( 1 - (--percentageComplete * percentageComplete) );
  140. Easing.Circular.EaseInOut = (percentageComplete) => {
  141. if ( ( percentageComplete /= 0.5 ) < 1) return - 0.5 * ( Math.sqrt( 1 - percentageComplete * percentageComplete) - 1);
  142. return 0.5 * ( Math.sqrt( 1 - ( percentageComplete -= 2) * percentageComplete) + 1);
  143. };
  144. Easing.Elastic = {};
  145. Easing.Elastic.EaseIn = (percentageComplete) => {
  146. var s, a = 0.1, p = 0.4;
  147. if ( percentageComplete == 0 ) return 0; if ( percentageComplete == 1 ) return 1; if ( !p ) p = 0.3;
  148. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  149. else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
  150. return - ( a * Math.pow( 2, 10 * ( percentageComplete -= 1 ) ) * Math.sin( ( percentageComplete - s ) * ( 2 * Math.PI ) / p ) );
  151. };
  152. Easing.Elastic.EaseOut = (percentageComplete) => {
  153. var s, a = 0.1, p = 0.4;
  154. if ( percentageComplete == 0 ) return 0; if ( percentageComplete == 1 ) return 1; if ( !p ) p = 0.3;
  155. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  156. else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
  157. return ( a * Math.pow( 2, - 10 * percentageComplete) * Math.sin( ( percentageComplete - s ) * ( 2 * Math.PI ) / p ) + 1 );
  158. };
  159. Easing.Elastic.EaseInOut = (percentageComplete) => {
  160. var s, a = 0.1, p = 0.4;
  161. if ( percentageComplete == 0 ) return 0; if ( percentageComplete == 1 ) return 1; if ( !p ) p = 0.3;
  162. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  163. else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
  164. if ( ( percentageComplete *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( percentageComplete -= 1 ) ) * Math.sin( ( percentageComplete - s ) * ( 2 * Math.PI ) / p ) );
  165. return a * Math.pow( 2, -10 * ( percentageComplete -= 1 ) ) * Math.sin( ( percentageComplete - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1;
  166. };
  167. Easing.Back = {};
  168. Easing.Back.EaseIn = (percentageComplete) => {
  169. var s = 1.70158;
  170. return percentageComplete * percentageComplete * ( ( s + 1 ) * percentageComplete - s );
  171. };
  172. Easing.Back.EaseOut = (percentageComplete) => {
  173. var s = 1.70158;
  174. return ( percentageComplete = percentageComplete - 1 ) * percentageComplete * ( ( s + 1 ) * percentageComplete + s ) + 1;
  175. };
  176. Easing.Back.EaseInOut = (percentageComplete) => {
  177. var s = 1.70158 * 1.525;
  178. if ( ( percentageComplete *= 2 ) < 1 ) return 0.5 * ( percentageComplete * percentageComplete * ( ( s + 1 ) * percentageComplete - s ) );
  179. return 0.5 * ( ( percentageComplete -= 2 ) * percentageComplete * ( ( s + 1 ) * percentageComplete + s ) + 2 );
  180. };
  181. Easing.Bounce = {};
  182. Easing.Bounce.EaseIn = (percentageComplete) => 1 - Easing.Bounce.EaseOut( 1 - percentageComplete );
  183. Easing.Bounce.EaseOut = (percentageComplete) => {
  184. if ( ( percentageComplete /= 1 ) < ( 1 / 2.75 ) ) {
  185. return 7.5625 * percentageComplete * percentageComplete;
  186. } else if ( percentageComplete < ( 2 / 2.75 ) ) {
  187. return 7.5625 * ( percentageComplete -= ( 1.5 / 2.75 ) ) * percentageComplete + 0.75;
  188. } else if ( percentageComplete < ( 2.5 / 2.75 ) ) {
  189. return 7.5625 * ( percentageComplete -= ( 2.25 / 2.75 ) ) * percentageComplete + 0.9375;
  190. } else {
  191. return 7.5625 * ( percentageComplete -= ( 2.625 / 2.75 ) ) * percentageComplete + 0.984375;
  192. }
  193. };
  194. Easing.Bounce.EaseInOut = (percentageComplete) => {
  195. if ( percentageComplete < 0.5 ) return Easing.Bounce.EaseIn( percentageComplete * 2 ) * 0.5;
  196. return Easing.Bounce.EaseOut( percentageComplete * 2 - 1 ) * 0.5 + 0.5;
  197. }