index.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // @ts-nocheck
  2. const TICK = Symbol('tick');
  3. const TICK_HANDLER = Symbol('tick-handler');
  4. const ANIMATIONS = Symbol('animations');
  5. const START_TIMES = Symbol('start-times');
  6. const PAUSE_START = Symbol('pause-start');
  7. const PAUSE_TIME = Symbol('pause-time');
  8. const _raf = typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame : function(cb: Function) {return setTimeout(cb, 1000/60)}
  9. const _caf = typeof cancelAnimationFrame !== 'undefined' ? cancelAnimationFrame: function(id: any) {clearTimeout(id)}
  10. export class Timeline {
  11. state: string
  12. constructor() {
  13. this.state = 'Initiated';
  14. this[ANIMATIONS] = new Set();
  15. this[START_TIMES] = new Map();
  16. }
  17. start() {
  18. if (!(this.state === 'Initiated')) return;
  19. this.state = 'Started';
  20. let startTime = Date.now();
  21. this[PAUSE_TIME] = 0;
  22. this[TICK] = () => {
  23. let now = Date.now();
  24. for (let animation of this[ANIMATIONS]) {
  25. let t: number;
  26. if (this[START_TIMES].get(animation) < startTime) {
  27. t = now - startTime - animation.delay - this[PAUSE_TIME];
  28. } else {
  29. t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
  30. }
  31. if (t > animation.duration) {
  32. this[ANIMATIONS].delete(animation);
  33. t = animation.duration;
  34. }
  35. if (t > 0) animation.run(t);
  36. }
  37. this[TICK_HANDLER] = _raf(this[TICK]);
  38. };
  39. this[TICK]();
  40. }
  41. pause() {
  42. if (!(this.state === 'Started')) return;
  43. this.state = 'Paused';
  44. this[PAUSE_START] = Date.now();
  45. _caf(this[TICK_HANDLER]);
  46. }
  47. resume() {
  48. if (!(this.state === 'Paused')) return;
  49. this.state = 'Started';
  50. this[PAUSE_TIME] += Date.now() - this[PAUSE_START];
  51. this[TICK]();
  52. }
  53. reset() {
  54. this.pause();
  55. this.state = 'Initiated';
  56. this[PAUSE_TIME] = 0;
  57. this[PAUSE_START] = 0;
  58. this[ANIMATIONS] = new Set();
  59. this[START_TIMES] = new Map();
  60. this[TICK_HANDLER] = null;
  61. }
  62. add(animation: any, startTime?: number) {
  63. if (arguments.length < 2) startTime = Date.now();
  64. this[ANIMATIONS].add(animation);
  65. this[START_TIMES].set(animation, startTime);
  66. }
  67. }
  68. export class Animation {
  69. startValue: number
  70. endValue: number
  71. duration: number
  72. timingFunction: (t: number) => number
  73. delay: number
  74. template: (t: number) => void
  75. constructor(startValue: number, endValue: number, duration: number, delay: number, timingFunction: (t: number) => number, template: (v: number) => void) {
  76. timingFunction = timingFunction || (v => v);
  77. template = template || (v => v);
  78. this.startValue = startValue;
  79. this.endValue = endValue;
  80. this.duration = duration;
  81. this.timingFunction = timingFunction;
  82. this.delay = delay;
  83. this.template = template;
  84. }
  85. run(time: number) {
  86. let range = this.endValue - this.startValue;
  87. let progress = this.timingFunction(time / this.duration);
  88. this.template(this.startValue + range * progress)
  89. }
  90. }