Smoothscroll

Smooth scrolling on pages using javascript and jquery

Устаревшая версия за 04.05.2016. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или 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-idle
// @grant    GM_info
// @grant         unsafeWindow
// @version 0.0.1.20160504232712
// ==/UserScript==






//SETTINGS HERE

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


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


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


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


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






var DEBUG = false;

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



if (smoothness>100)
{
	smoothness = 100;
}

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

var animationduration = Math.round(1000/refreshrate);
//var relativeratio = Math.round(51-smoothness/2)/100;
var relativeratio = Math.round(1/(1+smoothness)*100)/100;
//var relativeratio = relativeratio;



var lastLoop = new Date;
//var lastrefreshrate = 0;
function gameLoop() { 
	var thisLoop = new Date;
    var refreshrate0 = 1000 / (thisLoop - lastLoop + 1);
    lastLoop = thisLoop;
	
	refreshrate = refreshrate + (refreshrate0-refreshrate)*0.01;
	refreshrate = Math.round(refreshrate);
	
	if (DEBUG)
	{
		console.log(refreshrate);
	}
	
	animationduration = Math.round(1000/(refreshrate));
	//var relativeratio = Math.round(51-smoothness/2)/100;
	relativeratio = Math.round(1/(1+smoothness*refreshrate/baserefreshrate)*100)/100;
}
gameLoop();


function InitSmoothscroll()
{

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

var scrollfocus = $('body');
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);
	var parentelement = $(scrollfocus).parent();
	if ( $(parentelement))
	{
		//if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea"))
		if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea") || $(parentelement).is("article") || $(parentelement).is("article"))
		{
			return true;
		}
		else
		{
			if ($(parentelement).hasClass( "yt-scrollbar" ) || $(scrollfocus).hasClass( "yt-scrollbar" ))
			{
				return true;
			}
			return hasvisiblescrollbars;
		}
	}
	else
	{
		//scrollfocus = $('body');
		//maxposition = $(scrollfocus).height();
		return hasvisiblescrollbars;
	}
	return false;
}

