Smoothscroll

Smooth scrolling on pages using javascript and jquery

目前為 2016-05-04 提交的版本,檢視 最新版本

// ==UserScript==
// @name Smoothscroll
// @include     http*
// @author       Creec Winceptor
// @description  Smooth scrolling on pages using javascript and jquery
// @namespace https://gf.qytechs.cn/users/3167
// @run-at document-idle
// @grant    GM_info
// @grant         unsafeWindow
// @version 0.0.1.20160504074852
// ==/UserScript==


//SETTINGS HERE

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


//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($) {
    $.fn.hasScrollBar = function() {
        return this.get(0).scrollHeight > this.height();
    }
})(jQuery);
(function($) {
    $.fn.hasScrollBar0 = function() {
        var divnode = this.get(0);
        if(divnode.scrollHeight > divnode.clientHeight)
            return true;
    }
})(jQuery);
(function($) {
    $.fn.hasScrollBar1 = function() {
        return this.get(0).scrollHeight > this.height();
    }
})(jQuery);
(function($) {
    $.fn.hasScrollBar2 = function() {
        return this.get(0) ? this.get(0).scrollHeight > this.innerHeight() : false;
    }
})(jQuery);
(function($) {
    $.fn.hasScrollBar3 = function() {
        return this.get(0) ? (this.get(0).scrollHeight > this.innerHeight() && this.get(0).scrollHeight > this.height()) : false;
    }
})(jQuery);

function hasVerticalScroll(node){
    if(node == undefined){
        if(window.innerHeight){
            return document.body.offsetHeight> innerHeight;
        }
        else {
            return  document.documentElement.scrollHeight > 
                document.documentElement.offsetHeight ||
                document.body.scrollHeight>document.body.offsetHeight;
        }
    }
    else {
        return node.scrollHeight> node.offsetHeight;
    }
}	
*/

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).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;
			}*/
			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 maxposition = scrollfocus.scrollHeight - $(scrollfocus).outerHeight();
	 //console.log(maxposition);
	 //console.log($(scrollfocus).scrollTop());
	 
	 /*var rolled = 0;
	 if ('wheelDelta' in event) {
		 rolled = event.wheelDelta;
	 }
	 else {  // Firefox
		 // The measurement units of the detail and wheelDelta properties are different.
		 rolled = event.detail*(-120);
	 }
	 rolled = rolled*(-1);*/
	 
	 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;
	 //console.log("positiondeltadelta: " + positiondeltadelta);
	 //Math.abs(positiondelta*relativeratio)
	 
	 
	 //console.log("target:" + targetposition);
	//var targetposition = $(scrollfocus).scrollTop() + positiondelta;
	 /*
	 if (targetposition <= 0)
		 {
			 targetposition = -startposition;
			 //console.log("start")
		 }
	 
	 else if (targetposition+startposition >= maxposition)
		 {
			 targetposition = (maxposition-startposition);
			 //console.log("end")
		 }
	 else
		 {
			 
		 }
	 $(scrollfocus).data( "targetposition", targetposition );
	 */
	 
	 //console.log("document:" + $(document).height());
	 //console.log("window:" + $(window).height());

	 //position = startposition + targetposition;
	 //$(scrollfocus).data( "position", position );
	 //
	 //$(scrollfocus).data( "positiondelta", positiondelta );
	 $(scrollfocus)[0].setAttribute("positiondelta",positiondelta );
	 
	 
	 UpdatePosition($(scrollfocus));
	 
	 //element.innerHTML = "";
	 //console.log("pos:" + position);
	 //event.preventDefault();
	 return true;
 	}

	/*
	function Init (smoothscrollelem) {
		
		// for mouse scrolling in Firefox
		
		
		if (smoothscrollelem.addEventListener) {    // all browsers except IE before version 9
			// Internet Explorer, Opera, Google Chrome and Safari
			smoothscrollelem.addEventListener ("mousewheel", MouseScroll, false);
			// Firefox
			smoothscrollelem.addEventListener ("DOMMouseScroll", MouseScroll, false);
		}
		else {
			if (smoothscrollelem.attachEvent) { // IE before version 9
				smoothscrollelem.attachEvent ("onmousewheel", MouseScroll);
			}
		}
    }
	*/
	
	/*var elements = $('*');
	console.log("Loaded " + elements.length + " scrollable elements.");
	$(elements).each(function() {
		$( this ).bind({
		 mouseenter: function(e) {
			  UpdateFocus(e.originalEvent);
			  
		  },
			 mouseleave: function(e) {
			  UpdateFocus(e.originalEvent);
			  
		  }
		});
	});*/
 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;
				}
 		}
		//scrollfocus = $('body');
	/*if (DEBUG)
	{
		$(scrollfocus).css( "border", "3px solid green" );
		setTimeout(function(){ 
			//console.log(nodelist);
			for (var i = nodelist.length-1; i >= 0; i--) { 
				//var parent = nodelist[i-1];
			  	var newfocus = nodelist[i];
				$(newfocus).css( "border", "0px solid white" );
			}
		 }, 1000);
	}*/
	
	 return scrollfocus;
 }
		//$(document).off("mousewheel");
	 /*
	$(document).on('mousewheel DOMMouseScroll', function(e){

	  //var dat = $(e.delegateTarget).data(); //in case you have set some, read it here.
	  //var datx = dat.x || 0; // just to show how to get specific out of jq-data object
		var x = 0;
		var y = 0;
		
	  var eo = e.originalEvent;
		
	  //var xy = eo.wheelDelta || -eo.detail; //shortest possible code
	  //var x = eo.wheelDeltaX || (eo.axis==1?xy:0);
	  //var y = eo.wheelDeltaY || (eo.axis==2?xy:0); // () necessary!
		
		
	  	x = x*(-1);
		y = y*(-1);
		console.log(x,y);

		//e.preventDefault();
		//MouseScroll(x,y);
		
	});
	*/
		
		$('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 = false;

//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();
		console.log("jQuery OK!");
		InitSmoothscroll();
	}
	else
	{
		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();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址