Smoothscroll

Smooth scrolling on pages using javascript and jquery

当前为 2016-11-01 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Smoothscroll
  3. // @include http*
  4. // @author Creec Winceptor
  5. // @description Smooth scrolling on pages using javascript and jquery
  6. // @namespace https://greasyfork.org/users/3167
  7. // @run-at document-idle
  8. // @grant none
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @grant GM_registerMenuCommand
  12. // @version 2.0.1
  13. // ==/UserScript==
  14.  
  15. if (window.top != window.self) //don't run on frames or iframes
  16. return;
  17.  
  18.  
  19.  
  20.  
  21.  
  22. //DEFAULT SETTINGS HERE
  23. //DO NOT CHANGE ANYTHING HERE ANYMORE, USE SCRIPT COMMANDS -> CONFIGURE SMOOTHSCROLL
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30. //Smoothness factor value (how strong the smoothing effect is)
  31. //values: 1-(infinite)
  32. var smoothness = 30;
  33.  
  34. //Scroll sensitivity
  35. //values: anything? (default 1.00)
  36. var sensitivity = 1;
  37.  
  38. //Acceleration sensitivity
  39. //values: anything? (default 1.50)
  40. var acceleration = 1;
  41.  
  42. //Refreshrate setting
  43. //values: 30-144 (default = 60/72/120/144 = same as your monitor hz)
  44. var refreshrate = 60;
  45.  
  46.  
  47. //Alternative scrolling multiplier
  48. //values: true/false (try to set this to true if scrolling is too slow/doesn't work)
  49. var alternative_sensitivity_multiplier = false;
  50.  
  51.  
  52. //CODE STARTS HERE
  53.  
  54. var minimal_jquery_version = 200;
  55.  
  56. //max retries
  57. //var jquery_retry_max = 5;
  58. //var jquery_retry_count = 0;
  59.  
  60.  
  61. var DEBUG = false;
  62.  
  63. var WEBKIT = false;
  64.  
  65. //this.$ = this.jQuery = jQuery.noConflict(true);
  66.  
  67. console.log("Loading smoothscroll...");
  68.  
  69.  
  70. var baserefreshrate = 60; //DO NOT CHANGE THIS EVER
  71. if (smoothness>100)
  72. {
  73. smoothness = 100;
  74. }
  75.  
  76. if (refreshrate <= 30 || refreshrate>144)
  77. {
  78. refreshrate = 144;
  79. }
  80.  
  81. //var animationduration = Math.round(1000/refreshrate*3);
  82. //var relativeratio = Math.round(51-smoothness/2)/100;
  83. //var relativeratio = Math.round(1/(1+smoothness*baserefreshrate/refreshrate)*100)/100;
  84. //var relativeratio = relativeratio;
  85.  
  86.  
  87. /*
  88. var lastLoop = new Date;
  89. //var lastrefreshrate = 0;
  90. function gameLoop() {
  91. var thisLoop = new Date;
  92. var refreshrate0 = 1000 / (thisLoop - lastLoop + 1);
  93. lastLoop = thisLoop;
  94. refreshrate = refreshrate + (refreshrate0-refreshrate)*0.1;
  95. refreshrate = Math.round(refreshrate);
  96. if (DEBUG)
  97. {
  98. console.log(refreshrate);
  99. }
  100. //animationduration = Math.round(1000/(refreshrate*3));
  101. //console.log(animationduration);
  102. //var relativeratio = Math.round(51-smoothness/2)/100;
  103. relativeratio = Math.round(1/(1+smoothness*baserefreshrate/refreshrate)*100)/100;
  104. }
  105. gameLoop();*/
  106.  
  107.  
  108. function InitSmoothscroll()
  109. {
  110. LoadConfig();
  111.  
  112. InitConfigmenu();
  113.  
  114. var startposition = false;
  115. var targetposition = 0;
  116. var position = 0;
  117.  
  118. //var scrollfocus = //ss$('body');
  119. var scrollfocus = document.body;
  120. var mousemoved = true;
  121. function hasScrollBarVisible(element)
  122. {
  123. //return (document.documentElement.scrollHeight !== document.documentElement.clientHeight);
  124. // Get the computed style of the body element
  125. var cStyle = element.currentStyle||window.getComputedStyle(element, "");
  126. // Check the overflow and overflowY properties for "auto" and "visible" values
  127. var scrollbar1 = cStyle.overflow == "scroll" || cStyle.overflowY == "scroll";
  128.  
  129. var scrollbar2 = cStyle.overflow == "auto" || cStyle.overflowY == "auto";
  130. var scrollbar = scrollbar1 || scrollbar2;
  131. return scrollbar;
  132. }
  133.  
  134.  
  135. function hasscrollbars(scrollfocus)
  136. {
  137. var hasvisiblescrollbars = hasScrollBarVisible(scrollfocus);
  138. return hasvisiblescrollbars;
  139. /*
  140. var parentelement = //ss$(scrollfocus).parent();
  141. if ( //ss$(parentelement))
  142. {
  143. if (//ss$(parentelement).is("textarea") || //ss$(scrollfocus).is("textarea") || //ss$(parentelement).is("article") || //ss$(parentelement).is("article"))
  144. {
  145. return true;
  146. }
  147. else
  148. {
  149. if (//ss$(parentelement).hasClass( "yt-scrollbar" ) || //ss$(scrollfocus).hasClass( "yt-scrollbar" ))
  150. {
  151. return true;
  152. }
  153. return hasvisiblescrollbars;
  154. }
  155. }
  156. else
  157. {
  158. return hasvisiblescrollbars;
  159. }
  160. return false;
  161. */
  162. }
  163.  
  164. var scroll_timeout = null;
  165.  
  166. function UpdatePosition(element)
  167. {
  168. //gameLoop();
  169. var interpolation = 3;
  170. var animationduration = Math.round(1000/(refreshrate*interpolation));
  171. var relativeratio = Math.round(( 1/(1+smoothness)/interpolation*refreshrate/baserefreshrate )*1000)/1000;
  172. var positiondelta = scrollpositiondelta(element);
  173. //console.log(positiondelta);
  174. var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
  175. if (positiondelta<0)
  176. {
  177. smoothdelta = smoothdelta*(-1);
  178. }
  179. //console.log(smoothdelta);
  180. //console.log(positiondelta-smoothdelta);
  181. if (Math.abs( (positiondelta-smoothdelta) ) <= 1 )
  182. //if (Math.abs( smoothdelta ) < 1 )
  183. {
  184. /*
  185. //ss$(element).stop();
  186. ss$(element).animate({
  187. scrollTop: '+=' + Math.round(positiondelta)
  188. }, animationduration, "linear", function() {
  189. scrollpositiondelta(element, 0);
  190. if (DEBUG)
  191. {
  192. //ss$(element).css( "border", "1px solid red" );
  193. }
  194. });
  195. */
  196. scroll_timeout = setTimeout(function() {
  197. element.scrollTop = element.scrollTop + smoothdelta;
  198. scrollpositiondelta(element, 0);
  199. }, animationduration);
  200.  
  201. }
  202. else
  203. {
  204. /*
  205. //ss$(element).stop();
  206. ss$(element).animate({
  207. scrollTop: '+=' + Math.round(smoothdelta)
  208. }, animationduration, "linear", function() {
  209. scrollpositiondelta(element, positiondelta-smoothdelta);
  210. UpdatePosition(element);
  211. if (DEBUG)
  212. {
  213. //ss$(element).css( "border", "1px solid red" );
  214. }
  215. });
  216. */
  217. scroll_timeout = setTimeout(function() {
  218. element.scrollTop = element.scrollTop + smoothdelta;
  219. scrollpositiondelta(element, positiondelta - smoothdelta);
  220. UpdatePosition(element);
  221. }, animationduration);
  222. }
  223. }
  224.  
  225.  
  226. function MouseScroll (e) {
  227. //gameLoop();
  228. var mul = 1;
  229. if (!WEBKIT || alternative_sensitivity_multiplier)
  230. mul = 40;
  231. var x = e.deltaX*mul;
  232. var y = e.deltaY*mul;
  233. if (mousemoved)
  234. {
  235. scrollfocus = UpdateFocus(x,y);
  236. mousemoved = false;
  237. }
  238. var positiondelta = 0;
  239. var lastscrolltop = 0;
  240.  
  241. //var parentelement = //ss$(scrollfocus).parent();
  242. var rolled = y;
  243. //var lastscrolltop = //ss$(scrollfocus).scrollTop();
  244. if (!canscroll(scrollfocus, rolled))
  245. {
  246. //if (!//ss$(scrollfocus).is("html"))
  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. e.preventDefault();
  261. }
  262. positiondelta = scrollpositiondelta(scrollfocus);
  263. //console.log("positiondelta = " + positiondelta);
  264. var direction = rolled/Math.abs(rolled);
  265. var positiondeltadelta = Math.round(rolled*sensitivity + Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.09/sensitivity);
  266. positiondelta = positiondelta*1 + positiondeltadelta*1;
  267. //console.log("positiondelta + " + positiondeltadelta + " = " + positiondelta);
  268.  
  269. scrollpositiondelta(scrollfocus, positiondelta)
  270. //UpdatePosition(//ss$(scrollfocus));
  271. clearTimeout(scroll_timeout);
  272. UpdatePosition(scrollfocus);
  273. return true;
  274. }
  275.  
  276. function canscroll(element, dir)
  277. {
  278. //console.log(dir);
  279. if (dir>0)
  280. {
  281. dir = 1;
  282. }
  283. if (dir<0)
  284. {
  285. dir = -1;
  286. }
  287. var checkradius = 3; //pixels to try scrolling
  288. var canscroll0 = false;
  289. //var scrollable = //ss$(element);
  290. var scrollable = element;
  291. //var lastscrolltop = //ss$(scrollable).scrollTop();
  292. var lastscrolltop = scrollable.scrollTop;
  293.  
  294. //ss$(scrollable).scrollTop(lastscrolltop+dir*checkradius);
  295. scrollable.scrollTop = lastscrolltop+dir*checkradius;
  296. //if (//ss$(scrollable).scrollTop()!=lastscrolltop)
  297. if (scrollable.scrollTop!=lastscrolltop)
  298. {
  299. canscroll0 = true;
  300. }
  301. //ss$(scrollable).scrollTop(lastscrolltop);
  302. scrollable.scrollTop = lastscrolltop;
  303. //console.log("canscroll0: " + //ss$(element).prev().prop('nodeName') + " : " + canscroll0);
  304. return canscroll0;
  305. }
  306. function scrollpositiondelta(element, newdelta)
  307. {
  308. //var target = //ss$(element);
  309. var target = element;
  310. var delta = 0;
  311. if (newdelta!=undefined)
  312. {
  313. //console.log(dir);
  314. var dir = 0;
  315. if (newdelta>0)
  316. {
  317. dir = 1;
  318. }
  319. if (newdelta<0)
  320. {
  321. dir = -1;
  322. }
  323. target.setAttribute("positiondelta", newdelta );
  324. //console.log(newdelta);
  325. ////ss$(target)[0].setAttribute("positiondelta", newdelta );
  326. //ss$( target ).data( "positiondelta", newdelta );
  327. delta = newdelta;
  328. }
  329. else
  330. {
  331. var olddelta = target.getAttribute("positiondelta");
  332. //var olddelta = //ss$(target)[0].getAttribute("positiondelta");
  333. //var olddelta = //ss$( target ).data( "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. ////ss$(nodelist).stop();
  351. //console.log(nodelist);
  352. if (WEBKIT)
  353. {
  354. //scrollfocus = //ss$('body');
  355. scrollfocus = document.body;
  356. }
  357. else
  358. {
  359. //scrollfocus = //ss$('html');
  360. scrollfocus = document.documentElement;
  361. }
  362. for (var i = nodelist.length-1; i >= 0 ; i--) {
  363. //var parent = nodelist[i-1];
  364. var newfocus = nodelist[i];
  365. if (DEBUG)
  366. {
  367. //ss$(newfocus).css( "border", "1px solid blue" );
  368. //var debugtimer = setTimeout(function(){ //ss$(newfocus).css( "border", "0px solid white" ); }, 1000);
  369. }
  370. //if (//ss$(newfocus).hasScrollBar3() && hasScrollBarVisible(newfocus) && canscroll(newfocus, dir) && hasscrollbars(newfocus))
  371. if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
  372. {
  373. //scrollfocus = ss$(newfocus);
  374. scrollfocus = newfocus;
  375. return newfocus;
  376. }
  377. }
  378.  
  379. return scrollfocus;
  380. }
  381. /*ss$('html').bind({
  382. mousemove: function(e) {
  383. mousemoved = true;
  384. },
  385. mousedown: function(e) {
  386. if (DEBUG)
  387. {
  388. console.log(scrollfocus);
  389. }
  390. if (scrollfocus)
  391. {
  392. scrollpositiondelta(scrollfocus, 0);
  393. ////ss$(scrollfocus).stop();
  394. }
  395. scrollfocus = UpdateFocus(0,0);
  396. //console.log("click");
  397. }
  398. });
  399. */
  400. document.documentElement.addEventListener("wheel", function(e){
  401. MouseScroll(e);
  402. mousemoved = true;
  403. //console.log("scrolling");
  404. });
  405.  
  406. //WEBKIT = 'webkitRequestAnimationFrame' in window;
  407. WEBKIT = document.compatMode == 'CSS1Compat' || document.compatMode == "BackCompat";
  408. //console.log("window: " + window);
  409. console.log("Smoothscroll initiated! Webkit: " + WEBKIT);
  410. $smoothscroll$ = true;
  411. }
  412.  
  413. /*
  414. var JQUERY = false;
  415. var OWNJQUERY = false;
  416. var OLDJQUERY = false;
  417.  
  418. var old$;
  419. var oldjQuery;
  420.  
  421. var ss$;
  422. */
  423.  
  424. /*
  425. function jQueryVersion(temp$)
  426. {
  427. if (typeof temp$ == 'undefined' || typeof temp$.fn == 'undefined' || typeof temp$.fn.jquery == 'undefined')
  428. {
  429. return 0;
  430. }
  431.  
  432. var versiontable = temp$.fn.jquery.split('.');
  433. var version = 0;
  434. for (var i = versiontable.length-1; i >= 0; i--) {
  435. var power = versiontable.length-i;
  436. version += Math.pow(10,power-1)*versiontable[i];
  437. }
  438. return version;
  439. }
  440. */
  441.  
  442. function LoadConfig()
  443. {
  444. smoothness = GM_getValue( 'smoothness', smoothness );
  445. sensitivity = GM_getValue( 'sensitivity', sensitivity );
  446. acceleration = GM_getValue( 'acceleration', acceleration );
  447. refreshrate = GM_getValue( 'refreshrate', refreshrate );
  448. //alternative_sesitivity_multiplier = GM_getValue( 'alternative_sesitivity_multiplier', alternative_sesitivity_multiplier );
  449. console.log("Config for smoothscroll loaded!")
  450. }
  451.  
  452. function SaveConfig()
  453. {
  454. GM_setValue( 'smoothness', document.getElementById('ss-smoothness').value)
  455. GM_setValue( 'sensitivity', document.getElementById('ss-sensitivity').value)
  456. GM_setValue( 'acceleration', document.getElementById('ss-acceleration').value)
  457. GM_setValue( 'refreshrate', document.getElementById('ss-refreshrate').value)
  458. //console.log(document.getElementById('ss-alternative_sesitivity_multiplier').checked)
  459. console.log("Config for smoothscroll saved!")
  460. }
  461.  
  462. function CloseConfig()
  463. {
  464. var configbar = document.getElementById("ss-configbar");
  465. configbar.style.display = 'none';
  466. }
  467.  
  468. function InitConfigmenu()
  469. {
  470. console.log("Initiating smoothscroll config...");
  471. var configbar = document.createElement('div');
  472. configbar.setAttribute("id","ss-configbar");
  473. 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="100" value="' + smoothness + '"></td><td> Smoothness factor value (how strong the smoothing effect is)</td></tr><tr><td>Sensitivity</td><td><input type="number" id="ss-sensitivity" min="0" max="100" value="' + sensitivity + '"></td><td> Scroll sensitivity (duh)</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 (saves your finger)</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>';
  474. var configparent = document.getElementsByTagName("body")[0];
  475. configbar.style.width = '100%';
  476. configbar.style.display = 'none';
  477. configbar.style.position = 'absolute';
  478. configbar.style.zIndex = '9999';
  479. configbar.style.backgroundColor = 'white';
  480. configparent.insertBefore(configbar, configparent.childNodes[0]);
  481. document.getElementById("ss-close").onclick = function() {CloseConfig()};
  482. document.getElementById("ss-save").onclick = function() {SaveConfig()};
  483. //ss$("#ss-close").click(function() {
  484. ////ss$("#ss-config").animate({
  485. // height: '0'
  486. //}, 100);
  487. //ss$("#ss-configbar").hide("slow");
  488. //});
  489. //ss$("#ss-save").click(function() {
  490. //SaveConfig();
  491. //});
  492. ////ss$("#ss-configbar").hide();
  493. }
  494.  
  495. function ConfigSmoothscroll()
  496. {
  497. if (typeof $smoothscroll$ == 'undefined'){
  498. alert("Smoothscroll is not running properly on this page!");
  499. return;
  500. }
  501. ////ss$("#ss-config").animate({
  502. //height: '100px'
  503. //}, 100);
  504. //ss$("#ss-configbar").show("slow");
  505. var configbar = document.getElementById("ss-configbar");
  506. configbar.style.display = 'block';
  507. //ss$("html, body").animate({ scrollTop: 0 }, "slow");
  508. console.log("opening config...");
  509. }
  510.  
  511. /*
  512. function LoadjQuery(loading)
  513. {
  514. if (loading)
  515. {
  516. console.log("Waiting for jQuery...");
  517. if (typeof $ == 'undefined' || typeof jQuery == 'undefined' || jQueryVersion($)<minimal_jquery_version)
  518. {
  519. if (jquery_retry_count<jquery_retry_max)
  520. {
  521. jquery_retry_count++;
  522. setTimeout(function() {
  523. LoadjQuery(true);
  524. }, 100);
  525. }
  526. else
  527. {
  528. console.log("Failed to load smoothscroll!");
  529. if (typeof old$ != 'undefined') {
  530. $ = old$;
  531. }
  532. if (typeof oldjQuery != 'undefined') {
  533. jQuery = oldjQuery;
  534. }
  535. }
  536. }
  537. else
  538. {
  539. //ss$ = $;
  540. //ssjQuery = jQuery;
  541. console.log("jQuery loaded!");
  542. if (typeof old$ != 'undefined') {
  543. $ = old$;
  544. }
  545. if (typeof oldjQuery != 'undefined') {
  546. jQuery = oldjQuery;
  547. }
  548. console.log("Page jQuery version: " + jQueryVersion(old$));
  549. console.log("Script jQuery version: " + jQueryVersion(//ss$));
  550. InitSmoothscroll();
  551. }
  552. }
  553. else
  554. {
  555. console.log("Loading own jQuery...");
  556. jquery_retry_count = 0;
  557. var filename = "https://code.jquery.com/jquery-2.2.3.js";
  558. var fileref = document.createElement('script');
  559. fileref.setAttribute("type","text/javascript");
  560. fileref.setAttribute("src", filename);
  561.  
  562. if (typeof fileref!="undefined")
  563. {
  564. var scriptparent = document.getElementsByTagName("head")[0];
  565.  
  566. if (typeof scriptparent=="undefined")
  567. {
  568. var scriptparent = document.createElement('head');
  569. document.getElementsByTagName("html")[0].appendChild(scriptparent);
  570. }
  571. scriptparent.appendChild(fileref);
  572. }
  573. LoadjQuery(true);
  574. }
  575. }
  576. */
  577.  
  578. /*
  579. function Init()
  580. {
  581.  
  582. if (typeof $smoothscroll$ == 'undefined' )
  583. {
  584. var sitejquery = !(typeof $ == 'undefined' || typeof jQuery == 'undefined');
  585. if (sitejquery && jQueryVersion($)>=minimal_jquery_version)
  586. {
  587. //ss$ = $;
  588. //ssjQuery = jQuery;
  589. console.log("Reusing page jQuery...");
  590. console.log("Page jQuery version: " + jQueryVersion($));
  591. InitSmoothscroll();
  592. }
  593. else
  594. {
  595. if (typeof $ != 'undefined' && typeof old$ == 'undefined')
  596. {
  597. old$ = $;
  598. }
  599. if (typeof jQuery != 'undefined' && typeof oldjQuery == 'undefined')
  600. {
  601. oldjQuery = jQuery;
  602. }
  603. LoadjQuery(false);
  604. }
  605. }
  606. }
  607. */
  608.  
  609. if (typeof $smoothscroll$ == 'undefined'){
  610. console.log("Initiating smoothscroll...");
  611. //Init();
  612. InitSmoothscroll();
  613. GM_registerMenuCommand("Configurate smoothscroll", ConfigSmoothscroll);
  614. }
  615. else
  616. {
  617. console.log("Smoothscroll already loaded!");
  618. }