Tween.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. export class TweenManager {
  2. constructor() {
  3. this.clear()
  4. }
  5. add(tween) {
  6. tween.setId(this.tweenIdIndex++)
  7. this.activeTweens.push(tween);
  8. return tween.getId();
  9. }
  10. remove(tween) {
  11. this.activeTweens.splice(this.activeTweens.findIndex(t => t == tween), 1);
  12. }
  13. cancel(tweenId) {
  14. let tweenIndex = this.activeTweens.findIndex(t => t.getId() == tweenId);
  15. if(tweenIndex != -1) {
  16. this.activeTweens.splice(tweenIndex, 1)
  17. }
  18. }
  19. update() {
  20. let completedTweens = [];
  21. for(let i = 0; i < this.activeTweens.length; i++) {
  22. let tween = this.activeTweens[i];
  23. tween.update();
  24. if(tween.isComplete()) {
  25. completedTweens.push(tween);
  26. }
  27. }
  28. for(let i = 0; i < completedTweens.length; i++) {
  29. let tween = completedTweens[i];
  30. tween.onFinish();
  31. this.remove(tween);
  32. }
  33. }
  34. clear() {
  35. this.activeTweens = [];
  36. this.tweenIdIndex = 0;
  37. }
  38. }
  39. export class Tween {
  40. constructor(objToTween, targetProperties, duration, easing = Easing.Linear.EaseNone, onFinish = () => {}) {
  41. this.objectToTween = objToTween;
  42. this.startProperties = {};
  43. this.targetProperties = targetProperties;
  44. this.saveInitialValues(this.startProperties, objToTween, targetProperties);
  45. this.startTime = new Date().getTime()
  46. this.endTime = this.startTime + duration
  47. this.easing = easing;
  48. this.onFinish = onFinish;
  49. this.id = -1;
  50. }
  51. saveInitialValues(propertiesObj, obj, targetProperties) {
  52. for(let property in targetProperties) {
  53. let startValue = obj[property];
  54. if(typeof startValue == "object") {
  55. propertiesObj[property] = {};
  56. this.saveInitialValues(propertiesObj[property], obj[property], targetProperties[property]);
  57. continue;
  58. }
  59. propertiesObj[property] = startValue;
  60. }
  61. }
  62. update() {
  63. let currentTime = new Date().getTime();
  64. let runTime = currentTime - this.startTime;
  65. let duration = this.endTime - this.startTime;
  66. let percentageComplete = Math.min(1, runTime / duration);
  67. let valueToUpdate = this.easing(percentageComplete);
  68. this.updateProperties(this.objectToTween, this.startProperties, this.targetProperties, valueToUpdate);
  69. }
  70. updateProperties(obj, objStart, objTarget, valueToUpdate) {
  71. for(let property in objStart) {
  72. let startValue = objStart[property];
  73. if(typeof startValue == "object") {
  74. this.updateProperties(obj[property], objStart[property], objTarget[property], valueToUpdate);
  75. continue;
  76. }
  77. let endValue = objTarget[property];
  78. let delta = endValue - startValue;
  79. obj[property] = startValue + (delta * valueToUpdate);
  80. }
  81. }
  82. setId(newId){
  83. this.id = newId
  84. }
  85. getId() {
  86. return this.id
  87. }
  88. isComplete() {
  89. return this.endTime <= new Date().getTime()
  90. }
  91. }
  92. export class Easing {}
  93. Easing.Linear = {};
  94. Easing.Linear.EaseNone = (percentageComplete) => percentageComplete;
  95. Easing.Quadratic = {};
  96. Easing.Quadratic.EaseIn = (percentageComplete) => percentageComplete * percentageComplete;
  97. Easing.Quadratic.EaseOut = (percentageComplete) => -percentageComplete * ( percentageComplete - 2 );
  98. Easing.Quadratic.EaseInOut = (percentageComplete) => {
  99. if ( ( percentageComplete *= 2 ) < 1 ) return 0.5 * percentageComplete * percentageComplete;
  100. return - 0.5 * ( --percentageComplete * ( percentageComplete - 2 ) - 1 );
  101. };
  102. Easing.Elastic = {};
  103. Easing.Elastic.EaseIn = (percentageComplete) => {
  104. var s, a = 0.1, p = 0.4;
  105. if ( percentageComplete == 0 ) return 0; if ( percentageComplete == 1 ) return 1; if ( !p ) p = 0.3;
  106. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  107. else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
  108. return - ( a * Math.pow( 2, 10 * ( percentageComplete -= 1 ) ) * Math.sin( ( percentageComplete - s ) * ( 2 * Math.PI ) / p ) );
  109. };
  110. Easing.Elastic.EaseOut = (percentageComplete) => {
  111. var s, a = 0.1, p = 0.4;
  112. if ( percentageComplete == 0 ) return 0; if ( percentageComplete == 1 ) return 1; if ( !p ) p = 0.3;
  113. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  114. else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
  115. return ( a * Math.pow( 2, - 10 * percentageComplete) * Math.sin( ( percentageComplete - s ) * ( 2 * Math.PI ) / p ) + 1 );
  116. };
  117. Easing.Elastic.EaseInOut = (percentageComplete) => {
  118. var s, a = 0.1, p = 0.4;
  119. if ( percentageComplete == 0 ) return 0; if ( percentageComplete == 1 ) return 1; if ( !p ) p = 0.3;
  120. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  121. else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
  122. if ( ( percentageComplete *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( percentageComplete -= 1 ) ) * Math.sin( ( percentageComplete - s ) * ( 2 * Math.PI ) / p ) );
  123. return a * Math.pow( 2, -10 * ( percentageComplete -= 1 ) ) * Math.sin( ( percentageComplete - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1;
  124. };