You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
5.7 KiB
179 lines
5.7 KiB
/*
|
|
* Scroller
|
|
* http://github.com/zynga/scroller
|
|
*
|
|
* Copyright 2011, Zynga Inc.
|
|
* Licensed under the MIT License.
|
|
* https://raw.github.com/zynga/scroller/master/MIT-LICENSE.txt
|
|
*
|
|
* Based on the work of: Unify Project (unify-project.org)
|
|
* http://unify-project.org
|
|
* Copyright 2011, Deutsche Telekom AG
|
|
* License: MIT + Apache (V2)
|
|
*/
|
|
|
|
/**
|
|
* Generic animation class with support for dropped frames both optional easing and duration.
|
|
*
|
|
* Optional duration is useful when the lifetime is defined by another condition than time
|
|
* e.g. speed of an animating object, etc.
|
|
*
|
|
* Dropped frame logic allows to keep using the same updater logic independent from the actual
|
|
* rendering. This eases a lot of cases where it might be pretty complex to break down a state
|
|
* based on the pure time difference.
|
|
*/
|
|
var desiredFrames = 60;
|
|
var millisecondsPerSecond = 1000;
|
|
var running = {};
|
|
var counter = 1;
|
|
var win = typeof window !== 'undefined' ? window : undefined;
|
|
|
|
if (!win) {
|
|
win = typeof global !== 'undefined' ? global : {};
|
|
}
|
|
|
|
// 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 and Tino Zijdel
|
|
(function () {
|
|
var lastTime = 0;
|
|
var vendors = ['ms', 'moz', 'webkit', 'o'];
|
|
for (var x = 0; x < vendors.length && !win.requestAnimationFrame; ++x) {
|
|
win.requestAnimationFrame = win[vendors[x] + 'RequestAnimationFrame'];
|
|
win.cancelAnimationFrame = win[vendors[x] + 'CancelAnimationFrame'] || win[vendors[x] + 'CancelRequestAnimationFrame'];
|
|
}
|
|
|
|
if (!win.requestAnimationFrame) {
|
|
win.requestAnimationFrame = function (callback) {
|
|
var currTime = new Date().getTime();
|
|
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
|
var id = win.setTimeout(function () {
|
|
callback(currTime + timeToCall);
|
|
}, timeToCall);
|
|
lastTime = currTime + timeToCall;
|
|
return id;
|
|
};
|
|
}
|
|
if (!win.cancelAnimationFrame) {
|
|
win.cancelAnimationFrame = function (id) {
|
|
clearTimeout(id);
|
|
};
|
|
}
|
|
})();
|
|
|
|
var Animate = {
|
|
/**
|
|
* Stops the given animation.
|
|
*
|
|
* @param id {Integer} Unique animation ID
|
|
* @return {Boolean} Whether the animation was stopped (aka, was running before)
|
|
*/
|
|
stop: function stop(id) {
|
|
var cleared = running[id] != null;
|
|
if (cleared) {
|
|
running[id] = null;
|
|
}
|
|
|
|
return cleared;
|
|
},
|
|
|
|
/**
|
|
* Whether the given animation is still running.
|
|
*
|
|
* @param id {Integer} Unique animation ID
|
|
* @return {Boolean} Whether the animation is still running
|
|
*/
|
|
isRunning: function isRunning(id) {
|
|
return running[id] != null;
|
|
},
|
|
|
|
/**
|
|
* Start the animation.
|
|
*
|
|
* @param stepCallback {Function} Pointer to function which is executed on every step.
|
|
* Signature of the method should be `function(percent, now, virtual) { return continueWithAnimation; }`
|
|
* @param verifyCallback {Function} Executed before every animation step.
|
|
* Signature of the method should be `function() { return continueWithAnimation; }`
|
|
* @param completedCallback {Function}
|
|
* Signature of the method should be `function(droppedFrames, finishedAnimation) {}`
|
|
* @param duration {Integer} Milliseconds to run the animation
|
|
* @param easingMethod {Function} Pointer to easing function
|
|
* Signature of the method should be `function(percent) { return modifiedValue; }`
|
|
* @return {Integer} Identifier of animation. Can be used to stop it any time.
|
|
*/
|
|
start: function start(stepCallback, verifyCallback, completedCallback, duration, easingMethod) {
|
|
var start = +new Date();
|
|
var lastFrame = start;
|
|
var percent = 0;
|
|
var dropCounter = 0;
|
|
var id = counter++;
|
|
|
|
// Compacting running db automatically every few new animations
|
|
if (id % 20 === 0) {
|
|
var newRunning = {};
|
|
for (var usedId in running) {
|
|
newRunning[usedId] = true;
|
|
}
|
|
running = newRunning;
|
|
}
|
|
|
|
// This is the internal step method which is called every few milliseconds
|
|
var step = function step(virtual) {
|
|
// Normalize virtual value
|
|
var render = virtual !== true;
|
|
|
|
// Get current time
|
|
var now = +new Date();
|
|
|
|
// Verification is executed before next animation step
|
|
if (!running[id] || verifyCallback && !verifyCallback(id)) {
|
|
|
|
running[id] = null;
|
|
completedCallback && completedCallback(desiredFrames - dropCounter / ((now - start) / millisecondsPerSecond), id, false);
|
|
return;
|
|
}
|
|
|
|
// For the current rendering to apply let's update omitted steps in memory.
|
|
// This is important to bring internal state variables up-to-date with progress in time.
|
|
if (render) {
|
|
|
|
var droppedFrames = Math.round((now - lastFrame) / (millisecondsPerSecond / desiredFrames)) - 1;
|
|
for (var j = 0; j < Math.min(droppedFrames, 4); j++) {
|
|
step(true);
|
|
dropCounter++;
|
|
}
|
|
}
|
|
|
|
// Compute percent value
|
|
if (duration) {
|
|
percent = (now - start) / duration;
|
|
if (percent > 1) {
|
|
percent = 1;
|
|
}
|
|
}
|
|
|
|
// Execute step callback, then...
|
|
var value = easingMethod ? easingMethod(percent) : percent;
|
|
if ((stepCallback(value, now, render) === false || percent === 1) && render) {
|
|
running[id] = null;
|
|
completedCallback && completedCallback(desiredFrames - dropCounter / ((now - start) / millisecondsPerSecond), id, percent === 1 || duration == null);
|
|
} else if (render) {
|
|
lastFrame = now;
|
|
win.requestAnimationFrame(step);
|
|
}
|
|
};
|
|
|
|
// Mark as running
|
|
running[id] = true;
|
|
|
|
// Init first step
|
|
win.requestAnimationFrame(step);
|
|
|
|
// Return unique animation ID
|
|
return id;
|
|
}
|
|
};
|
|
|
|
export default Animate; |