Last active
December 24, 2015 10:58
-
-
Save anhulife/a5c61d62aa5482e34e57 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 动画函数 | |
* @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