Smoothscroll

Smooth scrolling on pages using javascript and jquery

目前为 2016-10-27 提交的版本,查看 最新版本

  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 1.2
  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 = 25;
  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 baserefreshrate = 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. if (smoothness>100)
  70. {
  71. smoothness = 100;
  72. }
  73.  
  74. if (baserefreshrate <= 30 || baserefreshrate>144)
  75. {
  76. baserefreshrate = 144;
  77. }
  78. refreshrate = baserefreshrate;
  79.  
  80. var animationduration = Math.round(1000/refreshrate);
  81. //var relativeratio = Math.round(51-smoothness/2)/100;
  82. var relativeratio = Math.round(1/(1+smoothness*refreshrate/baserefreshrate)*100)/100;
  83. //var relativeratio = relativeratio;
  84.  
  85.  
  86.  
  87. var lastLoop = new Date;
  88. //var lastrefreshrate = 0;
  89. function gameLoop() {
  90. var thisLoop = new Date;
  91. var refreshrate0 = 1000 / (thisLoop - lastLoop + 1);
  92. lastLoop = thisLoop;
  93. refreshrate = refreshrate + (refreshrate0-refreshrate)*0.1;
  94. refreshrate = Math.round(refreshrate);
  95. if (DEBUG)
  96. {
  97. console.log(refreshrate);
  98. }
  99. //console.log(refreshrate);
  100. animationduration = Math.round(1000/(refreshrate));
  101. //var relativeratio = Math.round(51-smoothness/2)/100;
  102. relativeratio = Math.round(1/(1+smoothness*refreshrate/baserefreshrate)*100)/100;
  103. }
  104. gameLoop();
  105.  
  106.  
  107. function InitSmoothscroll()
  108. {
  109. //LoadConfig();
  110.  
  111. //InitConfigmenu();
  112.  
  113. var startposition = false;
  114. var targetposition = 0;
  115. var position = 0;
  116.  
  117. var scrollfocus = ss$('body');
  118. var mousemoved = true;
  119. function hasScrollBarVisible(element)
  120. {
  121. //return (document.documentElement.scrollHeight !== document.documentElement.clientHeight);
  122. // Get the computed style of the body element
  123. var cStyle = element.currentStyle||window.getComputedStyle(element, "");
  124. // Check the overflow and overflowY properties for "auto" and "visible" values
  125. var scrollbar1 = cStyle.overflow == "scroll" || cStyle.overflowY == "scroll";
  126.  
  127. var scrollbar2 = cStyle.overflow == "auto" || cStyle.overflowY == "auto";
  128. var scrollbar = scrollbar1 || scrollbar2;
  129. return scrollbar;
  130. }
  131.  
  132.  
  133. function hasscrollbars(scrollfocus)
  134. {
  135. var hasvisiblescrollbars = hasScrollBarVisible(scrollfocus);
  136. var parentelement = ss$(scrollfocus).parent();
  137. if ( ss$(parentelement))
  138. {
  139. if (ss$(parentelement).is("textarea") || ss$(scrollfocus).is("textarea") || ss$(parentelement).is("article") || ss$(parentelement).is("article"))
  140. {
  141. return true;
  142. }
  143. else
  144. {
  145. if (ss$(parentelement).hasClass( "yt-scrollbar" ) || ss$(scrollfocus).hasClass( "yt-scrollbar" ))
  146. {
  147. return true;
  148. }
  149. return hasvisiblescrollbars;
  150. }
  151. }
  152. else
  153. {
  154. return hasvisiblescrollbars;
  155. }
  156. return false;
  157. }
  158.  
  159. function UpdatePosition(element)
  160. {
  161. gameLoop();
  162. var positiondelta = ss$(element)[0].getAttribute( "positiondelta" );
  163. //var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
  164. var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
  165. if (positiondelta<0)
  166. {
  167. smoothdelta = smoothdelta*(-1);
  168. }
  169. //var relative = position - ss$(element).scrollTop();
  170. //console.log("smoothdelta:" + smoothdelta);
  171. if (Math.abs( (positiondelta-smoothdelta)) <= 1 )
  172. {
  173. ss$(element).stop();
  174. ss$(element).animate({
  175. scrollTop: '+=' + Math.round(positiondelta)
  176. }, animationduration, "linear", function() {
  177. ss$(element).attr( "positiondelta",0 );
  178. ss$(element)[0].setAttribute( "positiondelta",0 );
  179. if (DEBUG)
  180. {
  181. ss$(element).css( "border", "1px solid red" );
  182. }
  183. });
  184. }
  185. else
  186. {
  187. ss$(element).stop();
  188. ss$(element).animate({
  189. scrollTop: '+=' + Math.round(smoothdelta)
  190. }, animationduration, "linear", function() {
  191. ss$(element).attr( "positiondelta",positiondelta-smoothdelta );
  192. ss$(element)[0].setAttribute("positiondelta",positiondelta-smoothdelta );
  193. UpdatePosition(element);
  194. if (DEBUG)
  195. {
  196. ss$(element).css( "border", "1px solid red" );
  197. }
  198. });
  199. }
  200. }
  201.  
  202.  
  203. function MouseScroll (e) {
  204. gameLoop();
  205. var mul = 1;
  206. if (!WEBKIT || alternative_sensitivity_multiplier)
  207. mul = 40;
  208. var x = e.deltaX*mul;
  209. var y = e.deltaY*mul;
  210. if (mousemoved)
  211. {
  212. scrollfocus = UpdateFocus(x,y);
  213. mousemoved = false;
  214. }
  215. //
  216. var positiondelta = 0;
  217. var lastscrolltop = 0;
  218.  
  219. var parentelement = ss$(scrollfocus).parent();
  220. var rolled = y;
  221. var lastscrolltop = ss$(scrollfocus).scrollTop();
  222. //ss$(scrollfocus).scrollTop(lastscrolltop+rolled);
  223. //if (ss$(scrollfocus).scrollTop()==lastscrolltop)
  224. if (!canscroll(scrollfocus, rolled))
  225. {
  226. if (!ss$(scrollfocus).is("html"))
  227. {
  228. //scrollfocus = ss$(scrollfocus);
  229. //focus = UpdateFocus(event);
  230. //return MouseScroll (event);
  231. //console.log("false");
  232. //return false;
  233. scrollfocus = UpdateFocus(x,y);
  234. return false;
  235. }
  236. else
  237. {
  238. //console.log("true");
  239. return false;
  240. }
  241. }
  242. else
  243. {
  244. e.preventDefault();
  245. }
  246. //ss$(scrollfocus).scrollTop(lastscrolltop);
  247. if (ss$(scrollfocus)[0].getAttribute("positiondelta")==undefined)
  248. {
  249. positiondelta = 0;
  250. //console.log("positiondelta: undefined");
  251. }
  252. else
  253. {
  254. positiondelta = ss$(scrollfocus)[0].getAttribute("positiondelta");
  255. //console.log("positiondelta: " + positiondelta);
  256. }
  257. positiondelta = positiondelta*1;
  258. var direction = rolled/Math.abs(rolled);
  259. //var positiondeltadelta = rolled*sensitivity + Math.sqrt(Math.abs(positiondelta/rolled))*acceleration*rolled;
  260. //var positiondeltadelta = rolled*(sensitivity+Math.sqrt(Math.abs(positiondelta))*acceleration);
  261. var positiondeltadelta = Math.round(rolled*sensitivity + Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.05/sensitivity);
  262. positiondelta = positiondelta + positiondeltadelta;
  263. ss$(scrollfocus)[0].setAttribute("positiondelta",positiondelta );
  264. UpdatePosition(ss$(scrollfocus));
  265. return true;
  266. }
  267.  
  268. function canscroll(element, dir)
  269. {
  270. if (dir>0)
  271. {
  272. dir = 1;
  273. }
  274. else
  275. {
  276. dir = -1;
  277. }
  278. var scrollable = ss$(element);
  279. var lastscrolltop = ss$(scrollable).scrollTop();
  280. ss$(scrollable).scrollTop(lastscrolltop+dir);
  281. if (ss$(scrollable).scrollTop()==lastscrolltop && dir!=0)
  282. {
  283. ss$(scrollable).scrollTop(lastscrolltop);
  284. return false;
  285. }
  286. else
  287. {
  288. ss$(scrollable).scrollTop(lastscrolltop);
  289. return true;
  290. }
  291. }
  292.  
  293. function UpdateFocus(x,y) {
  294. if (scrollfocus)
  295. {
  296. //ss$(scrollfocus)[0].setAttribute( "positiondelta",0 );
  297. ss$(scrollfocus).stop();
  298. }
  299. var dir = y;
  300. var nodelist = document.querySelectorAll( ":hover" );
  301. //ss$(nodelist).stop();
  302. //console.log(nodelist);
  303. if (WEBKIT)
  304. {
  305. scrollfocus = ss$('body');
  306. }
  307. else
  308. {
  309. scrollfocus = ss$('html');
  310. }
  311. for (var i = nodelist.length-1; i >= 0 ; i--) {
  312. //var parent = nodelist[i-1];
  313. var newfocus = nodelist[i];
  314. if (DEBUG)
  315. {
  316. ss$(newfocus).css( "border", "1px solid blue" );
  317. //var debugtimer = setTimeout(function(){ ss$(newfocus).css( "border", "0px solid white" ); }, 1000);
  318. }
  319. //if (ss$(newfocus).hasScrollBar3() && hasScrollBarVisible(newfocus) && canscroll(newfocus, dir) && hasscrollbars(newfocus))
  320. if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
  321. {
  322. scrollfocus = ss$(newfocus);
  323. return newfocus;
  324. }
  325. }
  326.  
  327. return scrollfocus;
  328. }
  329. ss$('html').bind({
  330. //mousewheel: function(e) {
  331. //if (DEBUG)
  332. //{
  333. // console.log(scrollfocus);
  334. //}
  335. //console.log("scrolling");
  336. //MouseScroll(e.originalEvent);
  337. //},
  338. mousemove: function(e) {
  339. mousemoved = true;
  340. },
  341. mousedown: function(e) {
  342. if (DEBUG)
  343. {
  344. console.log(scrollfocus);
  345. }
  346. if (scrollfocus)
  347. {
  348. ss$(scrollfocus)[0].setAttribute( "positiondelta",0 );
  349. //ss$(scrollfocus).stop();
  350. }
  351. scrollfocus = UpdateFocus(0,0);
  352. //console.log("click");
  353. }
  354. });
  355. //Init(window);
  356.  
  357. document.documentElement.addEventListener("wheel", function(e){
  358. MouseScroll(e);
  359. //console.log("scrolling");
  360. });
  361. /*var oldpos = ss$('body').scrollTop();
  362. ss$('body').scrollTop(1);
  363. var iswebkit = ss$('body').scrollTop()>0;
  364. ss$('body').scrollTop(oldpos);*/
  365.  
  366. //WEBKIT = 'webkitRequestAnimationFrame' in window;
  367. WEBKIT = document.compatMode == 'CSS1Compat' || document.compatMode == "BackCompat";
  368. //console.log("window: " + window);
  369. console.log("Smoothscroll initiated! Webkit: " + WEBKIT);
  370. }
  371.  
  372. var JQUERY = false;
  373. var OWNJQUERY = false;
  374. var OLDJQUERY = false;
  375.  
  376. var old$;
  377. var oldjQuery;
  378.  
  379. var ss$;
  380.  
  381. function jQueryVersion(temp$)
  382. {
  383. if (typeof temp$ == 'undefined' || typeof temp$.fn == 'undefined' || typeof temp$.fn.jquery == 'undefined')
  384. {
  385. return 0;
  386. }
  387.  
  388. var versiontable = temp$.fn.jquery.split('.');
  389. var version = 0;
  390. for (var i = versiontable.length-1; i >= 0; i--) {
  391. var power = versiontable.length-i;
  392. version += Math.pow(10,power-1)*versiontable[i];
  393. }
  394. return version;
  395. }
  396.  
  397.  
  398. function LoadConfig()
  399. {
  400. smoothness = GM_getValue( 'smoothness', smoothness );
  401. sensitivity = GM_getValue( 'sensitivity', sensitivity );
  402. acceleration = GM_getValue( 'acceleration', acceleration );
  403. baserefreshrate = GM_getValue( 'baserefreshrate', baserefreshrate );
  404. //alternative_sesitivity_multiplier = GM_getValue( 'alternative_sesitivity_multiplier', alternative_sesitivity_multiplier );
  405. console.log("Config for smoothscroll loaded!")
  406. }
  407.  
  408. function SaveConfig()
  409. {
  410. GM_setValue( 'smoothness', document.getElementById('ss-smoothness').value)
  411. GM_setValue( 'sensitivity', document.getElementById('ss-sensitivity').value)
  412. GM_setValue( 'acceleration', document.getElementById('ss-acceleration').value)
  413. GM_setValue( 'baserefreshrate', document.getElementById('ss-baserefreshrate').value)
  414. //console.log(document.getElementById('ss-alternative_sesitivity_multiplier').checked)
  415. console.log("Config for smoothscroll saved!")
  416. }
  417.  
  418. function InitConfigmenu()
  419. {
  420. console.log("Initiating smoothscroll config...");
  421. var configbar = document.createElement('div');
  422. configbar.setAttribute("id","ss-configbar");
  423. 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-baserefreshrate" min="1" max="100" value="' + baserefreshrate + '"></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>';
  424. var configparent = document.getElementsByTagName("body")[0];
  425. configbar.style.width = '100%';
  426. configbar.style.display = 'none';
  427. configbar.style.position = 'absolute';
  428. configbar.style.zIndex = '9999';
  429. configbar.style.backgroundColor = 'white';
  430. configparent.insertBefore(configbar, configparent.childNodes[0]);
  431. ss$("#ss-close").click(function() {
  432. //ss$("#ss-config").animate({
  433. // height: '0'
  434. //}, 100);
  435. ss$("#ss-configbar").hide("slow");
  436. });
  437. ss$("#ss-save").click(function() {
  438. SaveConfig();
  439. });
  440. //ss$("#ss-configbar").hide();
  441. }
  442.  
  443. function ConfigSmoothscroll()
  444. {
  445. if (typeof ss$ == 'undefined'){
  446. alert("Smoothscroll is not running properly on this page!");
  447. return;
  448. }
  449. //ss$("#ss-config").animate({
  450. // height: '100px'
  451. //}, 100);
  452. ss$("#ss-configbar").show("slow");
  453. ss$("html, body").animate({ scrollTop: 0 }, "slow");
  454. }
  455.  
  456. function LoadjQuery(loading)
  457. {
  458. if (loading)
  459. {
  460. console.log("Waiting for jQuery...");
  461. if (typeof $ == 'undefined' || typeof jQuery == 'undefined' || jQueryVersion($)<minimal_jquery_version)
  462. {
  463. if (jquery_retry_count<jquery_retry_max)
  464. {
  465. jquery_retry_count++;
  466. setTimeout(function() {
  467. LoadjQuery(true);
  468. }, 100);
  469. }
  470. else
  471. {
  472. console.log("Failed to load smoothscroll!");
  473. if (typeof old$ != 'undefined') {
  474. $ = old$;
  475. }
  476. if (typeof oldjQuery != 'undefined') {
  477. jQuery = oldjQuery;
  478. }
  479. }
  480. }
  481. else
  482. {
  483. ss$ = $;
  484. ssjQuery = jQuery;
  485. console.log("jQuery loaded!");
  486. if (typeof old$ != 'undefined') {
  487. $ = old$;
  488. }
  489. if (typeof oldjQuery != 'undefined') {
  490. jQuery = oldjQuery;
  491. }
  492. console.log("Page jQuery version: " + jQueryVersion(old$));
  493. console.log("Script jQuery version: " + jQueryVersion(ss$));
  494. InitSmoothscroll();
  495. }
  496. }
  497. else
  498. {
  499. console.log("Loading own jQuery...");
  500. jquery_retry_count = 0;
  501. var filename = "https://code.jquery.com/jquery-2.2.3.js";
  502. var fileref = document.createElement('script');
  503. fileref.setAttribute("type","text/javascript");
  504. fileref.setAttribute("src", filename);
  505.  
  506. if (typeof fileref!="undefined")
  507. {
  508. var scriptparent = document.getElementsByTagName("head")[0];
  509.  
  510. if (typeof scriptparent=="undefined")
  511. {
  512. var scriptparent = document.createElement('head');
  513. document.getElementsByTagName("html")[0].appendChild(scriptparent);
  514. }
  515. scriptparent.appendChild(fileref);
  516. }
  517. LoadjQuery(true);
  518. }
  519. }
  520.  
  521.  
  522. function Init()
  523. {
  524.  
  525. if (typeof ss$ == 'undefined' )
  526. {
  527. var sitejquery = !(typeof $ == 'undefined' || typeof jQuery == 'undefined');
  528. if (sitejquery && jQueryVersion($)>=minimal_jquery_version)
  529. {
  530. ss$ = $;
  531. ssjQuery = jQuery;
  532. console.log("Reusing page jQuery...");
  533. console.log("Page jQuery version: " + jQueryVersion($));
  534. InitSmoothscroll();
  535. }
  536. else
  537. {
  538. if (typeof $ != 'undefined' && typeof old$ == 'undefined')
  539. {
  540. old$ = $;
  541. }
  542. if (typeof jQuery != 'undefined' && typeof oldjQuery == 'undefined')
  543. {
  544. oldjQuery = jQuery;
  545. }
  546. LoadjQuery(false);
  547. }
  548. }
  549. }
  550.  
  551. if (typeof ss$ == 'undefined'){
  552. console.log("Initiating smoothscroll...");
  553. Init();
  554. //InitSmoothscroll();
  555. GM_registerMenuCommand("Configurate smoothscroll", ConfigSmoothscroll);
  556. }
  557. else
  558. {
  559. console.log("Smoothscroll already loaded!");
  560. }