Smoothscroll

Smooth scrolling on pages using javascript and jquery

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

  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 GM_info
  9. // @grant unsafeWindow
  10. // @version 0.0.1.20160520212705
  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 = $('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 = $(scrollfocus).parent();
  120. if ( $(parentelement))
  121. {
  122. //if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea"))
  123. if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea") || $(parentelement).is("article") || $(parentelement).is("article"))
  124. {
  125. return true;
  126. }
  127. else
  128. {
  129. if ($(parentelement).hasClass( "yt-scrollbar" ) || $(scrollfocus).hasClass( "yt-scrollbar" ))
  130. {
  131. return true;
  132. }
  133. return hasvisiblescrollbars;
  134. }
  135. }
  136. else
  137. {
  138. //scrollfocus = $('body');
  139. //maxposition = $(scrollfocus).height();
  140. return hasvisiblescrollbars;
  141. }
  142. return false;
  143. }
  144.  
  145. function UpdatePosition(element)
  146. {
  147. gameLoop();
  148. var positiondelta = $(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 - $(element).scrollTop();
  156. //console.log("smoothdelta:" + smoothdelta);
  157. if (Math.abs( (positiondelta-smoothdelta)) <= 1 )
  158. {
  159. $(element).stop();
  160. $(element).animate({
  161. scrollTop: '+=' + Math.round(positiondelta)
  162. }, animationduration, "linear", function() {
  163. $(element).attr( "positiondelta",0 );
  164. $(element)[0].setAttribute( "positiondelta",0 );
  165. if (DEBUG)
  166. {
  167. $(element).css( "border", "1px solid red" );
  168. }
  169. });
  170. }
  171. else
  172. {
  173. $(element).stop();
  174. $(element).animate({
  175. scrollTop: '+=' + Math.round(smoothdelta)
  176. }, animationduration, "linear", function() {
  177. $(element).attr( "positiondelta",positiondelta-smoothdelta );
  178. $(element)[0].setAttribute("positiondelta",positiondelta-smoothdelta );
  179. UpdatePosition(element);
  180. if (DEBUG)
  181. {
  182. $(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 = $(scrollfocus).parent();
  195. if ( $(parentelement))
  196. {
  197. if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea"))
  198. {
  199. //return true;
  200. }
  201. else
  202. {
  203. if ( $(parentelement).height() < $(scrollfocus).height())
  204. {
  205. //maxposition = $(scrollfocus).height() - $(parentelement).height();
  206. }
  207. else
  208. {
  209. if ($(scrollfocus).height()==0)
  210. {
  211. //scrollfocus = $('body');
  212. //maxposition = $(scrollfocus).height();
  213. }
  214.  
  215. //scrollfocus = $('body');
  216. //return MouseScroll (event);
  217. //return true;
  218. }
  219. }
  220. }
  221. else
  222. {
  223. scrollfocus = $('body');
  224. //maxposition = $(scrollfocus).height();
  225. }
  226. var rolled = y;
  227. //console.log("rolled: " + rolled);
  228. //if ($(scrollfocus).data("positiondelta" )==undefined)
  229. //$embellishment.data("embellishmentid",1)
  230. if ($(scrollfocus)[0].getAttribute("positiondelta")==undefined)
  231. {
  232. positiondelta = 0;
  233. //console.log("positiondelta: undefined");
  234. }
  235. else
  236. {
  237. positiondelta = $(scrollfocus)[0].getAttribute("positiondelta");
  238. //console.log("positiondelta: " + positiondelta);
  239. }
  240. positiondelta = positiondelta*1;
  241. var lastscrolltop = $(scrollfocus).scrollTop();
  242. $(scrollfocus).scrollTop(lastscrolltop+rolled);
  243. if ($(scrollfocus).scrollTop()==lastscrolltop)
  244. {
  245. if (!$(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. $(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. $(scrollfocus)[0].setAttribute("positiondelta",positiondelta );
  271. UpdatePosition($(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 = $(element);
  281. var lastscrolltop = $(scrollable).scrollTop();
  282. $(scrollable).scrollTop(lastscrolltop+dir);
  283. if ($(scrollable).scrollTop()==lastscrolltop)
  284. {
  285. $(scrollable).scrollTop(lastscrolltop);
  286. return false;
  287. }
  288. else
  289. {
  290. $(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. $(nodelist).stop();
  309. scrollfocus = $('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. $(newfocus).css( "border", "1px solid blue" );
  316. //var debugtimer = setTimeout(function(){ $(newfocus).css( "border", "0px solid white" ); }, 1000);
  317. }
  318. //if ($(newfocus).hasScrollBar3() && hasScrollBarVisible(newfocus) && canscroll(newfocus, dir) && hasscrollbars(newfocus))
  319. if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
  320. {
  321. scrollfocus = $(newfocus);
  322. return newfocus;
  323. }
  324. }
  325.  
  326. return scrollfocus;
  327. }
  328. $('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. $(scrollfocus)[0].setAttribute( "positiondelta",0 );
  347. $(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 loaded!");
  425. }
  426.  
  427.  
  428. var JQUERY = true;
  429.  
  430. //max retries
  431. var r_max = 3;
  432. var r_count = 0;
  433.  
  434. function Init() {
  435. //if (typeof jQuery == 'function') {
  436. if (typeof jQuery == 'undefined' || typeof $ == 'undefined' )
  437. {
  438. JQUERY = false;
  439. }
  440. if (JQUERY) {
  441. //console.log("Using existing jQuery...");
  442. //this.$ = this.jQuery = jQuery.noConflict(true);
  443. //var $ = jQuery.noConflict();
  444. //
  445. var versiontable = $.fn.jquery.split('.');
  446. var version = 0;
  447. for (var i = versiontable.length-1; i >= 0; i--) {
  448. var power = versiontable.length-i;
  449. version += Math.pow(10,power-1)*versiontable[i];
  450. }
  451. if (version<=minimal_jquery_version)
  452. {
  453. JQUERY = false;
  454. console.log("jQuery OLD! Version: " + version);
  455. }
  456. else
  457. {
  458. console.log("jQuery OK! Version: " + version);
  459. InitSmoothscroll();
  460. }
  461. }
  462. if (!JQUERY)
  463. {
  464. console.log("Loading jQuery...");
  465. //this.$ = this.jQuery = jQuery.noConflict(true);
  466. //var $ = jQuery.noConflict();
  467.  
  468. //this.$ = this.jQuery = jQuery.noConflict(true);
  469.  
  470. var filename = "https://code.jquery.com/jquery-2.2.3.js";
  471. var fileref=document.createElement('script')
  472. fileref.setAttribute("type","text/javascript")
  473. fileref.setAttribute("src", filename)
  474.  
  475. if (typeof fileref!="undefined")
  476. {
  477. var scriptparent = document.getElementsByTagName("head")[0];
  478. if (typeof scriptparent=="undefined")
  479. {
  480. var scriptparent = document.createElement('head')
  481. document.getElementsByTagName("html")[0].appendChild(scriptparent);
  482. }
  483. scriptparent.appendChild(fileref);
  484. }
  485. JQUERY = true;
  486. if (r_count<r_max)
  487. {
  488. setTimeout(Init, 1000);
  489. }
  490. else
  491. {
  492. console.log("Failed to load smoothscroll!");
  493. }
  494. r_count++;
  495. }
  496.  
  497. }
  498. console.log("Loading smoothscroll...");
  499. Init();