Smoothscroll

Smooth scrolling on pages using javascript and jquery

当前为 2016-05-24 提交的版本,查看 最新版本

  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-load
  8. // @grant GM_info
  9. // @grant unsafeWindow
  10. // @version 0.0.1.20160524014511
  11. // ==/UserScript==
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18. //SETTINGS HERE
  19.  
  20. //Smoothness factor value (how strong the smoothing effect is)
  21. //values: 1-(infinite) (default = 50)
  22. var smoothness = 30;
  23.  
  24.  
  25. //Scroll sensitivity
  26. //values: anything? (default 1.00)
  27. var sensitivity = 1.00;
  28.  
  29.  
  30. //Acceleration sensitivity
  31. //values: anything? (default 1.00)
  32. var acceleration = 1.00;
  33.  
  34.  
  35. //Refreshrate setting
  36. //values: 30-144 (default = 60/72/120/144 = same as your monitor hz)
  37. var baserefreshrate = 72;
  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_sesitivity_multiplier = false;
  43.  
  44.  
  45. var minimal_jquery_version = 200;
  46.  
  47.  
  48.  
  49. var DEBUG = false;
  50.  
  51. //CODE STARTS HERE
  52. if (window.top != window.self) //don't run on frames or iframes
  53. return;
  54.  
  55.  
  56.  
  57. if (smoothness>100)
  58. {
  59. smoothness = 100;
  60. }
  61.  
  62. if (baserefreshrate <= 30 || baserefreshrate>144)
  63. {
  64. baserefreshrate = 144;
  65. }
  66. refreshrate = baserefreshrate;
  67.  
  68. var animationduration = Math.round(1000/refreshrate);
  69. //var relativeratio = Math.round(51-smoothness/2)/100;
  70. var relativeratio = Math.round(1/(1+smoothness)*100)/100;
  71. //var relativeratio = relativeratio;
  72.  
  73.  
  74.  
  75. var lastLoop = new Date;
  76. //var lastrefreshrate = 0;
  77. function gameLoop() {
  78. var thisLoop = new Date;
  79. var refreshrate0 = 1000 / (thisLoop - lastLoop + 1);
  80. lastLoop = thisLoop;
  81. refreshrate = refreshrate + (refreshrate0-refreshrate)*0.01;
  82. refreshrate = Math.round(refreshrate);
  83. if (DEBUG)
  84. {
  85. console.log(refreshrate);
  86. }
  87. animationduration = Math.round(1000/(refreshrate));
  88. //var relativeratio = Math.round(51-smoothness/2)/100;
  89. relativeratio = Math.round(1/(1+smoothness*refreshrate/baserefreshrate)*100)/100;
  90. }
  91. gameLoop();
  92.  
  93.  
  94. function InitSmoothscroll()
  95. {
  96.  
  97. var startposition = false;
  98. var targetposition = 0;
  99. var position = 0;
  100.  
  101. var scrollfocus = $0('body');
  102. function hasScrollBarVisible(element)
  103. {
  104. //return (document.documentElement.scrollHeight !== document.documentElement.clientHeight);
  105. // Get the computed style of the body element
  106. var cStyle = element.currentStyle||window.getComputedStyle(element, "");
  107. // Check the overflow and overflowY properties for "auto" and "visible" values
  108. var scrollbar1 = cStyle.overflow == "scroll" || cStyle.overflowY == "scroll";
  109.  
  110. var scrollbar2 = cStyle.overflow == "auto" || cStyle.overflowY == "auto";
  111. var scrollbar = scrollbar1 || scrollbar2;
  112. return scrollbar;
  113. }
  114.  
  115.  
  116. function hasscrollbars(scrollfocus)
  117. {
  118. var hasvisiblescrollbars = hasScrollBarVisible(scrollfocus);
  119. var parentelement = $0(scrollfocus).parent();
  120. if ( $0(parentelement))
  121. {
  122. //if ($0(parentelement).is("textarea") || $0(scrollfocus).is("textarea"))
  123. if ($0(parentelement).is("textarea") || $0(scrollfocus).is("textarea") || $0(parentelement).is("article") || $0(parentelement).is("article"))
  124. {
  125. return true;
  126. }
  127. else
  128. {
  129. if ($0(parentelement).hasClass( "yt-scrollbar" ) || $0(scrollfocus).hasClass( "yt-scrollbar" ))
  130. {
  131. return true;
  132. }
  133. return hasvisiblescrollbars;
  134. }
  135. }
  136. else
  137. {
  138. //scrollfocus = $0('body');
  139. //maxposition = $0(scrollfocus).height();
  140. return hasvisiblescrollbars;
  141. }
  142. return false;
  143. }
  144.  
  145. function UpdatePosition(element)
  146. {
  147. gameLoop();
  148. var positiondelta = $0(element)[0].getAttribute( "positiondelta" );
  149. //var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
  150. var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
  151. if (positiondelta<0)
  152. {
  153. smoothdelta = smoothdelta*(-1);
  154. }
  155. //var relative = position - $0(element).scrollTop();
  156. //console.log("smoothdelta:" + smoothdelta);
  157. if (Math.abs( (positiondelta-smoothdelta)) <= 1 )
  158. {
  159. $0(element).stop();
  160. $0(element).animate({
  161. scrollTop: '+=' + Math.round(positiondelta)
  162. }, animationduration, "linear", function() {
  163. $0(element).attr( "positiondelta",0 );
  164. $0(element)[0].setAttribute( "positiondelta",0 );
  165. if (DEBUG)
  166. {
  167. $0(element).css( "border", "1px solid red" );
  168. }
  169. });
  170. }
  171. else
  172. {
  173. $0(element).stop();
  174. $0(element).animate({
  175. scrollTop: '+=' + Math.round(smoothdelta)
  176. }, animationduration, "linear", function() {
  177. $0(element).attr( "positiondelta",positiondelta-smoothdelta );
  178. $0(element)[0].setAttribute("positiondelta",positiondelta-smoothdelta );
  179. UpdatePosition(element);
  180. if (DEBUG)
  181. {
  182. $0(element).css( "border", "1px solid red" );
  183. }
  184. });
  185. }
  186. }
  187.  
  188.  
  189. function MouseScroll (x,y,e) {
  190. scrollfocus = UpdateFocus(x,y);
  191. var positiondelta = 0;
  192. var lastscrolltop = 0;
  193.  
  194. var parentelement = $0(scrollfocus).parent();
  195. if ( $0(parentelement))
  196. {
  197. if ($0(parentelement).is("textarea") || $0(scrollfocus).is("textarea"))
  198. {
  199. //return true;
  200. }
  201. else
  202. {
  203. if ( $0(parentelement).height() < $0(scrollfocus).height())
  204. {
  205. //maxposition = $0(scrollfocus).height() - $0(parentelement).height();
  206. }
  207. else
  208. {
  209. if ($0(scrollfocus).height()==0)
  210. {
  211. //scrollfocus = $0('body');
  212. //maxposition = $0(scrollfocus).height();
  213. }
  214.  
  215. //scrollfocus = $0('body');
  216. //return MouseScroll (event);
  217. //return true;
  218. }
  219. }
  220. }
  221. else
  222. {
  223. scrollfocus = $0('body');
  224. //maxposition = $0(scrollfocus).height();
  225. }
  226. var rolled = y;
  227. //console.log("rolled: " + rolled);
  228. //if ($0(scrollfocus).data("positiondelta" )==undefined)
  229. //$embellishment.data("embellishmentid",1)
  230. if ($0(scrollfocus)[0].getAttribute("positiondelta")==undefined)
  231. {
  232. positiondelta = 0;
  233. //console.log("positiondelta: undefined");
  234. }
  235. else
  236. {
  237. positiondelta = $0(scrollfocus)[0].getAttribute("positiondelta");
  238. //console.log("positiondelta: " + positiondelta);
  239. }
  240. positiondelta = positiondelta*1;
  241. var lastscrolltop = $0(scrollfocus).scrollTop();
  242. $0(scrollfocus).scrollTop(lastscrolltop+rolled);
  243. if ($0(scrollfocus).scrollTop()==lastscrolltop)
  244. {
  245. if (!$0(scrollfocus).is("body"))
  246. {
  247. focus = parentelement;
  248. //focus = UpdateFocus(event);
  249. //return MouseScroll (event);
  250. //console.log("false");
  251. return false;
  252. }
  253. else
  254. {
  255. //console.log("true");
  256. return false;
  257. }
  258. }
  259. else
  260. {
  261. e.preventDefault();
  262. }
  263. $0(scrollfocus).scrollTop(lastscrolltop);
  264. var direction = rolled/Math.abs(rolled);
  265. //var positiondeltadelta = rolled*sensitivity + Math.sqrt(Math.abs(positiondelta/rolled))*acceleration*rolled;
  266. //var positiondeltadelta = rolled*(sensitivity+Math.sqrt(Math.abs(positiondelta))*acceleration);
  267. //
  268. var positiondeltadelta = Math.round(rolled*sensitivity + Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.03/sensitivity);
  269. positiondelta = positiondelta + positiondeltadelta;
  270. $0(scrollfocus)[0].setAttribute("positiondelta",positiondelta );
  271. UpdatePosition($0(scrollfocus));
  272. //element.innerHTML = "";
  273. //console.log("pos:" + position);
  274. //event.preventDefault();
  275. return true;
  276. }
  277.  
  278. function canscroll(element, dir)
  279. {
  280. var scrollable = $0(element);
  281. var lastscrolltop = $0(scrollable).scrollTop();
  282. $0(scrollable).scrollTop(lastscrolltop+dir);
  283. if ($0(scrollable).scrollTop()==lastscrolltop)
  284. {
  285. $0(scrollable).scrollTop(lastscrolltop);
  286. return false;
  287. }
  288. else
  289. {
  290. $0(scrollable).scrollTop(lastscrolltop);
  291. return true;
  292. }
  293. }
  294. function UpdateFocus(x,y) {
  295. /*var dir = 0;
  296. if ('wheelDelta' in event) {
  297. dir = event.wheelDelta;
  298. }
  299. else { // Firefox
  300. // The measurement units of the detail and wheelDelta properties are different.
  301. dir = event.detail*(-120);
  302. }*/
  303. var dir = y;
  304. //console.log(dir);
  305. //dir = dir*(-1);
  306. //
  307. var nodelist = document.querySelectorAll( ":hover" );
  308. $0(nodelist).stop();
  309. scrollfocus = $0('body');
  310. for (var i = nodelist.length-1; i >= 0; i--) {
  311. //var parent = nodelist[i-1];
  312. var newfocus = nodelist[i];
  313. if (DEBUG)
  314. {
  315. $0(newfocus).css( "border", "1px solid blue" );
  316. //var debugtimer = setTimeout(function(){ $0(newfocus).css( "border", "0px solid white" ); }, 1000);
  317. }
  318. //if ($0(newfocus).hasScrollBar3() && hasScrollBarVisible(newfocus) && canscroll(newfocus, dir) && hasscrollbars(newfocus))
  319. if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
  320. {
  321. scrollfocus = $0(newfocus);
  322. return newfocus;
  323. }
  324. }
  325.  
  326. return scrollfocus;
  327. }
  328. $0('body').bind({
  329. /*
  330. mousewheel: function(e) {
  331. if (DEBUG)
  332. {
  333. console.log(scrollfocus);
  334. }
  335. console.log("scrolling");
  336. MouseScroll(e.originalEvent);
  337. },
  338. */
  339. mousedown: function(e) {
  340. if (DEBUG)
  341. {
  342. console.log(scrollfocus);
  343. }
  344. if (scrollfocus)
  345. {
  346. $0(scrollfocus)[0].setAttribute( "positiondelta",0 );
  347. $0(scrollfocus).stop();
  348. }
  349. //scrollfocus = UpdateFocus(e.originalEvent);
  350. //console.log("click");
  351. }
  352. });
  353. //Init(window);
  354.  
  355. (function(window,document) {
  356.  
  357. var prefix = "", _addEventListener, onwheel, support;
  358.  
  359. // detect event model
  360. if ( window.addEventListener ) {
  361. _addEventListener = "addEventListener";
  362. } else {
  363. _addEventListener = "attachEvent";
  364. prefix = "on";
  365. }
  366.  
  367. // detect available wheel event
  368. support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
  369. document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
  370. "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
  371.  
  372. window.addWheelListener = function( elem, callback, useCapture ) {
  373. _addWheelListener( elem, support, callback, useCapture );
  374.  
  375. // handle MozMousePixelScroll in older Firefox
  376. if( support == "DOMMouseScroll" ) {
  377. _addWheelListener( elem, "MozMousePixelScroll", callback, useCapture );
  378. }
  379. };
  380.  
  381. function _addWheelListener( elem, eventName, callback, useCapture ) {
  382. elem[ _addEventListener ]( prefix + eventName, support == "wheel" ? callback : function( originalEvent ) {
  383. !originalEvent && ( originalEvent = window.event );
  384.  
  385. // create a normalized event object
  386. var event = {
  387. // keep a ref to the original event object
  388. originalEvent: originalEvent,
  389. target: originalEvent.target || originalEvent.srcElement,
  390. type: "wheel",
  391. deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
  392. deltaX: 0,
  393. deltaZ: 0,
  394. preventDefault: function() {
  395. originalEvent.preventDefault ?
  396. originalEvent.preventDefault() :
  397. originalEvent.returnValue = false;
  398. }
  399. };
  400. // calculate deltaY (and deltaX) according to the event
  401. if ( support == "mousewheel" ) {
  402. event.deltaY = - 1/40 * originalEvent.wheelDelta;
  403. // Webkit also support wheelDeltaX
  404. originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX );
  405. } else {
  406. event.deltaY = originalEvent.detail;
  407. }
  408.  
  409. // it's time to fire the callback
  410. return callback( event );
  411.  
  412. }, useCapture || false );
  413. }
  414.  
  415. })(window,document);
  416. addWheelListener( window, function( e ) {
  417. var mul = 1;
  418. if (alternative_sesitivity_multiplier)
  419. mul = 40;
  420. //console.log( e.deltaY );
  421. MouseScroll(e.deltaX*mul,e.deltaY*mul, e);
  422. });
  423.  
  424. console.log("Smoothscroll initiated!");
  425. }
  426.  
  427.  
  428. var JQUERY = false;
  429. var OWNJQUERY = false;
  430. var OLDJQUERY = false;
  431.  
  432. //max retries
  433. var r_max = 10;
  434. var r_count = 0;
  435.  
  436. function Init() {
  437. //if (typeof jQuery == 'function') {
  438. //if (typeof jQuery == 'undefined' || typeof $ == 'undefined' )
  439. JQUERY = true;
  440. if (typeof $ == 'undefined' )
  441. {
  442. JQUERY = false;
  443. }
  444. OWNJQUERY = true;
  445. if (typeof $0 == 'undefined' )
  446. {
  447. OWNJQUERY = false;
  448. }
  449. if (!OWNJQUERY){
  450. if (JQUERY) {
  451. var versiontable = $.fn.jquery.split('.');
  452. var version = 0;
  453. for (var i = versiontable.length-1; i >= 0; i--) {
  454. var power = versiontable.length-i;
  455. version += Math.pow(10,power-1)*versiontable[i];
  456. }
  457.  
  458. if (version<=minimal_jquery_version)
  459. {
  460. console.log("Page jQuery OLD! Version: " + version);
  461. if (typeof old$ == 'undefined') {
  462. console.log("Saving old jQuery...");
  463. old$ = $;
  464. oldjQuery = jQuery;
  465. OLDJQUERY = true;
  466. }
  467. }
  468. else
  469. {
  470. $0 = $;
  471. OWNJQUERY = true;
  472. }
  473. }
  474. else
  475. {
  476. console.log("Page jQuery Missing!");
  477. }
  478. }
  479. if (!OWNJQUERY)
  480. {
  481. console.log("Loading new jQuery...");
  482.  
  483. //this.$ = this.jQuery = jQuery.noConflict(true);
  484. //var $ = jQuery.noConflict();
  485.  
  486. //this.$ = this.jQuery = jQuery.noConflict(true);
  487.  
  488.  
  489. var filename = "https://code.jquery.com/jquery-2.2.3.js";
  490. var fileref = document.createElement('script');
  491. fileref.setAttribute("type","text/javascript");
  492. fileref.setAttribute("src", filename);
  493.  
  494. if (typeof fileref!="undefined")
  495. {
  496. var scriptparent = document.getElementsByTagName("head")[0];
  497.  
  498. if (typeof scriptparent=="undefined")
  499. {
  500. var scriptparent = document.createElement('head');
  501. document.getElementsByTagName("html")[0].appendChild(scriptparent);
  502. }
  503. scriptparent.appendChild(fileref);
  504. }
  505.  
  506. if (r_count<r_max)
  507. {
  508. setTimeout(Init, 100);
  509. return 0;
  510. }
  511. else
  512. {
  513. console.log("Failed to load smoothscroll!");
  514. }
  515. r_count++;
  516. }
  517. if (OWNJQUERY) {
  518. var versiontable = $0.fn.jquery.split('.');
  519. var version = 0;
  520. for (var i = versiontable.length-1; i >= 0; i--) {
  521. var power = versiontable.length-i;
  522. version += Math.pow(10,power-1)*versiontable[i];
  523. }
  524.  
  525. console.log("Script jQuery OK! Version: " + version);
  526. InitSmoothscroll();
  527. }
  528. if (OLDJQUERY) {
  529. console.log("Restoring old jQuery...");
  530. $ = old$;
  531. jQuery = oldjQuery;
  532. var versiontable = $.fn.jquery.split('.');
  533. var version = 0;
  534. for (var i = versiontable.length-1; i >= 0; i--) {
  535. var power = versiontable.length-i;
  536. version += Math.pow(10,power-1)*versiontable[i];
  537. }
  538.  
  539. console.log("Page jQuery OK! Version: " + version);
  540. }
  541. console.log("Finished loading smoothscroll!");
  542. }
  543.  
  544. console.log("Loading smoothscroll...");
  545. Init();