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.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. var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
  174. var rounddelta = Math.ceil(smoothdelta);
  175. //var smoothdelta = positiondelta*relativeratio;
  176. if (positiondelta<0)
  177. {
  178. smoothdelta = smoothdelta*(-1);
  179. rounddelta = rounddelta*(-1);
  180. }
  181.  
  182. //console.log(smoothdelta);
  183. //console.log(smoothdelta);
  184. //console.log(positiondelta-smoothdelta);
  185. //if (Math.abs( (positiondelta-smoothdelta) ) <= 1 )
  186. if (Math.abs( rounddelta ) < 1 )
  187. {
  188. /*
  189. //ss$(element).stop();
  190. ss$(element).animate({
  191. scrollTop: '+=' + Math.round(positiondelta)
  192. }, animationduration, "linear", function() {
  193. scrollpositiondelta(element, 0);
  194. if (DEBUG)
  195. {
  196. //ss$(element).css( "border", "1px solid red" );
  197. }
  198. });
  199. */
  200. if (Math.abs( positiondelta ) > 1 )
  201. {
  202. scroll_timeout = setTimeout(function() {
  203. element.scrollTop = element.scrollTop + rounddelta;
  204. scrollpositiondelta(element, positiondelta - rounddelta);
  205. UpdatePosition(element);
  206. }, Math.abs(animationduration/smoothdelta) );
  207. }
  208. else
  209. {
  210. scroll_timeout = setTimeout(function() {
  211. element.scrollTop = element.scrollTop + rounddelta;
  212. scrollpositiondelta(element, 0);
  213. }, animationduration);
  214.  
  215. }
  216.  
  217.  
  218. }
  219. else
  220. {
  221. /*
  222. //ss$(element).stop();
  223. ss$(element).animate({
  224. scrollTop: '+=' + Math.round(smoothdelta)
  225. }, animationduration, "linear", function() {
  226. scrollpositiondelta(element, positiondelta-smoothdelta);
  227. UpdatePosition(element);
  228. if (DEBUG)
  229. {
  230. //ss$(element).css( "border", "1px solid red" );
  231. }
  232. });
  233. */
  234. scroll_timeout = setTimeout(function() {
  235. element.scrollTop = element.scrollTop + rounddelta;
  236. scrollpositiondelta(element, positiondelta - rounddelta);
  237. UpdatePosition(element);
  238. }, animationduration);
  239. }
  240. }
  241.  
  242.  
  243. function MouseScroll (e) {
  244. //gameLoop();
  245. var mul = 1;
  246. if (!WEBKIT || alternative_sensitivity_multiplier)
  247. mul = 40;
  248. var x = e.deltaX*mul;
  249. var y = e.deltaY*mul;
  250. if (mousemoved)
  251. {
  252. scrollfocus = UpdateFocus(x,y);
  253. mousemoved = false;
  254. }
  255. var positiondelta = 0;
  256. var lastscrolltop = 0;
  257.  
  258. //var parentelement = //ss$(scrollfocus).parent();
  259. var rolled = y;
  260. //var lastscrolltop = //ss$(scrollfocus).scrollTop();
  261. if (!canscroll(scrollfocus, rolled))
  262. {
  263. //if (!//ss$(scrollfocus).is("html"))
  264. if (scrollfocus != document.documentElement)
  265. {
  266. scrollfocus = UpdateFocus(x,y);
  267. return false;
  268. }
  269. else
  270. {
  271. //console.log("true");
  272. return false;
  273. }
  274. }
  275. else
  276. {
  277. e.preventDefault();
  278. }
  279. positiondelta = scrollpositiondelta(scrollfocus);
  280. //console.log("positiondelta = " + positiondelta);
  281. var direction = rolled/Math.abs(rolled);
  282. var positiondeltadelta = Math.round(rolled*sensitivity + Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.09/sensitivity);
  283. positiondelta = positiondelta*1 + positiondeltadelta*1;
  284. //console.log("positiondelta + " + positiondeltadelta + " = " + positiondelta);
  285.  
  286. scrollpositiondelta(scrollfocus, positiondelta)
  287. //UpdatePosition(//ss$(scrollfocus));
  288. clearTimeout(scroll_timeout);
  289. UpdatePosition(scrollfocus);
  290. return true;
  291. }
  292.  
  293. function canscroll(element, dir)
  294. {
  295. //console.log(dir);
  296. if (dir>0)
  297. {
  298. dir = 1;
  299. }
  300. if (dir<0)
  301. {
  302. dir = -1;
  303. }
  304. var checkradius = 3; //pixels to try scrolling
  305. var canscroll0 = false;
  306. //var scrollable = //ss$(element);
  307. var scrollable = element;
  308. //var lastscrolltop = //ss$(scrollable).scrollTop();
  309. var lastscrolltop = scrollable.scrollTop;
  310.  
  311. //ss$(scrollable).scrollTop(lastscrolltop+dir*checkradius);
  312. scrollable.scrollTop = lastscrolltop+dir*checkradius;
  313. //if (//ss$(scrollable).scrollTop()!=lastscrolltop)
  314. if (scrollable.scrollTop!=lastscrolltop)
  315. {
  316. canscroll0 = true;
  317. }
  318. //ss$(scrollable).scrollTop(lastscrolltop);
  319. scrollable.scrollTop = lastscrolltop;
  320. //console.log("canscroll0: " + //ss$(element).prev().prop('nodeName') + " : " + canscroll0);
  321. return canscroll0;
  322. }
  323. function scrollpositiondelta(element, newdelta)
  324. {
  325. //var target = //ss$(element);
  326. var target = element;
  327. var delta = 0;
  328. if (newdelta!=undefined)
  329. {
  330. //console.log(dir);
  331. var dir = 0;
  332. if (newdelta>0)
  333. {
  334. dir = 1;
  335. }
  336. if (newdelta<0)
  337. {
  338. dir = -1;
  339. }
  340. target.setAttribute("positiondelta", newdelta );
  341. //console.log(newdelta);
  342. ////ss$(target)[0].setAttribute("positiondelta", newdelta );
  343. //ss$( target ).data( "positiondelta", newdelta );
  344. delta = newdelta;
  345. }
  346. else
  347. {
  348. var olddelta = target.getAttribute("positiondelta");
  349. //var olddelta = //ss$(target)[0].getAttribute("positiondelta");
  350. //var olddelta = //ss$( target ).data( "positiondelta" );
  351. if (olddelta!=undefined)
  352. {
  353. delta = olddelta;
  354. }
  355. }
  356. return delta*1;
  357. }
  358.  
  359. function UpdateFocus(x,y) {
  360. if (scrollfocus)
  361. {
  362. //scrollpositiondelta(scrollfocus, 0);
  363. //ss$(scrollfocus).stop();
  364. }
  365. var dir = y;
  366. var nodelist = document.querySelectorAll( ":hover" );
  367. ////ss$(nodelist).stop();
  368. //console.log(nodelist);
  369. if (WEBKIT)
  370. {
  371. //scrollfocus = //ss$('body');
  372. scrollfocus = document.body;
  373. }
  374. else
  375. {
  376. //scrollfocus = //ss$('html');
  377. scrollfocus = document.documentElement;
  378. }
  379. for (var i = nodelist.length-1; i >= 0 ; i--) {
  380. //var parent = nodelist[i-1];
  381. var newfocus = nodelist[i];
  382. if (DEBUG)
  383. {
  384. //ss$(newfocus).css( "border", "1px solid blue" );
  385. //var debugtimer = setTimeout(function(){ //ss$(newfocus).css( "border", "0px solid white" ); }, 1000);
  386. }
  387. //if (//ss$(newfocus).hasScrollBar3() && hasScrollBarVisible(newfocus) && canscroll(newfocus, dir) && hasscrollbars(newfocus))
  388. if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
  389. {
  390. //scrollfocus = ss$(newfocus);
  391. scrollfocus = newfocus;
  392. return newfocus;
  393. }
  394. }
  395.  
  396. return scrollfocus;
  397. }
  398. /*ss$('html').bind({
  399. mousemove: function(e) {
  400. mousemoved = true;
  401. },
  402. mousedown: function(e) {
  403. if (DEBUG)
  404. {
  405. console.log(scrollfocus);
  406. }
  407. if (scrollfocus)
  408. {
  409. scrollpositiondelta(scrollfocus, 0);
  410. ////ss$(scrollfocus).stop();
  411. }
  412. scrollfocus = UpdateFocus(0,0);
  413. //console.log("click");
  414. }
  415. });
  416. */
  417. document.documentElement.addEventListener("wheel", function(e){
  418. MouseScroll(e);
  419. mousemoved = true;
  420. //console.log("scrolling");
  421. });
  422.  
  423. //WEBKIT = 'webkitRequestAnimationFrame' in window;
  424. WEBKIT = document.compatMode == 'CSS1Compat' || document.compatMode == "BackCompat";
  425. //console.log("window: " + window);
  426. console.log("Smoothscroll initiated! Webkit: " + WEBKIT);
  427. $smoothscroll$ = true;
  428. }
  429.  
  430. /*
  431. var JQUERY = false;
  432. var OWNJQUERY = false;
  433. var OLDJQUERY = false;
  434.  
  435. var old$;
  436. var oldjQuery;
  437.  
  438. var ss$;
  439. */
  440.  
  441. /*
  442. function jQueryVersion(temp$)
  443. {
  444. if (typeof temp$ == 'undefined' || typeof temp$.fn == 'undefined' || typeof temp$.fn.jquery == 'undefined')
  445. {
  446. return 0;
  447. }
  448.  
  449. var versiontable = temp$.fn.jquery.split('.');
  450. var version = 0;
  451. for (var i = versiontable.length-1; i >= 0; i--) {
  452. var power = versiontable.length-i;
  453. version += Math.pow(10,power-1)*versiontable[i];
  454. }
  455. return version;
  456. }
  457. */
  458.  
  459. function LoadConfig()
  460. {
  461. smoothness = GM_getValue( 'smoothness', smoothness );
  462. sensitivity = GM_getValue( 'sensitivity', sensitivity );
  463. acceleration = GM_getValue( 'acceleration', acceleration );
  464. refreshrate = GM_getValue( 'refreshrate', refreshrate );
  465. //alternative_sesitivity_multiplier = GM_getValue( 'alternative_sesitivity_multiplier', alternative_sesitivity_multiplier );
  466. console.log("Config for smoothscroll loaded!")
  467. }
  468.  
  469. function SaveConfig()
  470. {
  471. GM_setValue( 'smoothness', document.getElementById('ss-smoothness').value)
  472. GM_setValue( 'sensitivity', document.getElementById('ss-sensitivity').value)
  473. GM_setValue( 'acceleration', document.getElementById('ss-acceleration').value)
  474. GM_setValue( 'refreshrate', document.getElementById('ss-refreshrate').value)
  475. //console.log(document.getElementById('ss-alternative_sesitivity_multiplier').checked)
  476. console.log("Config for smoothscroll saved!")
  477. }
  478.  
  479. function CloseConfig()
  480. {
  481. var configbar = document.getElementById("ss-configbar");
  482. configbar.style.display = 'none';
  483. }
  484.  
  485. function InitConfigmenu()
  486. {
  487. console.log("Initiating smoothscroll config...");
  488. var configbar = document.createElement('div');
  489. configbar.setAttribute("id","ss-configbar");
  490. 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>';
  491. var configparent = document.getElementsByTagName("body")[0];
  492. configbar.style.width = '100%';
  493. configbar.style.display = 'none';
  494. configbar.style.position = 'absolute';
  495. configbar.style.zIndex = '9999';
  496. configbar.style.backgroundColor = 'white';
  497. configparent.insertBefore(configbar, configparent.childNodes[0]);
  498. document.getElementById("ss-close").onclick = function() {CloseConfig()};
  499. document.getElementById("ss-save").onclick = function() {SaveConfig()};
  500. //ss$("#ss-close").click(function() {
  501. ////ss$("#ss-config").animate({
  502. // height: '0'
  503. //}, 100);
  504. //ss$("#ss-configbar").hide("slow");
  505. //});
  506. //ss$("#ss-save").click(function() {
  507. //SaveConfig();
  508. //});
  509. ////ss$("#ss-configbar").hide();
  510. }
  511.  
  512. function ConfigSmoothscroll()
  513. {
  514. if (typeof $smoothscroll$ == 'undefined'){
  515. alert("Smoothscroll is not running properly on this page!");
  516. return;
  517. }
  518. ////ss$("#ss-config").animate({
  519. //height: '100px'
  520. //}, 100);
  521. //ss$("#ss-configbar").show("slow");
  522. var configbar = document.getElementById("ss-configbar");
  523. configbar.style.display = 'block';
  524. //ss$("html, body").animate({ scrollTop: 0 }, "slow");
  525. console.log("opening config...");
  526. }
  527.  
  528. /*
  529. function LoadjQuery(loading)
  530. {
  531. if (loading)
  532. {
  533. console.log("Waiting for jQuery...");
  534. if (typeof $ == 'undefined' || typeof jQuery == 'undefined' || jQueryVersion($)<minimal_jquery_version)
  535. {
  536. if (jquery_retry_count<jquery_retry_max)
  537. {
  538. jquery_retry_count++;
  539. setTimeout(function() {
  540. LoadjQuery(true);
  541. }, 100);
  542. }
  543. else
  544. {
  545. console.log("Failed to load smoothscroll!");
  546. if (typeof old$ != 'undefined') {
  547. $ = old$;
  548. }
  549. if (typeof oldjQuery != 'undefined') {
  550. jQuery = oldjQuery;
  551. }
  552. }
  553. }
  554. else
  555. {
  556. //ss$ = $;
  557. //ssjQuery = jQuery;
  558. console.log("jQuery loaded!");
  559. if (typeof old$ != 'undefined') {
  560. $ = old$;
  561. }
  562. if (typeof oldjQuery != 'undefined') {
  563. jQuery = oldjQuery;
  564. }
  565. console.log("Page jQuery version: " + jQueryVersion(old$));
  566. console.log("Script jQuery version: " + jQueryVersion(//ss$));
  567. InitSmoothscroll();
  568. }
  569. }
  570. else
  571. {
  572. console.log("Loading own jQuery...");
  573. jquery_retry_count = 0;
  574. var filename = "https://code.jquery.com/jquery-2.2.3.js";
  575. var fileref = document.createElement('script');
  576. fileref.setAttribute("type","text/javascript");
  577. fileref.setAttribute("src", filename);
  578.  
  579. if (typeof fileref!="undefined")
  580. {
  581. var scriptparent = document.getElementsByTagName("head")[0];
  582.  
  583. if (typeof scriptparent=="undefined")
  584. {
  585. var scriptparent = document.createElement('head');
  586. document.getElementsByTagName("html")[0].appendChild(scriptparent);
  587. }
  588. scriptparent.appendChild(fileref);
  589. }
  590. LoadjQuery(true);
  591. }
  592. }
  593. */
  594.  
  595. /*
  596. function Init()
  597. {
  598.  
  599. if (typeof $smoothscroll$ == 'undefined' )
  600. {
  601. var sitejquery = !(typeof $ == 'undefined' || typeof jQuery == 'undefined');
  602. if (sitejquery && jQueryVersion($)>=minimal_jquery_version)
  603. {
  604. //ss$ = $;
  605. //ssjQuery = jQuery;
  606. console.log("Reusing page jQuery...");
  607. console.log("Page jQuery version: " + jQueryVersion($));
  608. InitSmoothscroll();
  609. }
  610. else
  611. {
  612. if (typeof $ != 'undefined' && typeof old$ == 'undefined')
  613. {
  614. old$ = $;
  615. }
  616. if (typeof jQuery != 'undefined' && typeof oldjQuery == 'undefined')
  617. {
  618. oldjQuery = jQuery;
  619. }
  620. LoadjQuery(false);
  621. }
  622. }
  623. }
  624. */
  625.  
  626. if (typeof $smoothscroll$ == 'undefined'){
  627. console.log("Initiating smoothscroll...");
  628. //Init();
  629. InitSmoothscroll();
  630. GM_registerMenuCommand("Configurate smoothscroll", ConfigSmoothscroll);
  631. }
  632. else
  633. {
  634. console.log("Smoothscroll already loaded!");
  635. }