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