Smoothscroll

Smooth scrolling on pages using javascript

Versão de: 08/03/2018. Veja: a última versão.

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Advertisement:

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

Advertisement:

// ==UserScript==
// @name Smoothscroll
// @author       Creec Winceptor
// @description  Smooth scrolling on pages using javascript
// @namespace https://greasyfork.org/users/3167
// @include     *
// @version 5.2
// ==/UserScript==

var Smoothscroll = {};

//dev
Smoothscroll.Debug = false;
Smoothscroll.Refreshrate = 60;

//settings
Smoothscroll.Smoothness = 0.5;
Smoothscroll.Acceleration = 0.5;

//scrolling and animation
function Timeout(element, newtimeout)
{
  if (newtimeout!=undefined)
  {
    var oldtimeout = element.ScrollTimeout;
    if (oldtimeout!=undefined)
    {
      clearTimeout(oldtimeout);
    }
    element.ScrollTimeout = newtimeout;
    return newtimeout;
  }
	else
  {
    var oldtimeout = element.ScrollTimeout;
    if (oldtimeout!=undefined)
    {
      return oldtimeout;
    }
    return null;
  }
}
function ScrollSubpixels(element, newvalue)
{
  if (newvalue!=undefined)
  {
    element.scrollsubpixels = newvalue;
    return newvalue;
  }
	else
  {
    var olddelta = element.scrollsubpixels;
    if (olddelta!=undefined)
    {
      return olddelta;
    }
    return 0;
  }
}
function ScrollPixels(element, newvalue)
{
  if (newvalue!=undefined)
  {
    element.scrollpixels = newvalue;
    
    ScrollSubpixels(element, 0);
    
    return newvalue;
  }
	else
  {
    var olddelta = element.scrollpixels;
    if (olddelta!=undefined)
    {
      return olddelta;
    }
    return 0;
  }
}
function AnimateScroll(target) {
  
  var updaterate = Math.floor(1000/(Smoothscroll.Refreshrate));
  
  var scrollsubpixels = ScrollSubpixels(target);
  var scrollpixels = ScrollPixels(target);

  var scrolldirection = 0;
  if (scrollpixels>0) {
    scrolldirection = 1;
  }
  if (scrollpixels<0) {
    scrolldirection = -1;
  }

  var scrollratio = 1-Math.pow( Smoothscroll.Refreshrate, -1/(Smoothscroll.Refreshrate*Smoothscroll.Smoothness));
  
  var scrollrate = scrollpixels*scrollratio;
  
  if (Math.abs(scrollpixels)>1) {
    
    var fullscrolls = Math.floor(Math.abs(scrollrate))*scrolldirection;
    var scrollsubpixelsadded = scrollrate - fullscrolls;

    var additionalscrolls = Math.floor(Math.abs(scrollsubpixels + scrollsubpixelsadded))*scrolldirection;
    var scrollsubpixelsleft = scrollsubpixels + scrollsubpixelsadded - additionalscrolls;

    ScrollPixels(target, scrollpixels-fullscrolls-additionalscrolls);
    ScrollSubpixels(target, scrollsubpixelsleft);
	
	  target.scrollTop += fullscrolls + additionalscrolls;

    Timeout(target, setTimeout(function() {

      AnimateScroll(target);
    }, updaterate));
  } else
  {
    ScrollPixels(target, 0);
  }
  
}

Smoothscroll.Stop = function(target) {
	if (target) {
		ScrollPixels(target, null);
		Timeout(target, null);
	}
}
Smoothscroll.Start = function(target, scrollamount) {
	if (target) {
		var scrollpixels = ScrollPixels(target);
		
		ScrollPixels(target, scrollamount);
		
		AnimateScroll(target);
	}
}

if (typeof module !== 'undefined') {
	module.exports = Smoothscroll;
}



//scroll target detection
function IsScrollable(element, dir)
{
	var checkradius = 2; //pixels to try scrolling

	if (dir>0)
	{
		dir = checkradius;
	}
	if (dir<0)
	{
		dir = -checkradius;
	}

	var originalscroll = element.scrollTop;
	var testscroll = Math.round(originalscroll + dir);
	element.scrollTop = testscroll;

	var scrollable = Math.round(element.scrollTop)==testscroll;
	element.scrollTop = originalscroll;

	return scrollable;
}
function HasScrollbars(element)
{
	//return (document.documentElement.scrollHeight !== document.documentElement.clientHeight);

	// Get the computed style of the body element
	var cStyle = element.currentStyle||window.getComputedStyle(element, "");

	// Check the overflow and overflowY properties for "auto" and "visible" values
	var scrollbar1 = cStyle.overflow == "scroll" || cStyle.overflowY == "scroll";
	var scrollbar2 = cStyle.overflow == "auto" || cStyle.overflowY == "auto";

	//body or html always have scrollbars
	var scrollbar3 = element==document.body || element==document.documentElement;

	return scrollbar1 || scrollbar2 || scrollbar3;
}
function GetTarget(e) {
  var direction = e.deltaY;
  var nodes = e.path;
  
  for (var i=0; i<nodes.length; i++) { 
    var node = nodes[i];
    if (IsScrollable(node, direction) && HasScrollbars(node))
    {
      if (Smoothscroll.Debug) {
        console.log("scrollbar: ");
        console.log(node);
      }
      return node;
    }
  }

  return null;
}



//mouse event scroll handlers
function StopScroll(e) {
  var nodes = e.path;
  
  for (var i=0; i<nodes.length; i++) { 
    var node = nodes[i];
    Smoothscroll.Stop(node);
  }
}
function StartScroll(e, target) {

  if (e.defaultPrevented)
  {
    return true;
  }
  else
  {
	var direction = e.deltaY;

	var scrollpixels = ScrollPixels(target);

	var accelerationratio = Math.sqrt(Math.abs(scrollpixels/direction*Smoothscroll.Acceleration));

	var acceleration = Math.round(direction*accelerationratio);

	Smoothscroll.Start(target, scrollpixels + direction + acceleration);

    e.preventDefault();
  }
}



//mouse event call handlers
function WheelEvent(e) {
  var target = GetTarget(e);
  
  if (target) {
    StartScroll(e, target);
  }
}
function ClickEvent(e) {
  StopScroll(e);
}



//init function
function Init()
{
  if (window.Smoothscroll) {
    console.log("Smoothscroll: already loaded");
    return null;
  }
  
  if (window.top != window.self) {
    console.log("Smoothscroll: ignoring iframe");
    return null;
  }
  
  document.documentElement.addEventListener("wheel", function(e){
    WheelEvent(e);
    
    if (Smoothscroll.Debug) {
      console.log(e);
    }
  });

  document.documentElement.addEventListener("mousedown", function(e){
    ClickEvent(e);
    
    if (Smoothscroll.Debug) {
      console.log(e);
    }
  });
  
  console.log("Smoothscroll: loaded");
  window.Smoothscroll = Smoothscroll;
}
Init();