ui.events.emitter.gesture.scroll.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /**
  2. * DevExtreme (ui/scroll_view/ui.events.emitter.gesture.scroll.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var eventsEngine = require("../../events/core/events_engine");
  11. var Class = require("../../core/class");
  12. var abstract = Class.abstract;
  13. var eventUtils = require("../../events/utils");
  14. var GestureEmitter = require("../../events/gesture/emitter.gesture");
  15. var registerEmitter = require("../../events/core/emitter_registrator");
  16. var animationFrame = require("../../animation/frame");
  17. var realDevice = require("../../core/devices").real();
  18. var compareVersions = require("../../core/utils/version").compare;
  19. var SCROLL_INIT_EVENT = "dxscrollinit";
  20. var SCROLL_START_EVENT = "dxscrollstart";
  21. var SCROLL_MOVE_EVENT = "dxscroll";
  22. var SCROLL_END_EVENT = "dxscrollend";
  23. var SCROLL_STOP_EVENT = "dxscrollstop";
  24. var SCROLL_CANCEL_EVENT = "dxscrollcancel";
  25. var Locker = Class.inherit(function() {
  26. var NAMESPACED_SCROLL_EVENT = eventUtils.addNamespace("scroll", "dxScrollEmitter");
  27. return {
  28. ctor: function(element) {
  29. this._element = element;
  30. this._locked = false;
  31. var that = this;
  32. this._proxiedScroll = function(e) {
  33. that._scroll(e)
  34. };
  35. eventsEngine.on(this._element, NAMESPACED_SCROLL_EVENT, this._proxiedScroll)
  36. },
  37. _scroll: abstract,
  38. check: function(e, callback) {
  39. if (this._locked) {
  40. callback()
  41. }
  42. },
  43. dispose: function() {
  44. eventsEngine.off(this._element, NAMESPACED_SCROLL_EVENT, this._proxiedScroll)
  45. }
  46. }
  47. }());
  48. var TimeoutLocker = Locker.inherit(function() {
  49. return {
  50. ctor: function(element, timeout) {
  51. this.callBase(element);
  52. this._timeout = timeout
  53. },
  54. _scroll: function() {
  55. this._prepare();
  56. this._forget()
  57. },
  58. _prepare: function() {
  59. if (this._timer) {
  60. this._clearTimer()
  61. }
  62. this._locked = true
  63. },
  64. _clearTimer: function() {
  65. clearTimeout(this._timer);
  66. this._locked = false;
  67. this._timer = null
  68. },
  69. _forget: function() {
  70. var that = this;
  71. this._timer = setTimeout(function() {
  72. that._clearTimer()
  73. }, this._timeout)
  74. },
  75. dispose: function() {
  76. this.callBase();
  77. this._clearTimer()
  78. }
  79. }
  80. }());
  81. var WheelLocker = TimeoutLocker.inherit(function() {
  82. var WHEEL_UNLOCK_TIMEOUT = 400;
  83. return {
  84. ctor: function(element) {
  85. this.callBase(element, WHEEL_UNLOCK_TIMEOUT);
  86. this._lastWheelDirection = null
  87. },
  88. check: function(e, callback) {
  89. this._checkDirectionChanged(e);
  90. this.callBase(e, callback)
  91. },
  92. _checkDirectionChanged: function(e) {
  93. if (!eventUtils.isDxMouseWheelEvent(e)) {
  94. this._lastWheelDirection = null;
  95. return
  96. }
  97. var direction = e.shiftKey || false;
  98. var directionChange = null !== this._lastWheelDirection && direction !== this._lastWheelDirection;
  99. this._lastWheelDirection = direction;
  100. this._locked = this._locked && !directionChange
  101. }
  102. }
  103. }());
  104. var PointerLocker = TimeoutLocker.inherit(function() {
  105. var POINTER_UNLOCK_TIMEOUT = 400;
  106. return {
  107. ctor: function(element) {
  108. this.callBase(element, POINTER_UNLOCK_TIMEOUT)
  109. }
  110. }
  111. }());
  112. ! function() {
  113. var ios8_greater = realDevice.ios && compareVersions(realDevice.version, [8]) >= 0;
  114. var android5_greater = realDevice.android && compareVersions(realDevice.version, [5]) >= 0;
  115. if (!(ios8_greater || android5_greater)) {
  116. return
  117. }
  118. PointerLocker = Locker.inherit(function() {
  119. return {
  120. _scroll: function() {
  121. this._locked = true;
  122. var that = this;
  123. animationFrame.cancelAnimationFrame(this._scrollFrame);
  124. this._scrollFrame = animationFrame.requestAnimationFrame(function() {
  125. that._locked = false
  126. })
  127. },
  128. check: function(e, callback) {
  129. animationFrame.cancelAnimationFrame(this._scrollFrame);
  130. animationFrame.cancelAnimationFrame(this._checkFrame);
  131. var that = this;
  132. var callBase = this.callBase;
  133. this._checkFrame = animationFrame.requestAnimationFrame(function() {
  134. callBase.call(that, e, callback);
  135. that._locked = false
  136. })
  137. },
  138. dispose: function() {
  139. this.callBase();
  140. animationFrame.cancelAnimationFrame(this._scrollFrame);
  141. animationFrame.cancelAnimationFrame(this._checkFrame)
  142. }
  143. }
  144. }())
  145. }();
  146. var ScrollEmitter = GestureEmitter.inherit(function() {
  147. var INERTIA_TIMEOUT = 100;
  148. var VELOCITY_CALC_TIMEOUT = 200;
  149. var FRAME_DURATION = Math.round(1e3 / 60);
  150. return {
  151. ctor: function(element) {
  152. this.callBase.apply(this, arguments);
  153. this.direction = "both";
  154. this._pointerLocker = new PointerLocker(element);
  155. this._wheelLocker = new WheelLocker(element)
  156. },
  157. validate: function() {
  158. return true
  159. },
  160. configure: function(data) {
  161. if (data.scrollTarget) {
  162. this._pointerLocker.dispose();
  163. this._wheelLocker.dispose();
  164. this._pointerLocker = new PointerLocker(data.scrollTarget);
  165. this._wheelLocker = new WheelLocker(data.scrollTarget)
  166. }
  167. this.callBase(data)
  168. },
  169. _init: function(e) {
  170. this._wheelLocker.check(e, function() {
  171. if (eventUtils.isDxMouseWheelEvent(e)) {
  172. this._accept(e)
  173. }
  174. }.bind(this));
  175. this._pointerLocker.check(e, function() {
  176. var skipCheck = this.isNative && eventUtils.isMouseEvent(e);
  177. if (!eventUtils.isDxMouseWheelEvent(e) && !skipCheck) {
  178. this._accept(e)
  179. }
  180. }.bind(this));
  181. this._fireEvent(SCROLL_INIT_EVENT, e);
  182. this._prevEventData = eventUtils.eventData(e)
  183. },
  184. move: function(e) {
  185. this.callBase.apply(this, arguments);
  186. e.isScrollingEvent = this.isNative || e.isScrollingEvent
  187. },
  188. _start: function(e) {
  189. this._savedEventData = eventUtils.eventData(e);
  190. this._fireEvent(SCROLL_START_EVENT, e);
  191. this._prevEventData = eventUtils.eventData(e)
  192. },
  193. _move: function(e) {
  194. var currentEventData = eventUtils.eventData(e);
  195. this._fireEvent(SCROLL_MOVE_EVENT, e, {
  196. delta: eventUtils.eventDelta(this._prevEventData, currentEventData)
  197. });
  198. var eventDelta = eventUtils.eventDelta(this._savedEventData, currentEventData);
  199. if (eventDelta.time > VELOCITY_CALC_TIMEOUT) {
  200. this._savedEventData = this._prevEventData
  201. }
  202. this._prevEventData = eventUtils.eventData(e)
  203. },
  204. _end: function(e) {
  205. var endEventDelta = eventUtils.eventDelta(this._prevEventData, eventUtils.eventData(e));
  206. var velocity = {
  207. x: 0,
  208. y: 0
  209. };
  210. if (!eventUtils.isDxMouseWheelEvent(e) && endEventDelta.time < INERTIA_TIMEOUT) {
  211. var eventDelta = eventUtils.eventDelta(this._savedEventData, this._prevEventData);
  212. var velocityMultiplier = FRAME_DURATION / eventDelta.time;
  213. velocity = {
  214. x: eventDelta.x * velocityMultiplier,
  215. y: eventDelta.y * velocityMultiplier
  216. }
  217. }
  218. this._fireEvent(SCROLL_END_EVENT, e, {
  219. velocity: velocity
  220. })
  221. },
  222. _stop: function(e) {
  223. this._fireEvent(SCROLL_STOP_EVENT, e)
  224. },
  225. cancel: function(e) {
  226. this.callBase.apply(this, arguments);
  227. this._fireEvent(SCROLL_CANCEL_EVENT, e)
  228. },
  229. dispose: function() {
  230. this.callBase.apply(this, arguments);
  231. this._pointerLocker.dispose();
  232. this._wheelLocker.dispose()
  233. },
  234. _clearSelection: function() {
  235. if (this.isNative) {
  236. return
  237. }
  238. return this.callBase.apply(this, arguments)
  239. },
  240. _toggleGestureCover: function() {
  241. if (this.isNative) {
  242. return
  243. }
  244. return this.callBase.apply(this, arguments)
  245. }
  246. }
  247. }());
  248. registerEmitter({
  249. emitter: ScrollEmitter,
  250. events: [SCROLL_INIT_EVENT, SCROLL_START_EVENT, SCROLL_MOVE_EVENT, SCROLL_END_EVENT, SCROLL_STOP_EVENT, SCROLL_CANCEL_EVENT]
  251. });
  252. module.exports = {
  253. init: SCROLL_INIT_EVENT,
  254. start: SCROLL_START_EVENT,
  255. move: SCROLL_MOVE_EVENT,
  256. end: SCROLL_END_EVENT,
  257. stop: SCROLL_STOP_EVENT,
  258. cancel: SCROLL_CANCEL_EVENT
  259. };