function UpdatePosition(element)
{
	gameLoop();
	
	var positiondelta = $(element)[0].getAttribute( "positiondelta" );
	//var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
	
	var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
	
	if (positiondelta<0)
	{
		smoothdelta = smoothdelta*(-1);
	}
	
	//var relative = position - $(element).scrollTop();
	//console.log("smoothdelta:" + smoothdelta);
	
	if (Math.abs( (positiondelta-smoothdelta)) <= 1 )
	{
		$(element).stop();
		$(element).animate({
			scrollTop: '+=' + Math.round(positiondelta)
		}, animationduration, "linear", function() {
			$(element).attr( "positiondelta",0 );
			$(element)[0].setAttribute( "positiondelta",0 );
			if (DEBUG)
			{
				$(element).css( "border", "1px solid red" );
			}
		});
	}
	else
	{
		
		$(element).stop();
		$(element).animate({
			scrollTop: '+=' + Math.round(smoothdelta)
		}, animationduration, "linear", function() {
			$(element).attr( "positiondelta",positiondelta-smoothdelta );
			$(element)[0].setAttribute("positiondelta",positiondelta-smoothdelta );
			UpdatePosition(element);
			if (DEBUG)
			{
				$(element).css( "border", "1px solid red" );
			}
		});
	}
}


 function MouseScroll (x,y,e) {
	 scrollfocus = UpdateFocus(x,y);
	
	 var positiondelta = 0;
	 var lastscrolltop = 0;

	 var parentelement = $(scrollfocus).parent();
	 if ( $(parentelement))
	 {
		 if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea"))
		 {
			 //return true;
		 }
		 else
		 {
			 if ( $(parentelement).height() < $(scrollfocus).height())
			 {
				 //maxposition = $(scrollfocus).height() - $(parentelement).height();
			 }
			 else
			 {
				 if ($(scrollfocus).height()==0)
				 {
					 //scrollfocus = $('body');
					 //maxposition = $(scrollfocus).height();
				 }

				 //scrollfocus = $('body');
				 //return MouseScroll (event);
				 //return true;
			 }
		 }
	 }
	 else
	 {
		 scrollfocus = $('body');
		 //maxposition = $(scrollfocus).height();
	 }
	 
	 var rolled = y;
	 
	 //console.log("rolled: " + rolled);
	
	 //if ($(scrollfocus).data("positiondelta" )==undefined)
	 //$embellishment.data("embellishmentid",1)
	 if ($(scrollfocus)[0].getAttribute("positiondelta")==undefined)
		 
		 {
			 positiondelta = 0;
			 //console.log("positiondelta: undefined");
		 }
	 else
		 {
			 positiondelta = $(scrollfocus)[0].getAttribute("positiondelta");
			 //console.log("positiondelta: " + positiondelta);
		 }
	 positiondelta = positiondelta*1;
	 
	 	var lastscrolltop = $(scrollfocus).scrollTop();
	 	$(scrollfocus).scrollTop(lastscrolltop+rolled);
	 	if ($(scrollfocus).scrollTop()==lastscrolltop)
		{
			if (!$(scrollfocus).is("body"))
			{
				focus = parentelement;
				//focus = UpdateFocus(event);
				//return MouseScroll (event);
				//console.log("false");
				return false;
			}
			else
			{
				//console.log("true");
				return false;
			}
		}
	 	else
		{
			e.preventDefault();
		}
	    $(scrollfocus).scrollTop(lastscrolltop);
	 
	 var direction = rolled/Math.abs(rolled);
	 //var positiondeltadelta = rolled*sensitivity + Math.sqrt(Math.abs(positiondelta/rolled))*acceleration*rolled;
	 
	 //var positiondeltadelta = rolled*(sensitivity+Math.sqrt(Math.abs(positiondelta))*acceleration);
	 //
	 var positiondeltadelta = Math.round(rolled*sensitivity + Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.03/sensitivity);
	 
	 positiondelta = positiondelta + positiondeltadelta;
	
	 $(scrollfocus)[0].setAttribute("positiondelta",positiondelta );
	 
	 
	 UpdatePosition($(scrollfocus));
	 
	 //element.innerHTML = "";
	 //console.log("pos:" + position);
	 //event.preventDefault();
	 return true;
 }

 function canscroll(element, dir)
{
	var scrollable = $(element);
	var lastscrolltop = $(scrollable).scrollTop();
	$(scrollable).scrollTop(lastscrolltop+dir);
	if ($(scrollable).scrollTop()==lastscrolltop)
	{
		$(scrollable).scrollTop(lastscrolltop);
		return false;
	}
	else
	{
		$(scrollable).scrollTop(lastscrolltop);
		return true;
	}
	
}
function UpdateFocus(x,y) {
	 /*var dir = 0;
	 if ('wheelDelta' in event) {
		 dir = event.wheelDelta;
	 }
	 else {  // Firefox
		 // The measurement units of the detail and wheelDelta properties are different.
		 dir = event.detail*(-120);
	 }*/
	var dir = y;
	//console.log(dir);
	 //dir = dir*(-1);
	 //
	 	var nodelist = document.querySelectorAll( ":hover" );
		$(nodelist).stop();
	 	scrollfocus = $('body');
	 	for (var i = nodelist.length-1; i >= 0; i--) { 
				//var parent = nodelist[i-1];
			  var newfocus = nodelist[i];
				if (DEBUG)
				{
					$(newfocus).css( "border", "1px solid blue" );
					//var debugtimer = setTimeout(function(){ $(newfocus).css( "border", "0px solid white" ); }, 1000);
				}
				//if ($(newfocus).hasScrollBar3() && hasScrollBarVisible(newfocus) && canscroll(newfocus, dir) && hasscrollbars(newfocus))
				if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
				{
					scrollfocus = $(newfocus);
					return newfocus;
				}
 		}

	 return scrollfocus;
 }
	
		$('body').bind({
			/*
			 mousewheel: function(e) {
			if (DEBUG)
			{
				console.log(scrollfocus);
			}
			  console.log("scrolling");
			  MouseScroll(e.originalEvent);
		  },
		  */
			
		  mousedown: function(e) {
			 if (DEBUG)
			{
				console.log(scrollfocus);
			}
			  if (scrollfocus)
			{
			  $(scrollfocus)[0].setAttribute( "positiondelta",0 );
			  $(scrollfocus).stop();
			}
				//scrollfocus = UpdateFocus(e.originalEvent);
			  //console.log("click");
		  }
		});
