Smoothscroll

Smooth scrolling on pages using javascript and jquery

当前为 2017-07-27 提交的版本,查看 最新版本

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