87 lines
2.7 KiB
JavaScript
87 lines
2.7 KiB
JavaScript
|
// AnimateScroll.js
|
||
|
// Sunmock Yang Nov. 2015
|
||
|
|
||
|
function animateScroll(target, duration, easing, padding, align, onFinish) {
|
||
|
padding = padding ? padding : 0;
|
||
|
var docElem = document.documentElement; // to facilitate minification better
|
||
|
var windowHeight = docElem.clientHeight;
|
||
|
var maxScroll = ( 'scrollMaxY' in window ) ? window.scrollMaxY : (docElem.scrollHeight - windowHeight);
|
||
|
var currentY = window.pageYOffset;
|
||
|
|
||
|
var targetY = currentY;
|
||
|
var elementBounds = isNaN(target) ? target.getBoundingClientRect() : 0;
|
||
|
|
||
|
if (align === "center") {
|
||
|
targetY += isNaN(target) ? (elementBounds.top + elementBounds.height/2) : target;
|
||
|
targetY -= windowHeight / 2;
|
||
|
targetY -= padding
|
||
|
}
|
||
|
else if (align === "bottom") {
|
||
|
targetY += elementBounds.bottom || target;
|
||
|
targetY -= windowHeight;
|
||
|
targetY += padding
|
||
|
}
|
||
|
else { // top, undefined
|
||
|
targetY += elementBounds.top || target;
|
||
|
targetY -= padding
|
||
|
}
|
||
|
targetY = Math.max(Math.min(maxScroll, targetY), 0);
|
||
|
|
||
|
var deltaY = targetY - currentY;
|
||
|
|
||
|
var obj = {
|
||
|
targetY: targetY,
|
||
|
deltaY: deltaY,
|
||
|
duration: (duration) ? duration : 0,
|
||
|
easing: (easing in animateScroll.Easing) ? animateScroll.Easing[easing] : animateScroll.Easing.linear,
|
||
|
onFinish: onFinish,
|
||
|
startTime: Date.now(),
|
||
|
lastY: currentY,
|
||
|
step: animateScroll.step,
|
||
|
};
|
||
|
|
||
|
window.requestAnimationFrame(obj.step.bind(obj));
|
||
|
}
|
||
|
|
||
|
// Taken from gre/easing.js
|
||
|
// https://gist.github.com/gre/1650294
|
||
|
animateScroll.Easing = {
|
||
|
linear: function (t) { return t },
|
||
|
easeInQuad: function (t) { return t*t },
|
||
|
easeOutQuad: function (t) { return t*(2-t) },
|
||
|
easeInOutQuad: function (t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t },
|
||
|
easeInCubic: function (t) { return t*t*t },
|
||
|
easeOutCubic: function (t) { return (--t)*t*t+1 },
|
||
|
easeInOutCubic: function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 },
|
||
|
easeInQuart: function (t) { return t*t*t*t },
|
||
|
easeOutQuart: function (t) { return 1-(--t)*t*t*t },
|
||
|
easeInOutQuart: function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t },
|
||
|
easeInQuint: function (t) { return t*t*t*t*t },
|
||
|
easeOutQuint: function (t) { return 1+(--t)*t*t*t*t },
|
||
|
easeInOutQuint: function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t }
|
||
|
};
|
||
|
|
||
|
animateScroll.step = function () {
|
||
|
if (this.lastY !== window.pageYOffset && this.onFinish) {
|
||
|
this.onFinish();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Calculate how much time has passed
|
||
|
var t = Math.min((Date.now() - this.startTime) / this.duration, 1);
|
||
|
|
||
|
// Scroll window amount determined by easing
|
||
|
var y = this.targetY - ((1 - this.easing(t)) * (this.deltaY));
|
||
|
window.scrollTo(window.scrollX, y);
|
||
|
|
||
|
// Continue animation as long as duration hasn't surpassed
|
||
|
if (t !== 1) {
|
||
|
this.lastY = window.pageYOffset;
|
||
|
window.requestAnimationFrame(this.step.bind(this));
|
||
|
} else {
|
||
|
if (this.onFinish) this.onFinish();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = animateScroll
|