//Init(window);

(function(window,document) {

    var prefix = "", _addEventListener, onwheel, support;

    // detect event model
    if ( window.addEventListener ) {
        _addEventListener = "addEventListener";
    } else {
        _addEventListener = "attachEvent";
        prefix = "on";
    }

    // detect available wheel event
    support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
              document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
              "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox

    window.addWheelListener = function( elem, callback, useCapture ) {
        _addWheelListener( elem, support, callback, useCapture );

        // handle MozMousePixelScroll in older Firefox
        if( support == "DOMMouseScroll" ) {
            _addWheelListener( elem, "MozMousePixelScroll", callback, useCapture );
        }
    };

    function _addWheelListener( elem, eventName, callback, useCapture ) {
        elem[ _addEventListener ]( prefix + eventName, support == "wheel" ? callback : function( originalEvent ) {
            !originalEvent && ( originalEvent = window.event );

            // create a normalized event object
            var event = {
                // keep a ref to the original event object
                originalEvent: originalEvent,
                target: originalEvent.target || originalEvent.srcElement,
                type: "wheel",
                deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
                deltaX: 0,
                deltaZ: 0,
                preventDefault: function() {
                    originalEvent.preventDefault ?
                        originalEvent.preventDefault() :
                        originalEvent.returnValue = false;
                }
            };
            
            // calculate deltaY (and deltaX) according to the event
            if ( support == "mousewheel" ) {
                event.deltaY = - 1/40 * originalEvent.wheelDelta;
                // Webkit also support wheelDeltaX
                originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX );
            } else {
                event.deltaY = originalEvent.detail;
            }

            // it's time to fire the callback
            return callback( event );

        }, useCapture || false );
    }

})(window,document);
	
addWheelListener( window, function( e ) { 
	var mul = 1;
	if (alternative_sesitivity_multiplier)
		mul = 40;
	//console.log( e.deltaY ); 
	MouseScroll(e.deltaX*mul,e.deltaY*mul, e);
});	

	
console.log("Smoothscroll loaded!");
}


var JQUERY = true;

//max retries
var r_max = 3;
var r_count = 0;

function Init() {
	//if (typeof jQuery == 'function')  {  
	if (typeof jQuery == 'undefined' || typeof $ == 'undefined' ) 
	{
		JQUERY = false;
	}
	if (JQUERY) {
		//console.log("Using existing jQuery..."); 
		//this.$ = this.jQuery = jQuery.noConflict(true);
		//var $ = jQuery.noConflict();
		//
		var versiontable = $.fn.jquery.split('.');
		var version = 0;
		for (var i = versiontable.length-1; i >= 0; i--) { 
				var power = versiontable.length-i;
				version += Math.pow(10,power-1)*versiontable[i];
		}
		
		if (version<200)
		{
			JQUERY = false;
			console.log("jQuery OLD! Version: " + version);
		}
		else
		{
			console.log("jQuery OK! Version: " + version);
			InitSmoothscroll();	
		}
	}
	if (!JQUERY) 
	{
		console.log("Loading jQuery...");  
		//this.$ = this.jQuery = jQuery.noConflict(true);
		//var $ = jQuery.noConflict();

		//this.$ = this.jQuery = jQuery.noConflict(true);

		var filename = "https://code.jquery.com/jquery-2.2.3.js";
		var fileref=document.createElement('script')
			fileref.setAttribute("type","text/javascript")
			fileref.setAttribute("src", filename)

		if (typeof fileref!="undefined")
		{
			document.getElementsByTagName("head")[0].appendChild(fileref);
		}
        
		
		JQUERY = true;
		
		if (r_count<r_max)
		{
			setTimeout(Init, 1000);
		}
		else
		{
			console.log("Failed to load smoothscroll!");
		}
		r_count++;
	}

}
console.log("Loading smoothscroll...");
Init();