你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
(我已經安裝了使用者樣式管理器,讓我安裝!)
// ==UserScript==
// @name Smoothscroll
// @include http://*
// @include https://*
// @author Creec Winceptor
// @description Smooth scrolling on pages using javascript and jquery
// @namespace https://greasyfork.org/users/3167
// @run-at document-load
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @version 2.8.1
// ==/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;
//var lastLoop = new Date;
var nextLoop = 1;
//var nextprint = lastLoop;
var dynamicframedelay = 0;
var dynamicrefreshrate = refreshrate;
function fpscalcloop(animationduration) {
var thisLoopDate = new Date;
var thisLoop = thisLoopDate.getTime();
//var fpscalc = 1000 / (thisLoop - lastLoop + 1);
//lastLoop = thisLoop;
//
var delay = thisLoop - nextLoop;
//var fpscalc = 1000 / (thisLoop - nextLoop + 1);
//refreshrate = refreshrate + (refreshrate0-refreshrate)*0.1;
//refreshrate = Math.round(refreshrate);
//animationduration = Math.round(1000/(refreshrate*3));
//console.log(animationduration);
//var relativeratio = Math.round(51-smoothness/2)/100;
//relativeratio = Math.round(1/(1+smoothness*baserefreshrate/refreshrate)*100)/100;
//
//
if (animationduration>=0)
{
nextLoop = thisLoop+animationduration;
framedelay = Math.round(delay*refreshrate/1000);
if (framedelay>0)
{
dynamicframedelay = dynamicframedelay + framedelay*2;
}
else
{
if ( dynamicframedelay>0 && framedelay<1 )
{
dynamicframedelay = Math.floor(dynamicframedelay/2);
}
}
refreshrate = refreshrate*1;
dynamicrefreshrate = Math.round( (refreshrate*refreshrate/(refreshrate+dynamicframedelay))*100 )/100;
}
else
{
nextLoop = thisLoop;
}
//console.log("dynamicframedelay: " + dynamicframedelay);
//console.log("dynamicrefreshrate: " + dynamicrefreshrate);
}
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 direction(number)
{
if (number>0)
{
return 1;
}
if (number<0)
{
return -1;
}
return 0;
}
function UpdatePosition(element)
{
//fpscalcloop(0);
var basespeed = 2;
var animationduration = Math.floor(1000/(dynamicrefreshrate));
//var relativeratio = Math.ceil( interpolation*( Math.pow(0.003*interpolation,smoothness)/dynamicrefreshrate *baserefreshrate )*1000000)/1000000;
//
//var relativeratio = Math.ceil( ( 0.5/dynamicrefreshrate *baserefreshrate )*1000000)/1000000;
var relativeratio = 1-Math.pow( dynamicrefreshrate, -1/dynamicrefreshrate*smoothness*basespeed);
var positiondelta = scrollpositiondelta(element);
var dir = direction(positiondelta);
//console.log("positiondelta:" + positiondelta);
//var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
//
var smoothdelta = Math.abs(positiondelta*relativeratio);
var rounddelta = Math.ceil(smoothdelta);
//var smoothdelta = positiondelta*relativeratio;
if ( rounddelta > 1 )
{
element.scrollTop = element.scrollTop + rounddelta*dir;
scrollpositiondelta(element, positiondelta - rounddelta*dir);
scroll_timeout = setTimeout(function() {
UpdatePosition(element);
}, animationduration);
fpscalcloop(animationduration);
}
else
{
if ( positiondelta*dir > 1 )
{
element.scrollTop = element.scrollTop + dir;
scrollpositiondelta(element, positiondelta - dir);
scroll_timeout = setTimeout(function() {
UpdatePosition(element);
}, (animationduration/smoothdelta));
}
else
{
element.scrollTop = element.scrollTop + rounddelta*dir;
scrollpositiondelta(element, 0);
//scroll_timeout = setTimeout(function() {
//}, (animationduration/smoothdelta));
}
fpscalcloop( (animationduration/smoothdelta) );
}
}
function MouseScroll (e) {
var mul = 1;
if (!WEBKIT || alternative_sensitivity_multiplier)
mul = 40;
var x = e.deltaX*mul;
var y = e.deltaY*mul;
scrollfocus = UpdateFocus(x,y);
/*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);
//var positiondeltadelta = Math.round(Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.2);
var positiondeltadelta = rolled*sensitivity;
var positiondeltacceleration = Math.sqrt(Math.abs(positiondelta/positiondeltadelta*acceleration));
//console.log("positiondelta: "+positiondelta+" positiondeltadelta: " + positiondeltadelta + " positiondeltacceleration: " + positiondeltacceleration);
positiondelta = Math.round(positiondelta*1 + positiondeltadelta*(1+positiondeltacceleration) );
scrollpositiondelta(scrollfocus, positiondelta)
clearTimeout(scroll_timeout);
fpscalcloop(-1);
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("newdelta:" + newdelta);
/*var dir = 0;
if (newdelta>0)
{
dir = 1;
}
if (newdelta<0)
{
dir = -1;
}*/
//target.setAttribute("positiondelta", newdelta );
target.positiondelta = newdelta;
delta = newdelta;
}
else
{
//var olddelta = target.getAttribute("positiondelta");
var olddelta = target.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");
});
document.documentElement.addEventListener("mousedown", function(e){
if (scrollfocus)
{
scrollpositiondelta(scrollfocus, 0);
////ss$(scrollfocus).stop();
}
});
/*
document.documentElement.addEventListener("mousemove", function(e){
mousemoved = true;
});*/
//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!")
location.reload();
}
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.documentElement;
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()};
}
var ConfigSmoothscroll = function()
{
console.log("opening");
if (typeof $smoothscroll$ == 'undefined'){
alert("Smoothscroll is not running properly on this page!");
return;
}
var configbar = document.getElementById("ss-configbar");
configbar.style.display = 'block';
window.scrollTo(0, 0);
//ss$("html, body").animate({ scrollTop: 0 }, "slow");
console.log("opening config...");
}
if (typeof $smoothscroll$ == 'undefined'){
//console.log("Initiating smoothscroll...");
InitSmoothscroll();
GM_registerMenuCommand("Smoothscroll config", ConfigSmoothscroll );
}
else
{
console.log("Smoothscroll already loaded!");
}