Smoothscroll

Smooth scrolling on pages using javascript and jquery

当前为 2016-12-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Smoothscroll
  3. // @include http://*
  4. // @include https://*
  5. // @author Creec Winceptor
  6. // @description Smooth scrolling on pages using javascript and jquery
  7. // @namespace https://greasyfork.org/users/3167
  8. // @run-at document-load
  9. // @grant none
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @grant GM_registerMenuCommand
  13. // @version 2.6
  14. // ==/UserScript==
  15.  
  16. if (window.top != window.self) //don't run on frames or iframes
  17. return;
  18.  
  19. //DEFAULT SETTINGS HERE
  20. //DO NOT CHANGE ANYTHING HERE ANYMORE, USE SCRIPT COMMANDS -> CONFIGURE SMOOTHSCROLL
  21.  
  22.  
  23. //Smoothness factor value (how strong the smoothing effect is)
  24. //values: 1-(infinite) (default 1.00)
  25. var smoothness = 1;
  26.  
  27. //Scroll sensitivity
  28. //values: anything? (default 1.00)
  29. var sensitivity = 1;
  30.  
  31. //Acceleration sensitivity
  32. //values: anything? (default 1.50)
  33. var acceleration = 1;
  34.  
  35. //Refreshrate setting
  36. //values: 30-144 (default = 60/72/120/144 = same as your monitor hz)
  37. var refreshrate = 60;
  38.  
  39.  
  40. //Alternative scrolling multiplier
  41. //values: true/false (try to set this to true if scrolling is too slow/doesn't work)
  42. var alternative_sensitivity_multiplier = false;
  43.  
  44.  
  45. //CODE STARTS HERE
  46.  
  47. var DEBUG = false;
  48.  
  49. var WEBKIT = false;
  50.  
  51. //console.log("Loading smoothscroll...");
  52.  
  53. var baserefreshrate = 60; //DO NOT CHANGE THIS EVER
  54. if (smoothness>10)
  55. {
  56. smoothness = 10;
  57. }
  58.  
  59. if (refreshrate <= 30 || refreshrate>144)
  60. {
  61. refreshrate = 144;
  62. }
  63.  
  64. function InitSmoothscroll()
  65. {
  66. LoadConfig();
  67.  
  68. InitConfigmenu();
  69.  
  70. var startposition = false;
  71. var targetposition = 0;
  72. var position = 0;
  73.  
  74. //var scrollfocus = //ss$('body');
  75. var scrollfocus = document.body;
  76. var mousemoved = true;
  77. //var lastLoop = new Date;
  78. var nextLoop = 1;
  79. //var nextprint = lastLoop;
  80. var dynamicframedelay = 0;
  81. var dynamicrefreshrate = refreshrate;
  82. function fpscalcloop(animationduration) {
  83. var thisLoopDate = new Date;
  84. var thisLoop = thisLoopDate.getTime();
  85. //var fpscalc = 1000 / (thisLoop - lastLoop + 1);
  86. //lastLoop = thisLoop;
  87. //
  88. var delay = thisLoop - nextLoop;
  89. //var fpscalc = 1000 / (thisLoop - nextLoop + 1);
  90.  
  91. //refreshrate = refreshrate + (refreshrate0-refreshrate)*0.1;
  92. //refreshrate = Math.round(refreshrate);
  93. //animationduration = Math.round(1000/(refreshrate*3));
  94. //console.log(animationduration);
  95. //var relativeratio = Math.round(51-smoothness/2)/100;
  96. //relativeratio = Math.round(1/(1+smoothness*baserefreshrate/refreshrate)*100)/100;
  97. //
  98. //
  99. if (animationduration>=0)
  100. {
  101. nextLoop = thisLoop+animationduration;
  102. framedelay = Math.round(delay*refreshrate/1000);
  103.  
  104. if (framedelay>0)
  105. {
  106. dynamicframedelay = dynamicframedelay + framedelay*2;
  107. }
  108. else
  109. {
  110. if ( dynamicframedelay>0 && framedelay<1 )
  111. {
  112. dynamicframedelay = Math.floor(dynamicframedelay/2);
  113.  
  114. }
  115. }
  116.  
  117. refreshrate = refreshrate*1;
  118. dynamicrefreshrate = Math.round( (refreshrate*refreshrate/(refreshrate+dynamicframedelay))*100 )/100;
  119. }
  120. else
  121. {
  122. nextLoop = thisLoop;
  123. }
  124. //console.log("dynamicframedelay: " + dynamicframedelay);
  125. //console.log("dynamicrefreshrate: " + dynamicrefreshrate);
  126. }
  127.  
  128. function hasScrollBarVisible(element)
  129. {
  130. //return (document.documentElement.scrollHeight !== document.documentElement.clientHeight);
  131. // Get the computed style of the body element
  132. var cStyle = element.currentStyle||window.getComputedStyle(element, "");
  133. // Check the overflow and overflowY properties for "auto" and "visible" values
  134. var scrollbar1 = cStyle.overflow == "scroll" || cStyle.overflowY == "scroll";
  135.  
  136. var scrollbar2 = cStyle.overflow == "auto" || cStyle.overflowY == "auto";
  137. var scrollbar = scrollbar1 || scrollbar2;
  138. return scrollbar;
  139. }
  140.  
  141.  
  142. function hasscrollbars(scrollfocus)
  143. {
  144. var hasvisiblescrollbars = hasScrollBarVisible(scrollfocus);
  145. return hasvisiblescrollbars;
  146. /*
  147. var parentelement = //ss$(scrollfocus).parent();
  148. if ( //ss$(parentelement))
  149. {
  150. if (//ss$(parentelement).is("textarea") || //ss$(scrollfocus).is("textarea") || //ss$(parentelement).is("article") || //ss$(parentelement).is("article"))
  151. {
  152. return true;
  153. }
  154. else
  155. {
  156. if (//ss$(parentelement).hasClass( "yt-scrollbar" ) || //ss$(scrollfocus).hasClass( "yt-scrollbar" ))
  157. {
  158. return true;
  159. }
  160. return hasvisiblescrollbars;
  161. }
  162. }
  163. else
  164. {
  165. return hasvisiblescrollbars;
  166. }
  167. return false;
  168. */
  169. }
  170.  
  171. var scroll_timeout = null;
  172. function direction(number)
  173. {
  174. if (number>0)
  175. {
  176. return 1;
  177. }
  178. if (number<0)
  179. {
  180. return -1;
  181. }
  182. return 0;
  183. }
  184.  
  185. function UpdatePosition(element)
  186. {
  187. //fpscalcloop(0);
  188. var interpolation = 3;
  189. var animationduration = Math.floor(1000/(dynamicrefreshrate*interpolation));
  190. var relativeratio = Math.ceil( interpolation*( Math.pow(0.01,smoothness)/dynamicrefreshrate *baserefreshrate )*1000000)/1000000;
  191. var positiondelta = scrollpositiondelta(element);
  192. var dir = direction(positiondelta);
  193. //console.log("positiondelta:" + positiondelta);
  194. var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio)/interpolation;
  195. var rounddelta = Math.ceil(smoothdelta);
  196. //var smoothdelta = positiondelta*relativeratio;
  197.  
  198. if ( rounddelta > 1 )
  199. {
  200. element.scrollTop = element.scrollTop + rounddelta*dir;
  201. scrollpositiondelta(element, positiondelta - rounddelta*dir);
  202. scroll_timeout = setTimeout(function() {
  203. UpdatePosition(element);
  204. }, animationduration);
  205. fpscalcloop(animationduration);
  206. }
  207. else
  208. {
  209. if ( positiondelta*dir > 1 )
  210. {
  211. element.scrollTop = element.scrollTop + dir;
  212. scrollpositiondelta(element, positiondelta - dir);
  213. scroll_timeout = setTimeout(function() {
  214. UpdatePosition(element);
  215. }, (animationduration/smoothdelta));
  216. }
  217. else
  218. {
  219. element.scrollTop = element.scrollTop + rounddelta*dir;
  220. scrollpositiondelta(element, 0);
  221. //scroll_timeout = setTimeout(function() {
  222. //}, (animationduration/smoothdelta));
  223. }
  224. fpscalcloop( (animationduration/smoothdelta) );
  225. }
  226. }
  227.  
  228.  
  229. function MouseScroll (e) {
  230.  
  231. var mul = 1;
  232. if (!WEBKIT || alternative_sensitivity_multiplier)
  233. mul = 40;
  234. var x = e.deltaX*mul;
  235. var y = e.deltaY*mul;
  236. //if (mousemoved)
  237. //{
  238. scrollfocus = UpdateFocus(x,y);
  239. //mousemoved = false;
  240. //}
  241. var positiondelta = 0;
  242. var lastscrolltop = 0;
  243.  
  244. var rolled = y;
  245. if (!canscroll(scrollfocus, rolled))
  246. {
  247. if (scrollfocus != document.documentElement)
  248. {
  249. scrollfocus = UpdateFocus(x,y);
  250. return false;
  251. }
  252. else
  253. {
  254. //console.log("true");
  255. return false;
  256. }
  257. }
  258. else
  259. {
  260. if (e.defaultPrevented)
  261. {
  262. return true;
  263. }
  264. else
  265. {
  266. e.preventDefault();
  267. }
  268. }
  269. positiondelta = scrollpositiondelta(scrollfocus);
  270. var direction = rolled/Math.abs(rolled);
  271. var positiondeltadelta = Math.round(rolled*sensitivity + Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.2);
  272. positiondelta = positiondelta*1 + positiondeltadelta*1;
  273. scrollpositiondelta(scrollfocus, positiondelta)
  274.  
  275. clearTimeout(scroll_timeout);
  276. fpscalcloop(-1);
  277. UpdatePosition(scrollfocus);
  278. //console.log(e);
  279. return true;
  280. }
  281.  
  282. function canscroll(element, dir)
  283. {
  284. if (dir>0)
  285. {
  286. dir = 1;
  287. }
  288. if (dir<0)
  289. {
  290. dir = -1;
  291. }
  292. var checkradius = 3; //pixels to try scrolling
  293. var canscroll0 = false;
  294.  
  295. var scrollable = element;
  296.  
  297. var lastscrolltop = scrollable.scrollTop;
  298.  
  299. scrollable.scrollTop = lastscrolltop+dir*checkradius;
  300.  
  301. if (scrollable.scrollTop!=lastscrolltop)
  302. {
  303. canscroll0 = true;
  304. }
  305.  
  306. scrollable.scrollTop = lastscrolltop;
  307.  
  308. return canscroll0;
  309. }
  310. function scrollpositiondelta(element, newdelta)
  311. {
  312. //var target = //ss$(element);
  313. var target = element;
  314. var delta = 0;
  315. if (newdelta!=undefined)
  316. {
  317. //console.log("newdelta:" + newdelta);
  318. /*var dir = 0;
  319. if (newdelta>0)
  320. {
  321. dir = 1;
  322. }
  323. if (newdelta<0)
  324. {
  325. dir = -1;
  326. }*/
  327. target.setAttribute("positiondelta", newdelta );
  328.  
  329. delta = newdelta;
  330. }
  331. else
  332. {
  333. var olddelta = target.getAttribute("positiondelta");
  334. if (olddelta!=undefined)
  335. {
  336. delta = olddelta;
  337. }
  338. }
  339. return delta*1;
  340. }
  341.  
  342. function UpdateFocus(x,y) {
  343. if (scrollfocus)
  344. {
  345. //scrollpositiondelta(scrollfocus, 0);
  346. //ss$(scrollfocus).stop();
  347. }
  348. var dir = y;
  349. var nodelist = document.querySelectorAll( ":hover" );
  350. if (WEBKIT)
  351. {
  352. //scrollfocus = //ss$('body');
  353. scrollfocus = document.body;
  354. }
  355. else
  356. {
  357. //scrollfocus = //ss$('html');
  358. scrollfocus = document.documentElement;
  359. }
  360. for (var i = nodelist.length-1; i >= 0 ; i--) {
  361. var newfocus = nodelist[i];
  362. if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
  363. {
  364. scrollfocus = newfocus;
  365. return newfocus;
  366. }
  367. }
  368.  
  369. return scrollfocus;
  370. }
  371. /*ss$('html').bind({
  372. mousemove: function(e) {
  373. mousemoved = true;
  374. },
  375. mousedown: function(e) {
  376. if (DEBUG)
  377. {
  378. console.log(scrollfocus);
  379. }
  380. if (scrollfocus)
  381. {
  382. scrollpositiondelta(scrollfocus, 0);
  383. ////ss$(scrollfocus).stop();
  384. }
  385. scrollfocus = UpdateFocus(0,0);
  386. //console.log("click");
  387. }
  388. });
  389. */
  390. document.documentElement.addEventListener("wheel", function(e){
  391. MouseScroll(e);
  392. mousemoved = true;
  393. //console.log("scrolling");
  394. });
  395.  
  396. //WEBKIT = 'webkitRequestAnimationFrame' in window;
  397. WEBKIT = document.compatMode == 'CSS1Compat' || document.compatMode == "BackCompat";
  398. //console.log("window: " + window);
  399. console.log("Smoothscroll loaded! Webkit: " + WEBKIT);
  400. $smoothscroll$ = true;
  401. }
  402.  
  403. function LoadConfig()
  404. {
  405. smoothness = GM_getValue( 'smoothness', smoothness );
  406. sensitivity = GM_getValue( 'sensitivity', sensitivity );
  407. acceleration = GM_getValue( 'acceleration', acceleration );
  408. refreshrate = GM_getValue( 'refreshrate', refreshrate );
  409. //alternative_sesitivity_multiplier = GM_getValue( 'alternative_sesitivity_multiplier', alternative_sesitivity_multiplier );
  410. //console.log("Config for smoothscroll loaded!")
  411. }
  412.  
  413. function SaveConfig()
  414. {
  415. GM_setValue( 'smoothness', document.getElementById('ss-smoothness').value)
  416. GM_setValue( 'sensitivity', document.getElementById('ss-sensitivity').value)
  417. GM_setValue( 'acceleration', document.getElementById('ss-acceleration').value)
  418. GM_setValue( 'refreshrate', document.getElementById('ss-refreshrate').value)
  419. //console.log(document.getElementById('ss-alternative_sesitivity_multiplier').checked)
  420. console.log("Config for smoothscroll saved!")
  421. location.reload();
  422. }
  423.  
  424. function CloseConfig()
  425. {
  426. var configbar = document.getElementById("ss-configbar");
  427. configbar.style.display = 'none';
  428. }
  429.  
  430. function InitConfigmenu()
  431. {
  432. //console.log("Initiating smoothscroll config...");
  433. var configbar = document.createElement('div');
  434. configbar.setAttribute("id","ss-configbar");
  435. //<tr><td>Sensitivity</td><td><input type="number" id="ss-sensitivity" min="0" max="100" value="' + sensitivity + '"></td><td> Scroll sensitivity (duh)</td></tr>
  436. 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>';
  437. var configparent = document.documentElement;
  438. configbar.style.width = '100%';
  439. configbar.style.display = 'none';
  440. configbar.style.position = 'absolute';
  441. configbar.style.zIndex = '9999';
  442. configbar.style.backgroundColor = 'white';
  443. configparent.insertBefore(configbar, configparent.childNodes[0]);
  444. document.getElementById("ss-close").onclick = function() {CloseConfig()};
  445. document.getElementById("ss-save").onclick = function() {SaveConfig()};
  446. }
  447.  
  448. function ConfigSmoothscroll()
  449. {
  450. if (typeof $smoothscroll$ == 'undefined'){
  451. alert("Smoothscroll is not running properly on this page!");
  452. return;
  453. }
  454.  
  455. var configbar = document.getElementById("ss-configbar");
  456. configbar.style.display = 'block';
  457. window.scrollTo(0, 0);
  458. //ss$("html, body").animate({ scrollTop: 0 }, "slow");
  459. //console.log("opening config...");
  460. }
  461.  
  462. if (typeof $smoothscroll$ == 'undefined'){
  463. //console.log("Initiating smoothscroll...");
  464. InitSmoothscroll();
  465. GM_registerMenuCommand("Configurate smoothscroll", ConfigSmoothscroll);
  466. }
  467. else
  468. {
  469. console.log("Smoothscroll already loaded!");
  470. }