Skip to content

Instantly share code, notes, and snippets.

@anhulife
Last active December 24, 2015 10:58
Show Gist options
  • Save anhulife/a5c61d62aa5482e34e57 to your computer and use it in GitHub Desktop.
Save anhulife/a5c61d62aa5482e34e57 to your computer and use it in GitHub Desktop.
/**
* 动画函数
* @param {Object} opts 动画参数
* @param {Number} opts.duration 持续时间
* @param {Function} [opts.delta] 动画进度计算函数默认为线性
* @param {Function} opts.complete 动画完成之后执行的函数
* @param {Function} opts.render 动画渲染函数
*/
function animate(opts) {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(callback ){window.setTimeout(callback, 1000/60);};
var duration = opts.duration;
var delta = opts.delta || function (progress) {return progress;};
var render = opts.render;
var complete = opts.complete || function () {};
var start = new Date();
var progress;
var stopFlag;
function frame() {
if (stopFlag) {
return;
}
progress = (new Date() - start) / duration;
progress = progress > 1 ? 1 : progress;
render(delta(progress));
if (progress < 1) {
requestAnimationFrame(frame);
} else {
complete();
}
}
requestAnimationFrame(frame);
return function stop() {
stopFlag = true;
};
}
/**
* KeySpline - use bezier curve for transition easing function
* is inspired from Firefox's nsSMILKeySpline.cpp
* Usage:
* var spline = new KeySpline(0.25, 0.1, 0.25, 1.0)
* spline.get(x) => returns the easing value | x must be in [0, 1] range
*/
function KeySpline(mX1, mY1, mX2, mY2) {
this.get = function (aX) {
if (mX1 == mY1 && mX2 == mY2) return aX; // linear
return CalcBezier(GetTForX(aX), mY1, mY2);
};
function A(aA1, aA2) {
return 1.0 - 3.0 * aA2 + 3.0 * aA1;
}
function B(aA1, aA2) {
return 3.0 * aA2 - 6.0 * aA1;
}
function C(aA1) {
return 3.0 * aA1;
}
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function CalcBezier(aT, aA1, aA2) {
return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;
}
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function GetSlope(aT, aA1, aA2) {
return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
}
function GetTForX(aX) {
// Newton raphson iteration
var aGuessT = aX;
for (var i = 0; i < 4; ++i) {
var currentSlope = GetSlope(aGuessT, mX1, mX2);
if (currentSlope == 0.0) return aGuessT;
var currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
}
function demo(el, start, end, complete) {
var diff = end - start;
animate({
duration: 500,
delta: new KeySpline(0.1, 0.5, 0.1, 1).get,
render: function (progress) {
el.style.left = (start + Math.floor(diff * progress)) + 'px';
},
complete: complete
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment