-
Notifications
You must be signed in to change notification settings - Fork 1
/
timeline.js
138 lines (114 loc) · 3.67 KB
/
timeline.js
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Timeline object
class timelineobj
{
constructor()
{
this.timeline=[]; // Array of actions
this.timelinepos=0; // Point in time of last update
this.timelineepoch=0; // Epoch when timeline was started
this.callback=null; // Optional callback on each timeline "tick"
this.running=false; // Start in non-running state
this.looped=0; // Completed iterations
this.loop=1; // Number of times to loop, 0 means infinite
}
// Add a new function to timeline with a given start time
add(itemstart, newitem)
{
var newobj={start:itemstart, item:newitem, done:false};
this.timeline.push(newobj);
// Keep timeline sorted by start time of items
this.timeline.sort(function(a,b) {return ((b.start<a.start)?1:(b.start==a.start)?0:-1)});
}
// Add a timeline callback
addcallback(item)
{
this.callback=item;
}
// Animation frame callback
timelineraf(timestamp)
{
var remain=0;
// Stop further processing if we're not running
if (!this.running) return;
// If this is the first call then just record the epoch
if (this.timelinepos==0)
{
this.timelineepoch=timestamp;
}
else
{
// Calculate delta time since timeline start
var delta=timestamp-this.timelineepoch;
// Look through timeline array for jobs not run which should have
for (var i=0; i<this.timeline.length; i++)
{
if ((!this.timeline[i].done) && (this.timeline[i].start<delta))
{
this.timeline[i].done=true;
// Only call function if it is defined
if (this.timeline[i].item!=undefined)
this.timeline[i].item();
}
// Keep a count of all remaining jobs
if (!this.timeline[i].done)
remain++;
}
// If a callback was requested, then call it
if (this.callback!=null)
{
// If there's only a single undefined function on the timeline and it doesn't start at 0, then call with percentage
if ((this.timeline.length==1) && (this.timeline[0].item==undefined) && (this.timeline[0].start>0))
this.callback((delta/this.timeline[0].start)*100);
else
this.callback();
}
}
// Record new timeline position
this.timelinepos=timestamp;
// If there is more jobs then request another callback
if ((this.timelinepos==this.timelineepoch) || (remain>0))
{
window.requestAnimationFrame(this.timelineraf.bind(this));
}
else
{
this.looped++;
// Check for more iterations
if ((this.loop==0) || (this.looped<this.loop))
{
this.running=false; // Prevent running until we've reset
this.timelinepos=0;
this.timelineepoch=0;
// Look through timeline, resetting done flag
for (var i=0; i<this.timeline.length; i++)
this.timeline[i].done=false;
this.running=true; // Start next iteration
window.requestAnimationFrame(this.timelineraf.bind(this));
}
}
}
// Start the timeline running
begin(loop)
{
this.looped=0;
this.loop=(loop==undefined?1:loop);
this.running=true;
window.requestAnimationFrame(this.timelineraf.bind(this));
}
// Stop the timeline running
end()
{
this.running=false;
}
// Reset the timeline to be used again
reset()
{
this.running=false; // Start in non-running state
this.timeline=[]; // Array of actions
this.timelinepos=0; // Point in time of last update
this.timelineepoch=0; // Epoch when timeline was started
this.callback=null; // Optional callback on each timeline "tick"
this.looped=0; // Completed iterations
this.loop=1; // Number of times to loop, 0 means infinite
}
}