-
Notifications
You must be signed in to change notification settings - Fork 8
/
metronome.js
135 lines (122 loc) · 4.64 KB
/
metronome.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
(function() {
// Adapted from https://gist.github.com/paulirish/1579671 which derived from
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller.
// Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon
var dateNow = Date.now || function() { return new Date().getTime(); };
(function() {
var vendors = ['webkit', 'moz'];
for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
var vp = vendors[i];
window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
|| window[vp+'CancelRequestAnimationFrame']);
}
if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
|| !window.requestAnimationFrame || !window.cancelAnimationFrame) {
var lastTime = 0;
window.requestAnimationFrame = function(callback) {
var now = dateNow();
var nextTime = Math.max(lastTime + 16, now);
return setTimeout(function() { callback(lastTime = nextTime); },
nextTime - now);
};
window.cancelAnimationFrame = clearTimeout;
}
}());
// From: https://gist.github.com/gre/1650294
var Easing = {
// no easing, no acceleration
linear: function (t) { return t; },
// accelerating from zero velocity
easeInQuad: function (t) { return t*t; },
// decelerating to zero velocity
easeOutQuad: function (t) { return t*(2-t); },
// acceleration until halfway, then deceleration
easeInOutQuad: function (t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t; },
// accelerating from zero velocity
easeInCubic: function (t) { return t*t*t; },
// decelerating to zero velocity
easeOutCubic: function (t) { return (--t)*t*t+1; },
// acceleration until halfway, then deceleration
easeInOutCubic: function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1; },
// accelerating from zero velocity
easeInQuart: function (t) { return t*t*t*t; },
// decelerating to zero velocity
easeOutQuart: function (t) { return 1-(--t)*t*t*t; },
// acceleration until halfway, then deceleration
easeInOutQuart: function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t; },
// accelerating from zero velocity
easeInQuint: function (t) { return t*t*t*t*t; },
// decelerating to zero velocity
easeOutQuint: function (t) { return 1+(--t)*t*t*t*t; },
// acceleration until halfway, then deceleration
easeInOutQuint: function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t; }
};
var MetronomeException = function(message) {
this.name = "MetronomeException";
this.message = message;
};
var noop = function() {};
var animate_frames = function(options) {
var handle = 0;
var current_frame = 0;
var max_frame = options.frames;
var progress = 0;
var callback = options.draw || noop;
var complete = options.complete || noop;
var easing = Easing[options.easing || 'easeInOutQuad' ];
var progress_method = function() {
current_frame++;
return Math.min(1, easing(current_frame/max_frame));
};
var draw = function() {
var progress = progress_method();
callback(handle, progress);
if (progress >= 1) {
window.cancelAnimationFrame(handle);
if (!!complete) { complete(); }
} else {
handle = window.requestAnimationFrame(draw);
}
};
draw();
};
var animate_duration = function(options) {
var handle = 0;
var initial_ts = dateNow();
var progress = 0;
var max_duration = options.duration;
var callback = options.draw || noop;
var complete = options.complete || noop;
var easing = Easing[options.easing || 'easeInOutQuad'];
var progress_method = function() {
return Math.min(1, easing((dateNow() - initial_ts)/max_duration));
};
var draw = function() {
var progress = progress_method();
callback(handle, progress);
if (progress >= 1) {
window.cancelAnimationFrame(handle);
if (!!complete) { complete(); }
} else {
handle = window.requestAnimationFrame(draw);
}
};
draw();
};
var Metronome = function(options) {
if (!options.type) {
throw new MetronomeException("'type' is required");
return;
}
if (options.type === 'frame') {
animate_frames(options);
}
if (options.type === 'duration') {
animate_duration(options);
}
};
window.Metronome = Metronome;
})();