Matteo Scandolo | 46b5610 | 2015-12-16 14:23:08 -0800 | [diff] [blame] | 1 | /* |
| 2 | * https://github.com/alicelieutier/smoothScroll/ |
| 3 | * A teeny tiny, standard compliant, smooth scroll script with ease-in-out effect and no jQuery (or any other dependancy, FWIW). |
| 4 | * MIT License |
| 5 | */ |
| 6 | window.smoothScroll = (function(){ |
| 7 | // We do not want this script to be applied in browsers that do not support those |
| 8 | // That means no smoothscroll on IE9 and below. |
| 9 | if(document.querySelectorAll === void 0 || window.pageYOffset === void 0 || history.pushState === void 0) { return; } |
| 10 | |
| 11 | // Get the top position of an element in the document |
| 12 | var getTop = function(element) { |
| 13 | // return value of html.getBoundingClientRect().top ... IE : 0, other browsers : -pageYOffset |
| 14 | if(element.nodeName === 'HTML') return -window.pageYOffset |
| 15 | return element.getBoundingClientRect().top + window.pageYOffset; |
| 16 | } |
| 17 | // ease in out function thanks to: |
| 18 | // http://blog.greweb.fr/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation/ |
| 19 | var easeInOutCubic = function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 } |
| 20 | |
| 21 | // calculate the scroll position we should be in |
| 22 | // given the start and end point of the scroll |
| 23 | // the time elapsed from the beginning of the scroll |
| 24 | // and the total duration of the scroll (default 500ms) |
| 25 | var position = function(start, end, elapsed, duration) { |
| 26 | if (elapsed > duration) return end; |
| 27 | return start + (end - start) * easeInOutCubic(elapsed / duration); // <-- you can change the easing funtion there |
| 28 | // return start + (end - start) * (elapsed / duration); // <-- this would give a linear scroll |
| 29 | } |
| 30 | |
| 31 | // we use requestAnimationFrame to be called by the browser before every repaint |
| 32 | // if the first argument is an element then scroll to the top of this element |
| 33 | // if the first argument is numeric then scroll to this location |
| 34 | // if the callback exist, it is called when the scrolling is finished |
| 35 | var smoothScroll = function(el, duration, callback){ |
| 36 | duration = duration || 500; |
| 37 | var start = window.pageYOffset; |
| 38 | |
| 39 | if (typeof el === 'number') { |
| 40 | var end = parseInt(el); |
| 41 | } else { |
| 42 | var end = getTop(el); |
| 43 | } |
| 44 | |
| 45 | var clock = Date.now(); |
| 46 | var requestAnimationFrame = window.requestAnimationFrame || |
| 47 | window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || |
| 48 | function(fn){window.setTimeout(fn, 15);}; |
| 49 | |
| 50 | var step = function(){ |
| 51 | var elapsed = Date.now() - clock; |
| 52 | window.scroll(0, position(start, end, elapsed, duration)); |
| 53 | if (elapsed > duration) { |
| 54 | if (typeof callback === 'function') { |
| 55 | callback(el); |
| 56 | } |
| 57 | } else { |
| 58 | requestAnimationFrame(step); |
| 59 | } |
| 60 | } |
| 61 | step(); |
| 62 | } |
| 63 | |
| 64 | var linkHandler = function(ev) { |
| 65 | ev.preventDefault(); |
| 66 | |
| 67 | if (location.hash !== this.hash) { |
| 68 | //NOTE(@ajoslin): Changed this line to stop $digest errors |
| 69 | //window.history.pushState(null, null, this.hash) |
| 70 | angular.element(document).injector().get('$location').hash(this.hash); |
| 71 | } |
| 72 | // using the history api to solve issue #1 - back doesn't work |
| 73 | // most browser don't update :target when the history api is used: |
| 74 | // THIS IS A BUG FROM THE BROWSERS. |
| 75 | // change the scrolling duration in this call |
| 76 | var targetEl = document.getElementById(this.hash.substring(1)); |
| 77 | if (targetEl) { |
| 78 | smoothScroll(document.getElementById(this.hash.substring(1)), 500, function(el) { |
| 79 | location.replace('#' + el.id) |
| 80 | // this will cause the :target to be activated. |
| 81 | }); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | // We look for all the internal links in the documents and attach the smoothscroll function |
| 86 | document.addEventListener("DOMContentLoaded", function () { |
| 87 | var internal = document.querySelectorAll('a[href^="#"]'), a; |
| 88 | for(var i=internal.length; a=internal[--i];){ |
| 89 | a.addEventListener("click", linkHandler, false); |
| 90 | } |
| 91 | }); |
| 92 | |
| 93 | // return smoothscroll API |
| 94 | return smoothScroll; |
| 95 | |
| 96 | })(); |
| 97 | |