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