Last active
June 12, 2019 21:25
-
-
Save bootsified/71472b4df5d38ea34e3f936fcba4c713 to your computer and use it in GitHub Desktop.
Assign links to scroll to content within page.
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
/*/////////////////////////////////////////////////////////////// | |
SCROLL TO ANCHOR | |
Using your site's onLoad function, initialize the script: | |
`ScrollToAnchor.init();` | |
Any link with a hash href (e.g. '#myElement') will scroll the page | |
to the link position. To disable the scrolling for a link, give it | |
the 'no-scroll' class: | |
`<a href="#myElement" class="no-scroll">Click me</a>` | |
To manually scroll the page, call: | |
`scrollPage(target, padding, duration, easing, callback);` | |
Example: | |
`ScrollToAnchor.scrollPage('#myElement', 0, 750, 'easeInOutCubic', myCallbackFunction);` | |
Notes: | |
- The 'padding' parameter is the amount of extra space (pixels) | |
above the element when scrolling completes (default 0). | |
- Default duration is 750 (milliseconds). | |
- For easing functions, see Easing object below. | |
Default 'easeInOutCubic'. | |
///////////////////////////////////////////////////////////////*/ | |
var ctaRafId, | |
ScrollToAnchor = { | |
init: function() { | |
this.bindUIActions(); | |
}, | |
bindUIActions: function() { | |
var elems = document.querySelectorAll('a[href*="#"]:not(.no-scroll)'); | |
if (elems.length) { | |
elems.forEach(function(elem) { | |
elem.addEventListener('click', ScrollToAnchor.onClick); | |
}); | |
} | |
}, | |
getHeaderHeight: function() { | |
var headHeight; | |
headHeight = document.querySelector('.site-header').offsetHeight + 20; | |
return headHeight; | |
}, | |
onClick: function(e) { | |
try { | |
e.preventDefault(); | |
var targetId = this.getAttribute('href'), | |
targetPad = this.getAttribute('data-scroll-pad'), | |
pad = 0; | |
if (typeof targetPad !== typeof null && targetPad !== '') { | |
pad = parseInt(targetPad); | |
} | |
// console.debug('targetId: ' + targetId); | |
// console.debug('elem: ' + document.querySelector(targetId)); | |
if (targetId != '#' && targetId != '#0' && document.querySelector(targetId)) { | |
ScrollToAnchor.scrollPage(targetId, pad); | |
document.querySelector('html').classList.remove('menu-open'); | |
} | |
} catch (error) { | |
console.debug(error.message); | |
window.location = this.getAttribute('href'); | |
} | |
}, | |
scrollPage: function(trgt, pad, duration, easing, callback) { | |
// console.debug('pad: ' + pad); | |
if (typeof pad === 'undefined') { | |
pad = 0; | |
} | |
if (typeof duration === 'undefined') { | |
duration = 750; | |
} | |
if (typeof easing === 'undefined') { | |
easing = 'easeInOutCubic'; | |
} | |
try { | |
var destination = document.querySelector(trgt); | |
var start = window.pageYOffset; | |
var startTime = 'now' in window.performance ? performance.now() : new Date().getTime(); | |
var documentHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight); | |
var windowHeight = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight; | |
var windowWidth = window.innerWidth || document.documentElement.clientWidth || document.getElementsByTagName('body')[0].clientWidth; | |
var headerHeight = ScrollToAnchor.getHeaderHeight(); | |
// TODO: For some reason, `offsetTop` doesn't work for the grid elements when stacked on mobile. | |
// var offsetTop = destination.offsetTop; | |
var offsetTop = $(destination).offset().top; // TODO: Convert to vanilla js | |
var currentScroll = window.scrollY + headerHeight; | |
if (pad < 1 && windowWidth >= 840) { | |
if (offsetTop > currentScroll) { | |
pad = 50; | |
} else { | |
pad = headerHeight; | |
} | |
} else { | |
pad = headerHeight; | |
} | |
var destinationOffset = typeof destination === 'number' ? destination : offsetTop - pad; | |
var destinationOffsetToScroll = Math.round(documentHeight - destinationOffset < windowHeight ? documentHeight - windowHeight : destinationOffset); | |
// console.debug('----------------'); | |
console.debug('pad: ' + pad); | |
// console.debug('start: ' + start); | |
// console.debug('startTime: ' + startTime); | |
// console.debug('documentHeight: ' + documentHeight); | |
// console.debug('windowHeight: ' + windowHeight); | |
// console.debug('offsetTop: ' + offsetTop); | |
// console.debug('currentScroll: ' + currentScroll); | |
// console.debug('destination.offsetTop: ' + destination.offsetTop); | |
// console.debug('destinationOffset: ' + destinationOffset); | |
// console.debug('destinationOffsetToScroll: ' + destinationOffsetToScroll); | |
// console.debug('----------------'); | |
if ('requestAnimationFrame' in window === false) { | |
window.scroll(0, destinationOffsetToScroll); | |
if (callback) { | |
callback(); | |
} | |
return; | |
} | |
function scroll() { | |
var now = 'now' in window.performance ? performance.now() : new Date().getTime(); | |
var time = Math.min(1, ((now - startTime) / duration)); | |
var timeFunction = Easings[easing](time); | |
window.scroll(0, Math.ceil((timeFunction * (destinationOffsetToScroll - start)) + start)); | |
if (window.pageYOffset === destinationOffsetToScroll) { | |
if (callback) { | |
callback(); | |
} | |
return; | |
} | |
ctaRafId = requestAnimationFrame(scroll); | |
} | |
// scroll(); | |
ctaRafId = requestAnimationFrame(scroll); | |
setTimeout(function() { | |
cancelAnimationFrame(ctaRafId); | |
}, 1000); | |
} catch (error) { | |
console.log('Caught error: ' + error.message) | |
} | |
}, | |
destroy: function() { | |
var elems = document.querySelectorAll('a[href*="#"]:not(.no-scroll)'); | |
elems.forEach(function(elem) { | |
elem.removeEventListener('click', ScrollToAnchor.onClick); | |
}); | |
} | |
}; | |
var Easings = { | |
linear: function(t) { | |
return t; | |
}, | |
easeInQuad: function(t) { | |
return t * t; | |
}, | |
easeOutQuad: function(t) { | |
return t * (2 - t); | |
}, | |
easeInOutQuad: function(t) { | |
return t < 0.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 < 0.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 < 0.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 < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment