JAVASCRIPT 10
Smoothscroll.js Guest on 15th October 2020 04:15:37 PM
  1. /** SMOOTHSCROLL V1.2.1
  2.         Licensed under the terms of the MIT license.
  3.  **************************************************************** **/
  4. (function($) {
  5.         $.extend({
  6.  
  7.                 smoothScroll: function() {
  8.  
  9.                         // Scroll Variables (tweakable)
  10.                         var defaultOptions = {
  11.  
  12.                                 // Scrolling Core
  13.                                 frameRate        : 60, // [Hz]
  14.                                 animationTime    : 700, // [px]
  15.                                 stepSize         : 120, // [px]
  16.  
  17.                                 // Pulse (less tweakable)
  18.                                 // ratio of "tail" to "acceleration"
  19.                                 pulseAlgorithm   : true,
  20.                                 pulseScale       : 10,
  21.                                 pulseNormalize   : 1,
  22.  
  23.                                 // Acceleration
  24.                                 accelerationDelta : 20,  // 20
  25.                                 accelerationMax   : 1,   // 1
  26.  
  27.                                 // Keyboard Settings
  28.                                 keyboardSupport   : true,  // option
  29.                                 arrowScroll       : 50,     // [px]
  30.  
  31.                                 // Other
  32.                                 touchpadSupport   : true,
  33.                                 fixedBackground   : true,
  34.                                 excluded          : ""
  35.                         };
  36.  
  37.                         var options = defaultOptions;
  38.  
  39.                         // Other Variables
  40.                         var isExcluded = false;
  41.                         var isFrame = false;
  42.                         var direction = { x: 0, y: 0 };
  43.                         var initDone  = false;
  44.                         var root = document.documentElement;
  45.                         var activeElement;
  46.                         var observer;
  47.                         var deltaBuffer = [ 120, 120, 120 ];
  48.  
  49.                         var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32,
  50.                                                 pageup: 33, pagedown: 34, end: 35, home: 36 };
  51.  
  52.  
  53.                         /***********************************************
  54.                          * INITIALIZE
  55.                          ***********************************************/
  56.  
  57.                         /**
  58.                          * Tests if smooth scrolling is allowed. Shuts down everything if not.
  59.                          */
  60.                         function initTest() {
  61.  
  62.                                 var disableKeyboard = false;
  63.  
  64.                                 // disable keys for google reader (spacebar conflict)
  65.                                 if (document.URL.indexOf("google.com/reader/view") > -1) {
  66.                                         disableKeyboard = true;
  67.                                 }
  68.  
  69.                                 // disable everything if the page is blacklisted
  70.                                 if (options.excluded) {
  71.                                         var domains = options.excluded.split(/[,\n] ?/);
  72.                                         domains.push("mail.google.com"); // exclude Gmail for now
  73.                                         for (var i = domains.length; i--;) {
  74.                                                 if (document.URL.indexOf(domains[i]) > -1) {
  75.                                                         observer && observer.disconnect();
  76.                                                         removeEvent("mousewheel", wheel);
  77.                                                         disableKeyboard = true;
  78.                                                         isExcluded = true;
  79.                                                         break;
  80.                                                 }
  81.                                         }
  82.                                 }
  83.  
  84.                                 // disable keyboard support if anything above requested it
  85.                                 if (disableKeyboard) {
  86.                                         removeEvent("keydown", keydown);
  87.                                 }
  88.  
  89.                                 if (options.keyboardSupport && !disableKeyboard) {
  90.                                         addEvent("keydown", keydown);
  91.                                 }
  92.                         }
  93.  
  94.                         /**
  95.                          * Sets up scrolls array, determines if frames are involved.
  96.                          */
  97.                         function init() {
  98.  
  99.                                 if (!document.body) return;
  100.  
  101.                                 var body = document.body;
  102.                                 var html = document.documentElement;
  103.                                 var windowHeight = window.innerHeight;
  104.                                 var scrollHeight = body.scrollHeight;
  105.  
  106.                                 // check compat mode for root element
  107.                                 root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;
  108.                                 activeElement = body;
  109.  
  110.                                 initTest();
  111.                                 initDone = true;
  112.  
  113.                                 // Checks if this script is running in a frame
  114.                                 if (top != self) {
  115.                                         isFrame = true;
  116.                                 }
  117.  
  118.                                 /**
  119.                                  * This fixes a bug where the areas left and right to
  120.                                  * the content does not trigger the onmousewheel event
  121.                                  * on some pages. e.g.: html, body { height: 100% }
  122.                                  */
  123.                                 else if (scrollHeight > windowHeight &&
  124.                                                 (body.offsetHeight <= windowHeight ||
  125.                                                  html.offsetHeight <= windowHeight)) {
  126.  
  127.                                         // DOMChange (throttle): fix height
  128.                                         var pending = false;
  129.                                         var refresh = function () {
  130.                                                 if (!pending && html.scrollHeight != document.height) {
  131.                                                         pending = true; // add a new pending action
  132.                                                         setTimeout(function () {
  133.                                                                 html.style.height = document.height + 'px';
  134.                                                                 pending = false;
  135.                                                         }, 500); // act rarely to stay fast
  136.                                                 }
  137.                                         };
  138.                                         html.style.height = 'auto';
  139.                                         setTimeout(refresh, 10);
  140.  
  141.                                         var config = {
  142.                                                 attributes: true,
  143.                                                 childList: true,
  144.                                                 characterData: false
  145.                                         };
  146.  
  147.                                         observer = new MutationObserver(refresh);
  148.                                         observer.observe(body, config);
  149.  
  150.                                         // clearfix
  151.                                         if (root.offsetHeight <= windowHeight) {
  152.                                                 var underlay = document.createElement("div");
  153.                                                 underlay.style.clear = "both";
  154.                                                 body.appendChild(underlay);
  155.                                         }
  156.                                 }
  157.  
  158.                                 // gmail performance fix
  159.                                 if (document.URL.indexOf("mail.google.com") > -1) {
  160.                                         var s = document.createElement("style");
  161.                                         s.innerHTML = ".iu { visibility: hidden }";
  162.                                         (document.getElementsByTagName("head")[0] || html).appendChild(s);
  163.                                 }
  164.                                 // facebook better home timeline performance
  165.                                 // all the HTML resized images make rendering CPU intensive
  166.                                 else if (document.URL.indexOf("www.facebook.com") > -1) {
  167.                                         var home_stream = document.getElementById("home_stream");
  168.                                         home_stream && (home_stream.style.webkitTransform = "translateZ(0)");
  169.                                 }
  170.                                 // disable fixed background
  171.                                 if (!options.fixedBackground && !isExcluded) {
  172.                                         body.style.backgroundAttachment = "scroll";
  173.                                         html.style.backgroundAttachment = "scroll";
  174.                                 }
  175.                         }
  176.  
  177.  
  178.                         /************************************************
  179.                          * SCROLLING
  180.                          ************************************************/
  181.  
  182.                         var que = [];
  183.                         var pending = false;
  184.                         var lastScroll = +new Date;
  185.  
  186.                         /**
  187.                          * Pushes scroll actions to the scrolling queue.
  188.                          */
  189.                         function scrollArray(elem, left, top, delay) {
  190.  
  191.                                 delay || (delay = 1000);
  192.                                 directionCheck(left, top);
  193.  
  194.                                 if (options.accelerationMax != 1) {
  195.                                         var now = +new Date;
  196.                                         var elapsed = now - lastScroll;
  197.                                         if (elapsed < options.accelerationDelta) {
  198.                                                 var factor = (1 + (30 / elapsed)) / 2;
  199.                                                 if (factor > 1) {
  200.                                                         factor = Math.min(factor, options.accelerationMax);
  201.                                                         left *= factor;
  202.                                                         top  *= factor;
  203.                                                 }
  204.                                         }
  205.                                         lastScroll = +new Date;
  206.                                 }
  207.  
  208.                                 // push a scroll command
  209.                                 que.push({
  210.                                         x: left,
  211.                                         y: top,
  212.                                         lastX: (left < 0) ? 0.99 : -0.99,
  213.                                         lastY: (top  < 0) ? 0.99 : -0.99,
  214.                                         start: +new Date
  215.                                 });
  216.  
  217.                                 // don't act if there's a pending queue
  218.                                 if (pending) {
  219.                                         return;
  220.                                 }
  221.  
  222.                                 var scrollWindow = (elem === document.body);
  223.  
  224.                                 var step = function (time) {
  225.  
  226.                                         var now = +new Date;
  227.                                         var scrollX = 0;
  228.                                         var scrollY = 0;
  229.  
  230.                                         for (var i = 0; i < que.length; i++) {
  231.  
  232.                                                 var item = que[i];
  233.                                                 var elapsed  = now - item.start;
  234.                                                 var finished = (elapsed >= options.animationTime);
  235.  
  236.                                                 // scroll position: [0, 1]
  237.                                                 var position = (finished) ? 1 : elapsed / options.animationTime;
  238.  
  239.                                                 // easing [optional]
  240.                                                 if (options.pulseAlgorithm) {
  241.                                                         position = pulse(position);
  242.                                                 }
  243.  
  244.                                                 // only need the difference
  245.                                                 var x = (item.x * position - item.lastX) >> 0;
  246.                                                 var y = (item.y * position - item.lastY) >> 0;
  247.  
  248.                                                 // add this to the total scrolling
  249.                                                 scrollX += x;
  250.                                                 scrollY += y;
  251.  
  252.                                                 // update last values
  253.                                                 item.lastX += x;
  254.                                                 item.lastY += y;
  255.  
  256.                                                 // delete and step back if it's over
  257.                                                 if (finished) {
  258.                                                         que.splice(i, 1); i--;
  259.                                                 }
  260.                                         }
  261.  
  262.                                         // scroll left and top
  263.                                         if (scrollWindow) {
  264.                                                 window.scrollBy(scrollX, scrollY);
  265.                                         }
  266.                                         else {
  267.                                                 if (scrollX) elem.scrollLeft += scrollX;
  268.                                                 if (scrollY) elem.scrollTop  += scrollY;
  269.                                         }
  270.  
  271.                                         // clean up if there's nothing left to do
  272.                                         if (!left && !top) {
  273.                                                 que = [];
  274.                                         }
  275.  
  276.                                         if (que.length) {
  277.                                                 requestFrame(step, elem, (delay / options.frameRate + 1));
  278.                                         } else {
  279.                                                 pending = false;
  280.                                         }
  281.                                 };
  282.  
  283.                                 // start a new queue of actions
  284.                                 requestFrame(step, elem, 0);
  285.                                 pending = true;
  286.                         }
  287.  
  288.  
  289.                         /***********************************************
  290.                          * EVENTS
  291.                          ***********************************************/
  292.  
  293.                         /**
  294.                          * Mouse wheel handler.
  295.                          * @param {Object} event
  296.                          */
  297.                         function wheel(event) {
  298.  
  299.                                 if (!initDone) {
  300.                                         init();
  301.                                 }
  302.  
  303.                                 var target = event.target;
  304.                                 var overflowing = overflowingAncestor(target);
  305.  
  306.                                 // use default if there's no overflowing
  307.                                 // element or default action is prevented
  308.                                 if (!overflowing || event.defaultPrevented ||
  309.                                         isNodeName(activeElement, "embed") ||
  310.                                    (isNodeName(target, "embed") && /\.pdf/i.test(target.src))) {
  311.                                         return true;
  312.                                 }
  313.  
  314.                                 var deltaX = event.wheelDeltaX || 0;
  315.                                 var deltaY = event.wheelDeltaY || 0;
  316.  
  317.                                 // use wheelDelta if deltaX/Y is not available
  318.                                 if (!deltaX && !deltaY) {
  319.                                         deltaY = event.wheelDelta || 0;
  320.                                 }
  321.  
  322.                                 // check if it's a touchpad scroll that should be ignored
  323.                                 if (!options.touchpadSupport && isTouchpad(deltaY)) {
  324.                                         return true;
  325.                                 }
  326.  
  327.                                 // scale by step size
  328.                                 // delta is 120 most of the time
  329.                                 // synaptics seems to send 1 sometimes
  330.                                 if (Math.abs(deltaX) > 1.2) {
  331.                                         deltaX *= options.stepSize / 120;
  332.                                 }
  333.                                 if (Math.abs(deltaY) > 1.2) {
  334.                                         deltaY *= options.stepSize / 120;
  335.                                 }
  336.  
  337.                                 scrollArray(overflowing, -deltaX, -deltaY);
  338.                                 event.preventDefault();
  339.                         }
  340.  
  341.                         /**
  342.                          * Keydown event handler.
  343.                          * @param {Object} event
  344.                          */
  345.                         function keydown(event) {
  346.  
  347.                                 var target   = event.target;
  348.                                 var modifier = event.ctrlKey || event.altKey || event.metaKey ||
  349.                                                           (event.shiftKey && event.keyCode !== key.spacebar);
  350.  
  351.                                 // do nothing if user is editing text
  352.                                 // or using a modifier key (except shift)
  353.                                 // or in a dropdown
  354.                                 if ( /input|textarea|select|embed/i.test(target.nodeName) ||
  355.                                          target.isContentEditable ||
  356.                                          event.defaultPrevented   ||
  357.                                          modifier ) {
  358.                                   return true;
  359.                                 }
  360.                                 // spacebar should trigger button press
  361.                                 if (isNodeName(target, "button") &&
  362.                                         event.keyCode === key.spacebar) {
  363.                                   return true;
  364.                                 }
  365.  
  366.                                 var shift, x = 0, y = 0;
  367.                                 var elem = overflowingAncestor(activeElement);
  368.                                 var clientHeight = elem.clientHeight;
  369.  
  370.                                 if (elem == document.body) {
  371.                                         clientHeight = window.innerHeight;
  372.                                 }
  373.  
  374.                                 switch (event.keyCode) {
  375.                                         case key.up:
  376.                                                 y = -options.arrowScroll;
  377.                                                 break;
  378.                                         case key.down:
  379.                                                 y = options.arrowScroll;
  380.                                                 break;
  381.                                         case key.spacebar: // (+ shift)
  382.                                                 shift = event.shiftKey ? 1 : -1;
  383.                                                 y = -shift * clientHeight * 0.9;
  384.                                                 break;
  385.                                         case key.pageup:
  386.                                                 y = -clientHeight * 0.9;
  387.                                                 break;
  388.                                         case key.pagedown:
  389.                                                 y = clientHeight * 0.9;
  390.                                                 break;
  391.                                         case key.home:
  392.                                                 y = -elem.scrollTop;
  393.                                                 break;
  394.                                         case key.end:
  395.                                                 var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
  396.                                                 y = (damt > 0) ? damt+10 : 0;
  397.                                                 break;
  398.                                         case key.left:
  399.                                                 x = -options.arrowScroll;
  400.                                                 break;
  401.                                         case key.right:
  402.                                                 x = options.arrowScroll;
  403.                                                 break;
  404.                                         default:
  405.                                                 return true; // a key we don't care about
  406.                                 }
  407.  
  408.                                 scrollArray(elem, x, y);
  409.                                 event.preventDefault();
  410.                         }
  411.  
  412.                         /**
  413.                          * Mousedown event only for updating activeElement
  414.                          */
  415.                         function mousedown(event) {
  416.                                 activeElement = event.target;
  417.                         }
  418.  
  419.  
  420.                         /***********************************************
  421.                          * OVERFLOW
  422.                          ***********************************************/
  423.  
  424.                         var cache = {}; // cleared out every once in while
  425.                         setInterval(function () { cache = {}; }, 10 * 1000);
  426.  
  427.                         var uniqueID = (function () {
  428.                                 var i = 0;
  429.                                 return function (el) {
  430.                                         return el.uniqueID || (el.uniqueID = i++);
  431.                                 };
  432.                         })();
  433.  
  434.                         function setCache(elems, overflowing) {
  435.                                 for (var i = elems.length; i--;)
  436.                                         cache[uniqueID(elems[i])] = overflowing;
  437.                                 return overflowing;
  438.                         }
  439.  
  440.                         function overflowingAncestor(el) {
  441.                                 var elems = [];
  442.                                 var rootScrollHeight = root.scrollHeight;
  443.                                 do {
  444.                                         var cached = cache[uniqueID(el)];
  445.                                         if (cached) {
  446.                                                 return setCache(elems, cached);
  447.                                         }
  448.                                         elems.push(el);
  449.                                         if (rootScrollHeight === el.scrollHeight) {
  450.                                                 if (!isFrame || root.clientHeight + 10 < rootScrollHeight) {
  451.                                                         return setCache(elems, document.body); // scrolling root in WebKit
  452.                                                 }
  453.                                         } else if (el.clientHeight + 10 < el.scrollHeight) {
  454.                                                 overflow = getComputedStyle(el, "").getPropertyValue("overflow-y");
  455.                                                 if (overflow === "scroll" || overflow === "auto") {
  456.                                                         return setCache(elems, el);
  457.                                                 }
  458.                                         }
  459.                                 } while (el = el.parentNode);
  460.                         }
  461.  
  462.  
  463.                         /***********************************************
  464.                          * HELPERS
  465.                          ***********************************************/
  466.  
  467.                         function addEvent(type, fn, bubble) {
  468.                                 window.addEventListener(type, fn, (bubble||false));
  469.                         }
  470.  
  471.                         function removeEvent(type, fn, bubble) {
  472.                                 window.removeEventListener(type, fn, (bubble||false));
  473.                         }
  474.  
  475.                         function isNodeName(el, tag) {
  476.                                 return (el.nodeName||"").toLowerCase() === tag.toLowerCase();
  477.                         }
  478.  
  479.                         function directionCheck(x, y) {
  480.                                 x = (x > 0) ? 1 : -1;
  481.                                 y = (y > 0) ? 1 : -1;
  482.                                 if (direction.x !== x || direction.y !== y) {
  483.                                         direction.x = x;
  484.                                         direction.y = y;
  485.                                         que = [];
  486.                                         lastScroll = 0;
  487.                                 }
  488.                         }
  489.  
  490.                         var deltaBufferTimer;
  491.  
  492.                         function isTouchpad(deltaY) {
  493.                                 if (!deltaY) return;
  494.                                 deltaY = Math.abs(deltaY)
  495.                                 deltaBuffer.push(deltaY);
  496.                                 deltaBuffer.shift();
  497.                                 clearTimeout(deltaBufferTimer);
  498.                                 var allEquals    = (deltaBuffer[0] == deltaBuffer[1] &&
  499.                                                                         deltaBuffer[1] == deltaBuffer[2]);
  500.                                 var allDivisable = (isDivisible(deltaBuffer[0], 120) &&
  501.                                                                         isDivisible(deltaBuffer[1], 120) &&
  502.                                                                         isDivisible(deltaBuffer[2], 120));
  503.                                 return !(allEquals || allDivisable);
  504.                         }
  505.  
  506.                         function isDivisible(n, divisor) {
  507.                                 return (Math.floor(n / divisor) == n / divisor);
  508.                         }
  509.  
  510.                         var requestFrame = (function () {
  511.                                   return  window.requestAnimationFrame       ||
  512.                                                   window.webkitRequestAnimationFrame ||
  513.                                                   function (callback, element, delay) {
  514.                                                           window.setTimeout(callback, delay || (1000/60));
  515.                                                   };
  516.                         })();
  517.  
  518.                         var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
  519.  
  520.  
  521.                         /***********************************************
  522.                          * PULSE
  523.                          ***********************************************/
  524.  
  525.                         /**
  526.                          * Viscous fluid with a pulse for part and decay for the rest.
  527.                          * - Applies a fixed force over an interval (a damped acceleration), and
  528.                          * - Lets the exponential bleed away the velocity over a longer interval
  529.                          * - Michael Herf, http://stereopsis.com/stopping/
  530.                          */
  531.                         function pulse_(x) {
  532.                                 var val, start, expx;
  533.                                 // test
  534.                                 x = x * options.pulseScale;
  535.                                 if (x < 1) { // acceleartion
  536.                                         val = x - (1 - Math.exp(-x));
  537.                                 } else {     // tail
  538.                                         // the previous animation ended here:
  539.                                         start = Math.exp(-1);
  540.                                         // simple viscous drag
  541.                                         x -= 1;
  542.                                         expx = 1 - Math.exp(-x);
  543.                                         val = start + (expx * (1 - start));
  544.                                 }
  545.                                 return val * options.pulseNormalize;
  546.                         }
  547.  
  548.                         function pulse(x) {
  549.                                 if (x >= 1) return 1;
  550.                                 if (x <= 0) return 0;
  551.  
  552.                                 if (options.pulseNormalize == 1) {
  553.                                         options.pulseNormalize /= pulse_(1);
  554.                                 }
  555.                                 return pulse_(x);
  556.                         }
  557.  
  558.                         addEvent("mousedown", mousedown);
  559.                         addEvent("mousewheel", wheel);
  560.                         addEvent("load", init);
  561.  
  562.                 }
  563.  
  564.         });
  565. })(jQuery);

Paste is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.