Skip to content

Instantly share code, notes, and snippets.

@szepeviktor
Last active January 1, 2016 11:29
Show Gist options
  • Save szepeviktor/8138710 to your computer and use it in GitHub Desktop.
Save szepeviktor/8138710 to your computer and use it in GitHub Desktop.
smooth scroll AMD update
/* =============================================================
Smooth Scroll 3.0
Animate scrolling to anchor links, by Chris Ferdinandi.
http://gomakethings.com
Easing support contributed by Willem Liu.
https://github.com/willemliu
Easing functions forked from Gaëtan Renaudeau.
https://gist.github.com/gre/1650294
Free to use under the MIT License.
http://gomakethings.com/mit/
* ============================================================= */
(function(global) {
'use strict';
function smoothScrollDefinition() {
// Function to animate the scroll
var smoothScroll = function (anchor, duration, easing) {
// Functions to control easing
var easingPattern = function (type, time) {
if ( type == 'easeInQuad' ) return time * time; // accelerating from zero velocity
if ( type == 'easeOutQuad' ) return time * (2 - time); // decelerating to zero velocity
if ( type == 'easeInOutQuad' ) return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
if ( type == 'easeInCubic' ) return time * time * time; // accelerating from zero velocity
if ( type == 'easeOutCubic' ) return (--time) * time * time + 1; // decelerating to zero velocity
if ( type == 'easeInOutCubic' ) return time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
if ( type == 'easeInQuart' ) return time * time * time * time; // accelerating from zero velocity
if ( type == 'easeOutQuart' ) return 1 - (--time) * time * time * time; // decelerating to zero velocity
if ( type == 'easeInOutQuart' ) return time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
if ( type == 'easeInQuint' ) return time * time * time * time * time; // accelerating from zero velocity
if ( type == 'easeOutQuint' ) return 1 + (--time) * time * time * time * time; // decelerating to zero velocity
if ( type == 'easeInOutQuint' ) return time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
return time; // no easing, no acceleration
};
// Calculate how far and how fast to scroll
// http://www.quirksmode.org/blog/archives/2008/01/using_the_assig.html
var startLocation = window.pageYOffset;
var endLocation = function (anchor) {
var distance = 0;
if (anchor.offsetParent) {
do {
distance += anchor.offsetTop;
anchor = anchor.offsetParent;
} while (anchor);
}
return distance;
};
var distance = endLocation(anchor) - startLocation;
var increments = distance / (duration / 16);
var timeLapsed = 0;
var percentage, position, stopAnimation;
// Scroll the page by an increment, and check if it's time to stop
var animateScroll = function () {
timeLapsed += 16;
percentage = ( timeLapsed / duration );
percentage = ( percentage > 1 ) ? 1 : percentage;
position = startLocation + ( distance * easingPattern(easing, percentage) );
window.scrollTo(0, position);
stopAnimation();
};
// Stop the animation
if ( increments >= 0 ) { // If scrolling down
// Stop animation when you reach the anchor OR the bottom of the page
stopAnimation = function () {
var travelled = window.pageYOffset;
if ( (travelled >= (endLocation(anchor) - increments)) || ((window.innerHeight + travelled) >= document.body.offsetHeight) ) {
clearInterval(runAnimation);
}
};
} else { // If scrolling up
// Stop animation when you reach the anchor OR the top of the page
stopAnimation = function () {
var travelled = window.pageYOffset;
if ( travelled <= endLocation(anchor) || travelled <= 0 ) {
clearInterval(runAnimation);
}
};
}
// Loop the animation function
var runAnimation = setInterval(animateScroll, 16);
return runAnimation;
}
return smoothScroll;
}
// -------------------------- transport -------------------------- //
if ( typeof define === 'function' && define.amd ) {
// AMD
define( smoothScrollDefinition );
} else {
// browser global
global.SmoothScroll = smoothScrollDefinition();
// Feature Test
if ( 'querySelector' in document && 'addEventListener' in window && Array.prototype.forEach ) {
// For each smooth scroll link
var scrollToggle = global.document.querySelectorAll('.scroll');
[].forEach.call(scrollToggle, function (toggle) {
// When the smooth scroll link is clicked
toggle.addEventListener('click', function(e) {
// Prevent the default link behavior
e.preventDefault();
// Get anchor link and calculate distance from the top
var dataID = toggle.getAttribute('href');
var dataTarget = global.document.querySelector(dataID);
var dataSpeed = toggle.getAttribute('data-speed');
var dataEasing = toggle.getAttribute('data-easing'); // WL: Added easing attribute support.
// If the anchor exists
if (dataTarget) {
// Scroll to the anchor
global.SmoothScroll(dataTarget, dataSpeed || 500, dataEasing || 'easeInOutCubic');
}
}, false);
});
};
}
//TODO
// - wait for DOMReady
// - data-smoothscroll-speed / -easing
// http://www.w3.org/TR/2010/WD-html5-20101019/elements.html#embedding-custom-non-visible-data-with-the-data-attributes
// "Authors of libraries that are reused by many authors are encouraged to include their name in the attribute names,
// to reduce the risk of clashes."
//
// - requestAnimationFrame polyfill
// https://gist.github.com/paulirish/1579671
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment