animate.js
3.69 KB
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
(function() {
function noop() {
return false;
}
function defaultEasing(t, b, c, d) {
return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
}
/**
* Changes value from one to another within certain period of time, invoking callbacks as value is being changed.
* @memberOf fabric.util
* @param {Object} [options] Animation options
* @param {Function} [options.onChange] Callback; invoked on every value change
* @param {Function} [options.onComplete] Callback; invoked when value change is completed
* @param {Number} [options.startValue=0] Starting value
* @param {Number} [options.endValue=100] Ending value
* @param {Number} [options.byValue=100] Value to modify the property by
* @param {Function} [options.easing] Easing function
* @param {Number} [options.duration=500] Duration of change (in ms)
* @param {Function} [options.abort] Additional function with logic. If returns true, onComplete is called.
*/
function animate(options) {
requestAnimFrame(function(timestamp) {
options || (options = { });
var start = timestamp || +new Date(),
duration = options.duration || 500,
finish = start + duration, time,
onChange = options.onChange || noop,
abort = options.abort || noop,
onComplete = options.onComplete || noop,
easing = options.easing || defaultEasing,
startValue = 'startValue' in options ? options.startValue : 0,
endValue = 'endValue' in options ? options.endValue : 100,
byValue = options.byValue || endValue - startValue;
options.onStart && options.onStart();
(function tick(ticktime) {
// TODO: move abort call after calculation
// and pass (current,valuePerc, timePerc) as arguments
time = ticktime || +new Date();
var currentTime = time > finish ? duration : (time - start),
timePerc = currentTime / duration,
current = easing(currentTime, startValue, byValue, duration),
valuePerc = Math.abs((current - startValue) / byValue);
if (abort()) {
onComplete(endValue, 1, 1);
return;
}
if (time > finish) {
onChange(endValue, 1, 1);
onComplete(endValue, 1, 1);
return;
}
else {
onChange(current, valuePerc, timePerc);
requestAnimFrame(tick);
}
})(start);
});
}
var _requestAnimFrame = fabric.window.requestAnimationFrame ||
fabric.window.webkitRequestAnimationFrame ||
fabric.window.mozRequestAnimationFrame ||
fabric.window.oRequestAnimationFrame ||
fabric.window.msRequestAnimationFrame ||
function(callback) {
return fabric.window.setTimeout(callback, 1000 / 60);
};
var _cancelAnimFrame = fabric.window.cancelAnimationFrame || fabric.window.clearTimeout;
/**
* requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method
* @memberOf fabric.util
* @param {Function} callback Callback to invoke
* @param {DOMElement} element optional Element to associate with animation
*/
function requestAnimFrame() {
return _requestAnimFrame.apply(fabric.window, arguments);
}
function cancelAnimFrame() {
return _cancelAnimFrame.apply(fabric.window, arguments);
}
fabric.util.animate = animate;
fabric.util.requestAnimFrame = requestAnimFrame;
fabric.util.cancelAnimFrame = cancelAnimFrame;
})();