Smoothscroll

Smooth scrolling on pages using javascript and jquery

当前为 2016-11-23 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name Smoothscroll
// @include     http*
// @author       Creec Winceptor
// @description  Smooth scrolling on pages using javascript and jquery
// @namespace https://greasyfork.org/users/3167
// @run-at document-load
// @grant    none
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_registerMenuCommand
// @version 2.4
// ==/UserScript==

if (window.top != window.self)  //don't run on frames or iframes
    return;

//DEFAULT SETTINGS HERE 
//DO NOT CHANGE ANYTHING HERE ANYMORE, USE SCRIPT COMMANDS -> CONFIGURE SMOOTHSCROLL


//Smoothness factor value (how strong the smoothing effect is)
//values: 1-(infinite) (default 1.00)
var smoothness = 1;

//Scroll sensitivity
//values: anything? (default 1.00)
var sensitivity = 1;

//Acceleration sensitivity
//values: anything? (default 1.50)
var acceleration = 1;

//Refreshrate setting
//values: 30-144 (default = 60/72/120/144 = same as your monitor hz)
var refreshrate = 60;


//Alternative scrolling multiplier
//values: true/false (try to set this to true if scrolling is too slow/doesn't work)
var alternative_sensitivity_multiplier = false;


//CODE STARTS HERE

var DEBUG = false;

var WEBKIT = false;

//console.log("Loading smoothscroll...");

var baserefreshrate = 60; //DO NOT CHANGE THIS EVER
if (smoothness>10)
{
	smoothness = 10;
}

if (refreshrate <= 30 || refreshrate>144)
{
	refreshrate = 144;
}

