Smoothscroll

Smooth scrolling on pages using javascript

当前为 2018-03-08 提交的版本,查看 最新版本

  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 5.1
  8. // ==/UserScript==
  9.  
  10. //dev
  11. var DEBUG = false;
  12. var REFRESHRATE = 60;
  13.  
  14. //settings
  15. var SMOOTHNESS = 0.5;
  16. var ACCELERATION = 0.5;
  17.  
  18.  
  19. function IsScrollable(element, dir)
  20. {
  21. var checkradius = 2; //pixels to try scrolling
  22.  
  23. if (dir>0)
  24. {
  25. dir = checkradius;
  26. }
  27. if (dir<0)
  28. {
  29. dir = -checkradius;
  30. }
  31.  
  32. var originalscroll = element.scrollTop;
  33. var testscroll = Math.round(originalscroll + dir);
  34. element.scrollTop = testscroll;
  35.  
  36. var scrollable = Math.round(element.scrollTop)==testscroll;
  37. element.scrollTop = originalscroll;
  38.  
  39. return scrollable;
  40. }
  41.  
  42. function HasScrollbars(element)
  43. {
  44. //return (document.documentElement.scrollHeight !== document.documentElement.clientHeight);
  45.  
  46. // Get the computed style of the body element
  47. var cStyle = element.currentStyle||window.getComputedStyle(element, "");
  48.  
  49. // Check the overflow and overflowY properties for "auto" and "visible" values
  50. var scrollbar1 = cStyle.overflow == "scroll" || cStyle.overflowY == "scroll";
  51. var scrollbar2 = cStyle.overflow == "auto" || cStyle.overflowY == "auto";
  52.  
  53. //body or html always have scrollbars
  54. var scrollbar3 = element==document.body || element==document.documentElement;
  55.  
  56. return scrollbar1 || scrollbar2 || scrollbar3;
  57. }
  58.  
  59. function Direction(number)
  60. {
  61. if (number>0)
  62. {
  63. return 1;
  64. }
  65. if (number<0)
  66. {
  67. return -1;
  68. }
  69. return 0;
  70. }
  71.  
  72. function Timeout(element, newtimeout)
  73. {
  74. if (newtimeout!=undefined)
  75. {
  76. var oldtimeout = element.ScrollTimeout;
  77. if (oldtimeout!=undefined)
  78. {
  79. clearTimeout(oldtimeout);
  80. }
  81. element.ScrollTimeout = newtimeout;
  82. return newtimeout;
  83. }
  84. else
  85. {
  86. var oldtimeout = element.ScrollTimeout;
  87. if (oldtimeout!=undefined)
  88. {
  89. return oldtimeout;
  90. }
  91. return null;
  92. }
  93. }
  94.  
  95. function ScrollSubpixels(element, newvalue)
  96. {
  97. if (newvalue!=undefined)
  98. {
  99. element.scrollsubpixels = newvalue;
  100. return newvalue;
  101. }
  102. else
  103. {
  104. var olddelta = element.scrollsubpixels;
  105. if (olddelta!=undefined)
  106. {
  107. return olddelta;
  108. }
  109. return 0;
  110. }
  111. }
  112. function ScrollPixels(element, newvalue)
  113. {
  114. if (newvalue!=undefined)
  115. {
  116. element.scrollpixels = newvalue;
  117. ScrollSubpixels(element, 0);
  118. return newvalue;
  119. }
  120. else
  121. {
  122. var olddelta = element.scrollpixels;
  123. if (olddelta!=undefined)
  124. {
  125. return olddelta;
  126. }
  127. return 0;
  128. }
  129. }
  130.  
  131. function GetTarget(e) {
  132. var direction = e.deltaY;
  133. var nodes = e.path;
  134. for (var i=0; i<nodes.length; i++) {
  135. var node = nodes[i];
  136. if (IsScrollable(node, direction) && HasScrollbars(node))
  137. {
  138. if (DEBUG) {
  139. console.log("scrollbar: ");
  140. console.log(node);
  141. }
  142. return node;
  143. }
  144. }
  145.  
  146. return null;
  147. }
  148.  
  149. function AnimateScroll(target) {
  150. var updaterate = Math.floor(1000/(REFRESHRATE));
  151. var scrollsubpixels = ScrollSubpixels(target);
  152. var scrollpixels = ScrollPixels(target);
  153.  
  154. var scrolldirection = Direction(scrollpixels);
  155.  
  156. var scrollratio = 1-Math.pow( REFRESHRATE, -1/(REFRESHRATE*SMOOTHNESS));
  157. var scrollrate = scrollpixels*scrollratio;
  158. if (Math.abs(scrollpixels)>1) {
  159. var fullscrolls = Math.floor(Math.abs(scrollrate))*scrolldirection;
  160. var scrollsubpixelsadded = scrollrate - fullscrolls;
  161.  
  162. var additionalscrolls = Math.floor(Math.abs(scrollsubpixels + scrollsubpixelsadded))*scrolldirection;
  163. var scrollsubpixelsleft = scrollsubpixels + scrollsubpixelsadded - additionalscrolls;
  164.  
  165. ScrollPixels(target, scrollpixels-fullscrolls-additionalscrolls);
  166. ScrollSubpixels(target, scrollsubpixelsleft);
  167. target.scrollTop += fullscrolls + additionalscrolls;
  168.  
  169. Timeout(target, setTimeout(function() {
  170.  
  171. AnimateScroll(target);
  172. }, updaterate));
  173. } else
  174. {
  175. ScrollPixels(target, 0);
  176. }
  177. }
  178.  
  179. function StopScroll(e) {
  180. var nodes = e.path;
  181. for (var i=0; i<nodes.length; i++) {
  182. var node = nodes[i];
  183. ScrollPixels(node, null);
  184. Timeout(node, null);
  185. }
  186. }
  187.  
  188. function StartScroll(e, target) {
  189. var direction = e.deltaY;
  190. var scrollpixels = ScrollPixels(target);
  191.  
  192. var accelerationratio = Math.sqrt(Math.abs(scrollpixels/direction*ACCELERATION));
  193. var acceleration = Math.round(direction*accelerationratio);
  194.  
  195. ScrollPixels(target, scrollpixels + direction + acceleration);
  196. if (e.defaultPrevented)
  197. {
  198. return true;
  199. }
  200. else
  201. {
  202. AnimateScroll(target);
  203. e.preventDefault();
  204. }
  205. }
  206.  
  207.  
  208. function WheelEvent(e) {
  209. var target = GetTarget(e);
  210. if (target) {
  211. StartScroll(e, target);
  212. }
  213. }
  214.  
  215. function ClickEvent(e) {
  216. StopScroll(e);
  217. }
  218.  
  219. function Init()
  220. {
  221. if (window.SMOOTHSCROLL) {
  222. console.log("Smoothscroll: already loaded");
  223. return null;
  224. }
  225. if (window.top != window.self) {
  226. console.log("Smoothscroll: ignoring iframe");
  227. return null;
  228. }
  229. document.documentElement.addEventListener("wheel", function(e){
  230. WheelEvent(e);
  231. if (DEBUG) {
  232. console.log(e);
  233. }
  234. });
  235.  
  236. document.documentElement.addEventListener("mousedown", function(e){
  237. ClickEvent(e);
  238. if (DEBUG) {
  239. console.log(e);
  240. }
  241. });
  242. console.log("Smoothscroll: loaded");
  243. window.SMOOTHSCROLL = true;
  244. }
  245. Init();