Smoothscroll

Smooth scrolling on pages using javascript

目前为 2018-09-06 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Smoothscroll
  3. // @author Creec Winceptor
  4. // @description Smooth scrolling on pages using javascript
  5. // @namespace https://greasyfork.org/users/3167
  6. // @include *
  7. // @version 6
  8. // ==/UserScript==
  9.  
  10. var Smoothscroll = {};
  11.  
  12. //dev
  13. Smoothscroll.Debug = false;
  14. Smoothscroll.Refreshrate = 60;
  15.  
  16. //settings
  17. Smoothscroll.Smoothness = 0.5;
  18. Smoothscroll.Acceleration = 0.5;
  19.  
  20. //scrolling and animation
  21. function Timeout(element, newtimeout)
  22. {
  23. if (newtimeout!=undefined)
  24. {
  25. var oldtimeout = element.ScrollTimeout;
  26. if (oldtimeout!=undefined)
  27. {
  28. clearTimeout(oldtimeout);
  29. }
  30. element.ScrollTimeout = newtimeout;
  31. return newtimeout;
  32. }
  33. else
  34. {
  35. var oldtimeout = element.ScrollTimeout;
  36. if (oldtimeout!=undefined)
  37. {
  38. return oldtimeout;
  39. }
  40. return null;
  41. }
  42. }
  43. function ScrollSubpixels(element, newvalue)
  44. {
  45. if (newvalue!=undefined)
  46. {
  47. element.scrollsubpixels = newvalue;
  48. return newvalue;
  49. }
  50. else
  51. {
  52. var olddelta = element.scrollsubpixels;
  53. if (olddelta!=undefined)
  54. {
  55. return olddelta;
  56. }
  57. return 0;
  58. }
  59. }
  60. function ScrollPixels(element, newvalue)
  61. {
  62. if (newvalue!=undefined)
  63. {
  64. element.scrollpixels = newvalue;
  65. ScrollSubpixels(element, 0);
  66. return newvalue;
  67. }
  68. else
  69. {
  70. var olddelta = element.scrollpixels;
  71. if (olddelta!=undefined)
  72. {
  73. return olddelta;
  74. }
  75. return 0;
  76. }
  77. }
  78. function AnimateScroll(target) {
  79. var updaterate = Math.floor(1000/(Smoothscroll.Refreshrate));
  80. var scrollsubpixels = ScrollSubpixels(target);
  81. var scrollpixels = ScrollPixels(target);
  82.  
  83. var scrolldirection = 0;
  84. if (scrollpixels>0) {
  85. scrolldirection = 1;
  86. }
  87. if (scrollpixels<0) {
  88. scrolldirection = -1;
  89. }
  90.  
  91. var scrollratio = 1-Math.pow( Smoothscroll.Refreshrate, -1/(Smoothscroll.Refreshrate*Smoothscroll.Smoothness));
  92. var scrollrate = scrollpixels*scrollratio;
  93. if (Math.abs(scrollpixels)>1) {
  94. var fullscrolls = Math.floor(Math.abs(scrollrate))*scrolldirection;
  95. var scrollsubpixelsadded = scrollrate - fullscrolls;
  96.  
  97. var additionalscrolls = Math.floor(Math.abs(scrollsubpixels + scrollsubpixelsadded))*scrolldirection;
  98. var scrollsubpixelsleft = scrollsubpixels + scrollsubpixelsadded - additionalscrolls;
  99.  
  100. ScrollPixels(target, scrollpixels-fullscrolls-additionalscrolls);
  101. ScrollSubpixels(target, scrollsubpixelsleft);
  102. target.scrollTop += fullscrolls + additionalscrolls;
  103.  
  104. Timeout(target, setTimeout(function() {
  105.  
  106. AnimateScroll(target);
  107. }, updaterate));
  108. } else
  109. {
  110. ScrollPixels(target, 0);
  111. }
  112. }
  113.  
  114. Smoothscroll.Stop = function(target) {
  115. if (target) {
  116. ScrollPixels(target, null);
  117. Timeout(target, null);
  118. }
  119. }
  120. Smoothscroll.Start = function(target, scrollamount) {
  121. if (target) {
  122. var scrollpixels = ScrollPixels(target);
  123. ScrollPixels(target, scrollamount);
  124. AnimateScroll(target);
  125. }
  126. }
  127.  
  128. if (typeof module !== 'undefined') {
  129. module.exports = Smoothscroll;
  130. }
  131.  
  132. //scroll target detection
  133. function IsScrollable(element, dir)
  134. {
  135. //TODO: problem with webkit, body not scrollable?
  136. if (element==document.body) {
  137. return false;
  138. }
  139. if (dir>0)
  140. {
  141. if (Smoothscroll.Debug) {
  142.  
  143. console.log("element.offsetHeight: " + element.offsetHeight);
  144. console.log("element.clientHeight: " + element.clientHeight);
  145. console.log("element.scrollTop: " + element.scrollTop);
  146. console.log("element.scrollHeight: " + element.scrollHeight);
  147. }
  148. return element.scrollTop+element.clientHeight<element.scrollHeight;
  149. }
  150. if (dir<0)
  151. {
  152. return element.scrollTop>0;
  153. }
  154. return true;
  155. }
  156.  
  157. //scroll target detection backup
  158. function IsScrollable0(element, dir)
  159. {
  160. //TODO: problem with webkit, body not scrollable?
  161. if (element==document.body) {
  162. return false;
  163. }
  164.  
  165. var checkradius = 3; //pixels to try scrolling
  166.  
  167. if (dir>0)
  168. {
  169. dir = checkradius;
  170. }
  171. if (dir<0)
  172. {
  173. dir = -checkradius;
  174. }
  175.  
  176. var originalscroll = element.scrollTop;
  177. var testscroll = Math.round(originalscroll + dir);
  178. element.scrollTop = testscroll;
  179.  
  180. var scrollable = Math.round(element.scrollTop)==testscroll;
  181.  
  182. element.scrollTop = originalscroll;
  183.  
  184. return scrollable;
  185. }
  186. function HasScrollbars(element)
  187. {
  188. if (element==window || element==document) {
  189. return false;
  190. }
  191. //return (document.documentElement.scrollHeight !== document.documentElement.clientHeight);
  192.  
  193. // Get the computed style of the body element
  194. var cStyle = element.currentStyle || window.getComputedStyle(element, "");
  195.  
  196. // Check the overflow and overflowY properties for "auto" and "visible" values
  197. var scrollbar0 = element==document.body || element==document.documentElement;
  198. var scrollbar1 = cStyle.overflow != "hidden" && cStyle.overflowY != "hidden";
  199. var scrollbar2 = cStyle.overflowY == "scroll" || cStyle.overflowY == "auto";
  200. var scrollbar3 = cStyle.maxHeight<cStyle.height;
  201.  
  202. //body or html always have scrollbars
  203. var scrollbar4 = cStyle.overflow != "hidden" && cStyle.overflowY != "hidden";
  204.  
  205. return scrollbar0 || (scrollbar1 || scrollbar2) && scrollbar3;
  206. }
  207. function GetTarget(e) {
  208. var direction = e.deltaY;
  209. var nodes = e.path;
  210. if (Smoothscroll.Debug) {
  211. console.log("nodes: ");
  212. console.log(nodes);
  213. console.log("target: ");
  214. }
  215. for (var i=0; i<(nodes.length); i++) {
  216. var node = nodes[i];
  217. if (Smoothscroll.Debug) {
  218. console.log(node);
  219. }
  220. var scrollable_check = IsScrollable(node, direction);
  221. if (Smoothscroll.Debug) {
  222. console.log("scrollable_check: " + scrollable_check);
  223. }
  224. var scrollbar_check = HasScrollbars(node);
  225. if (Smoothscroll.Debug) {
  226. console.log("scrollbar_check: " + scrollbar_check);
  227. }
  228. if (scrollable_check && scrollbar_check)
  229. {
  230. if (Smoothscroll.Debug) {
  231. console.log("true");
  232. }
  233. return node;
  234. }
  235. }
  236. if (Smoothscroll.Debug) {
  237. console.log("false");
  238.  
  239. }
  240.  
  241. return null;
  242. }
  243.  
  244.  
  245.  
  246. //mouse event scroll handlers
  247. function StopScroll(e) {
  248. var nodes = e.path;
  249. for (var i=0; i<nodes.length; i++) {
  250. var node = nodes[i];
  251. Smoothscroll.Stop(node);
  252. }
  253. }
  254. function StartScroll(e, target) {
  255.  
  256. if (e.defaultPrevented)
  257. {
  258. return true;
  259. }
  260. else
  261. {
  262. var direction = e.deltaY;
  263.  
  264. var scrollpixels = ScrollPixels(target);
  265.  
  266. var accelerationratio = Math.sqrt(Math.abs(scrollpixels/direction*Smoothscroll.Acceleration));
  267.  
  268. var acceleration = Math.round(direction*accelerationratio);
  269.  
  270. Smoothscroll.Start(target, scrollpixels + direction + acceleration);
  271.  
  272. e.preventDefault();
  273. }
  274. }
  275.  
  276.  
  277.  
  278. //mouse event call handlers
  279. function WheelEvent(e) {
  280. var target = GetTarget(e);
  281. if (target) {
  282. StartScroll(e, target);
  283. }
  284. }
  285. function ClickEvent(e) {
  286. StopScroll(e);
  287. }
  288.  
  289.  
  290.  
  291. //init function
  292. function Init()
  293. {
  294.  
  295. if (window.top != window.self) {
  296. //console.log("Smoothscroll: ignoring iframe");
  297. return null;
  298. }
  299. if (window.Smoothscroll && window.Smoothscroll.Loaded) {
  300. //console.log("Smoothscroll: already loaded");
  301. return null;
  302. }
  303. document.documentElement.addEventListener("wheel", function(e){
  304. WheelEvent(e);
  305. if (Smoothscroll.Debug) {
  306. console.log(e);
  307. }
  308. });
  309.  
  310. document.documentElement.addEventListener("mousedown", function(e){
  311. ClickEvent(e);
  312. if (Smoothscroll.Debug) {
  313. console.log(e);
  314. }
  315. });
  316. window.Smoothscroll = Smoothscroll;
  317. window.Smoothscroll.Loaded = true;
  318. console.log("Smoothscroll: loaded");
  319. }
  320. Init();