function InitSmoothscroll()
{
  
  LoadConfig();

  InitConfigmenu();

var startposition = false;
var targetposition = 0;
var position = 0;

//var scrollfocus = //ss$('body');
var scrollfocus = document.body;
var mousemoved = true;
  
function hasScrollBarVisible(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";
	
	var scrollbar = scrollbar1 || scrollbar2;
 
  return scrollbar;
}


function hasscrollbars(scrollfocus)
{
	var hasvisiblescrollbars = hasScrollBarVisible(scrollfocus);
	return hasvisiblescrollbars;
	
	/*
	var parentelement = //ss$(scrollfocus).parent();
	if ( //ss$(parentelement))
	{
		if (//ss$(parentelement).is("textarea") || //ss$(scrollfocus).is("textarea") || //ss$(parentelement).is("article") || //ss$(parentelement).is("article"))
		{
			return true;
		}
		else
		{
			if (//ss$(parentelement).hasClass( "yt-scrollbar" ) || //ss$(scrollfocus).hasClass( "yt-scrollbar" ))
			{
				return true;
			}
			return hasvisiblescrollbars;
		}
	}
	else
	{
		return hasvisiblescrollbars;
	}
	return false;
	*/
}

var scroll_timeout = null;

function UpdatePosition(element)
{
	//gameLoop();
	var interpolation = 3;
  
	var animationduration = Math.round(1000/(refreshrate*interpolation));
  
  	var relativeratio = Math.round( ( 0.01/Math.pow(3,smoothness)/interpolation*refreshrate/baserefreshrate )*1000000)/1000000;
	
	var positiondelta = scrollpositiondelta(element);
	  
	var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
  	var rounddelta = Math.ceil(smoothdelta);
  	
	//var smoothdelta = positiondelta*relativeratio;
  
	if (positiondelta<0)
	{
		smoothdelta = smoothdelta*(-1);
      	rounddelta = rounddelta*(-1);
	}

	if (Math.abs( rounddelta ) <= 1 )
	{	
	
      if (Math.abs( positiondelta ) > 1 )
      {
      	
      	scroll_timeout = setTimeout(function() {
			element.scrollTop = element.scrollTop + rounddelta;
			scrollpositiondelta(element, positiondelta - rounddelta);
			UpdatePosition(element);
		  }, Math.abs(animationduration/smoothdelta) );
      
      }
      else
      {
          scroll_timeout = setTimeout(function() {
              element.scrollTop = element.scrollTop + rounddelta;
              scrollpositiondelta(element, 0);
            }, Math.abs(animationduration/smoothdelta));

      }
		


	}
	else
	{
		  scroll_timeout = setTimeout(function() {
			element.scrollTop = element.scrollTop + rounddelta;
			scrollpositiondelta(element, positiondelta - rounddelta);
			UpdatePosition(element);
		  }, animationduration);
	}
}


 function MouseScroll (e) {

   	var mul = 1;
	if (!WEBKIT || alternative_sensitivity_multiplier)
		mul = 40;
   	var x = e.deltaX*mul;
   	var y = e.deltaY*mul;
   
   	//if (mousemoved)
    //{
      scrollfocus = UpdateFocus(x,y);
      //mousemoved = false;
    //}
   
	 var positiondelta = 0;
	 var lastscrolltop = 0;

	 var rolled = y;
	 	
	 	if (!canscroll(scrollfocus, rolled))
		{
			if (scrollfocus != document.documentElement)	
			{
				scrollfocus = UpdateFocus(x,y);
              return false;
			}
			else
			{
              	
              	//console.log("true");
				return false;
			}
		}
	 	else
		{
          	if (e.defaultPrevented)
            {
              return true;
            }
          	else
            {
              e.preventDefault();
            }
			
		}
   	 positiondelta = scrollpositiondelta(scrollfocus);
   
	 var direction = rolled/Math.abs(rolled);
	 
	 var positiondeltadelta = Math.round(rolled*sensitivity + Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.2);
	 
	 positiondelta = positiondelta*1 + positiondeltadelta*1;
	 
  	 scrollpositiondelta(scrollfocus, positiondelta)

	 clearTimeout(scroll_timeout);
	 
	 UpdatePosition(scrollfocus);
   
   		//console.log(e);
	 
	 return true;
 }

 function canscroll(element, dir)
{
  	if (dir>0)
    {
      dir = 1;
    }
  	if (dir<0)
    {
      dir = -1;
    }
  	var checkradius = 3; //pixels to try scrolling
  
  	var canscroll0 = false;

	var scrollable = element;

	var lastscrolltop = scrollable.scrollTop;

	scrollable.scrollTop = lastscrolltop+dir*checkradius;

	if (scrollable.scrollTop!=lastscrolltop)
	{
		canscroll0 = true;
	}

	scrollable.scrollTop = lastscrolltop;

	return canscroll0;
}
  
  
function scrollpositiondelta(element, newdelta)
{
  	//var target = //ss$(element);
	var target = element;
  	var delta = 0;
  	if (newdelta!=undefined)
    {
      //console.log(dir);
      var dir = 0;
      if (newdelta>0)
      {
        dir = 1;
      }
      if (newdelta<0)
      {
        dir = -1;
      }
	  target.setAttribute("positiondelta", newdelta );

      delta = newdelta;
    }
	else
    {
		var olddelta = target.getAttribute("positiondelta");
      if (olddelta!=undefined)
      {
      	delta = olddelta;
      }
    }
  	return delta*1;
}

function UpdateFocus(x,y) {
	if (scrollfocus)
      {
        //scrollpositiondelta(scrollfocus, 0);
        //ss$(scrollfocus).stop();
      }
	var dir = y;
	 	var nodelist = document.querySelectorAll( ":hover" );
	 	if (WEBKIT)
        {
        	//scrollfocus = //ss$('body');
			scrollfocus = document.body;
        }
  		else
        {
            //scrollfocus = //ss$('html');
			scrollfocus = document.documentElement;
        }
  		
	 	for (var i = nodelist.length-1; i >= 0 ; i--) { 
			  var newfocus = nodelist[i];
				if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
				{
					scrollfocus = newfocus;
					return newfocus;
				}
 		}

	 return scrollfocus;
 }
	
  /*ss$('html').bind({
    
	mousemove: function(e) {
      mousemoved = true;
    },
    
    mousedown: function(e) {
      if (DEBUG)
      {
        console.log(scrollfocus);
      }
      if (scrollfocus)
      {
        scrollpositiondelta(scrollfocus, 0);
        ////ss$(scrollfocus).stop();
      }
      scrollfocus = UpdateFocus(0,0);
      //console.log("click");
    }
  });
	*/
	
  
document.documentElement.addEventListener("wheel", function(e){
    MouseScroll(e);
	mousemoved = true;
  //console.log("scrolling");
});
  

  //WEBKIT = 'webkitRequestAnimationFrame' in window;
  WEBKIT = document.compatMode == 'CSS1Compat' || document.compatMode == "BackCompat";
  
  //console.log("window: " + window);
  console.log("Smoothscroll loaded! Webkit: " + WEBKIT);
  
  $smoothscroll$ = true;
}

