web
9 小时以前 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
// @ts-nocheck
import {raf, cancelRaf} from '../raf'
export class Timeline {
    state : string
    animations : Set<Animation> = new Set<Animation>()
    delAnimations : Animation[] = []
    startTimes : Map<Animation, number> = new Map<Animation, number>()
    pauseTime : number = 0
    pauseStart : number = Date.now()
    tickHandler : number = 0
    tickHandlers : number[] = []
    tick : (() => void) | null = null
    constructor() {
        this.state = 'Initiated';
    }
    start() {
        if (!(this.state === 'Initiated')) return;
        this.state = 'Started';
 
        let startTime = Date.now();
        this.pauseTime = 0;
        this.tick = () => {
            let now = Date.now();
            this.animations.forEach((animation : Animation) => {
                let t:number;
                const ani = this.startTimes.get(animation)
                if (ani == null) return
                if (ani < startTime) {
                    t = now - startTime - animation.delay - this.pauseTime;
                } else {
                    t = now - ani - animation.delay - this.pauseTime;
                }
                if (t > animation.duration) {
                    this.delAnimations.push(animation)
                    // 不能在 foreach 里面 对 集合进行删除操作
                    // this.animations.delete(animation);
                    t = animation.duration;
                }
                if (t > 0) animation.run(t);
            })
            // 不能在 foreach 里面 对 集合进行删除操作
            while (this.delAnimations.length > 0) {
                const animation = this.delAnimations.pop();
                if (animation == null) return
                this.animations.delete(animation);
            }
            clearTimeout(this.tickHandler);
            if (this.state != 'Started') return
            // this.tickHandler = setTimeout(() => {
            //     this.tick!()
            // }, 1000 / 60)
            this.tickHandler = raf(()=> {
                this.tick!()
            })
            // this.tickHandlers.push(this.tickHandler)
        }
        this.tick!()
    }
    pause() {
        if (!(this.state === 'Started')) return;
        this.state = 'Paused';
        this.pauseStart = Date.now();
        // clearTimeout(this.tickHandler);
        cancelRaf(this.tickHandler);
    }
    resume() {
        if (!(this.state === 'Paused')) return;
        this.state = 'Started';
        this.pauseTime += Date.now() - this.pauseStart;
        this.tick!();
    }
    reset() {
        this.pause();
        this.state = 'Initiated';
        this.pauseTime = 0;
        this.pauseStart = 0;
        this.animations.clear()
        this.delAnimations.clear()
        this.startTimes.clear()
        this.tickHandler = 0;
    }
    add(animation : Animation, startTime ?: number | null) {
        if (startTime == null) startTime = Date.now();
        this.animations.add(animation);
        this.startTimes.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) {
        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)
    }
}