function LoadConfig()
{
  smoothness = GM_getValue( 'smoothness', smoothness );
  sensitivity = GM_getValue( 'sensitivity', sensitivity );
  acceleration = GM_getValue( 'acceleration', acceleration );
  refreshrate = GM_getValue( 'refreshrate', refreshrate );
  //alternative_sesitivity_multiplier = GM_getValue( 'alternative_sesitivity_multiplier', alternative_sesitivity_multiplier );
  //console.log("Config for smoothscroll loaded!")
}

function SaveConfig()
{
  GM_setValue( 'smoothness', document.getElementById('ss-smoothness').value)
  GM_setValue( 'sensitivity', document.getElementById('ss-sensitivity').value)
  GM_setValue( 'acceleration', document.getElementById('ss-acceleration').value)
  GM_setValue( 'refreshrate', document.getElementById('ss-refreshrate').value)
  //console.log(document.getElementById('ss-alternative_sesitivity_multiplier').checked)
  console.log("Config for smoothscroll saved!")
}

function CloseConfig()
{
 	var configbar = document.getElementById("ss-configbar");
  configbar.style.display = 'none';  
}

function InitConfigmenu()
{
  	//console.log("Initiating smoothscroll config...");
    var configbar = document.createElement('div');
    configbar.setAttribute("id","ss-configbar");
  
  //<tr><td>Sensitivity</td><td><input type="number" id="ss-sensitivity" min="0" max="100" value="' + sensitivity + '"></td><td> Scroll sensitivity (duh)</td></tr>
 	
  	configbar.innerHTML = '<div style="display:block; width: 100%; height: auto; border: 0px solid #aaaaaa; background-color: grey;">Config page for smoothscroll (refresh page for changes to apply!) Made by: Creec Winceptor</div><div id="ss-config" style="margin:3px; display:block; width: auto; height: auto; border: 0px solid #554433;"><table style="width:auto;"><tr><td>Smoothness</td><td><input type="number" id="ss-smoothness" min="0" max="10" value="' + smoothness + '"></td><td> Smoothness factor value (default 1.00)</td></tr><tr><td>Sensitivity</td><td><input type="number" id="ss-sensitivity" min="0" max="100" value="' + sensitivity + '"></td><td> Scroll sensitivity (default 1.00)</td></tr><tr><td>Acceleration</td><td><input type="number" id="ss-acceleration" min="0" max="100" value="' + acceleration + '"></td><td> Acceleration of continuous scroll action (default 1.00)</td></tr><tr><td>Refreshrate</td><td><input type="number" id="ss-refreshrate" min="1" max="100" value="' + refreshrate + '"></td><td>Refreshrate of scrollanimation (60Hz default)</td></tr></table></div><div style="width: 100%; height: auto; text-align: center; background-color: grey;"><input id="ss-save" type="button" value="Save config" style="width: 44%; height: auto; border: 0px solid #aaaaaa; margin: 3px"/><input id="ss-close" type="button" value="Close config" style="width: 44%; height: auto; border: 0px solid #aaaaaa; margin: 3px"/><div>';
  	
  	
    var configparent = document.getElementsByTagName("body")[0];
  	configbar.style.width = '100%';  
  	configbar.style.display = 'none';  
  	configbar.style.position = 'absolute';
	configbar.style.zIndex = '9999';
  	configbar.style.backgroundColor = 'white';
  
  	configparent.insertBefore(configbar, configparent.childNodes[0]);
  	
  	document.getElementById("ss-close").onclick = function() {CloseConfig()};
  
  	document.getElementById("ss-save").onclick = function() {SaveConfig()};
}

function ConfigSmoothscroll()
{
  if (typeof $smoothscroll$ == 'undefined'){
    alert("Smoothscroll is not running properly on this page!");
    return;
  }

  var configbar = document.getElementById("ss-configbar");
  configbar.style.display = 'block';  
  //ss$("html, body").animate({ scrollTop: 0 }, "slow");
  //console.log("opening config...");
}

if (typeof $smoothscroll$ == 'undefined'){
	//console.log("Initiating smoothscroll...");
	InitSmoothscroll();	
	GM_registerMenuCommand("Configurate smoothscroll", ConfigSmoothscroll);
}
else
{
  console.log("Smoothscroll already loaded!");
}