DOMMouseMoveTracker.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /**
  2. * Copyright (c) 2013-present, Facebook, Inc.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * This class listens to events on the document and then updates a react
  8. * component through callbacks.
  9. * Please note that captureMouseMove must be called in
  10. * order to initialize listeners on mousemove and mouseup.
  11. * releaseMouseMove must be called to remove them. It is important to
  12. * call releaseMouseMoves since mousemove is expensive to listen to.
  13. *
  14. * @typechecks
  15. */
  16. 'use strict';
  17. var EventListener = require("./EventListener");
  18. var cancelAnimationFramePolyfill = require("./cancelAnimationFramePolyfill");
  19. var requestAnimationFramePolyfill = require("./requestAnimationFramePolyfill");
  20. var DOMMouseMoveTracker =
  21. /*#__PURE__*/
  22. function () {
  23. /**
  24. * onMove is the callback that will be called on every mouse move.
  25. * onMoveEnd is called on mouse up when movement has ended.
  26. */
  27. function DOMMouseMoveTracker(
  28. /*function*/
  29. onMove,
  30. /*function*/
  31. onMoveEnd,
  32. /*DOMElement*/
  33. domNode) {
  34. this._isDragging = false;
  35. this._animationFrameID = null;
  36. this._domNode = domNode;
  37. this._onMove = onMove;
  38. this._onMoveEnd = onMoveEnd;
  39. this._onMouseMove = this._onMouseMove.bind(this);
  40. this._onMouseUp = this._onMouseUp.bind(this);
  41. this._didMouseMove = this._didMouseMove.bind(this);
  42. }
  43. /**
  44. * This is to set up the listeners for listening to mouse move
  45. * and mouse up signaling the movement has ended. Please note that these
  46. * listeners are added at the document.body level. It takes in an event
  47. * in order to grab inital state.
  48. */
  49. var _proto = DOMMouseMoveTracker.prototype;
  50. _proto.captureMouseMoves = function captureMouseMoves(
  51. /*object*/
  52. event) {
  53. if (!this._eventMoveToken && !this._eventUpToken) {
  54. this._eventMoveToken = EventListener.listen(this._domNode, 'mousemove', this._onMouseMove);
  55. this._eventUpToken = EventListener.listen(this._domNode, 'mouseup', this._onMouseUp);
  56. }
  57. if (!this._isDragging) {
  58. this._deltaX = 0;
  59. this._deltaY = 0;
  60. this._isDragging = true;
  61. this._x = event.clientX;
  62. this._y = event.clientY;
  63. }
  64. event.preventDefault();
  65. };
  66. /**
  67. * These releases all of the listeners on document.body.
  68. */
  69. _proto.releaseMouseMoves = function releaseMouseMoves() {
  70. if (this._eventMoveToken && this._eventUpToken) {
  71. this._eventMoveToken.remove();
  72. this._eventMoveToken = null;
  73. this._eventUpToken.remove();
  74. this._eventUpToken = null;
  75. }
  76. if (this._animationFrameID !== null) {
  77. cancelAnimationFramePolyfill(this._animationFrameID);
  78. this._animationFrameID = null;
  79. }
  80. if (this._isDragging) {
  81. this._isDragging = false;
  82. this._x = null;
  83. this._y = null;
  84. }
  85. };
  86. /**
  87. * Returns whether or not if the mouse movement is being tracked.
  88. */
  89. _proto.isDragging = function isDragging()
  90. /*boolean*/
  91. {
  92. return this._isDragging;
  93. };
  94. /**
  95. * Calls onMove passed into constructor and updates internal state.
  96. */
  97. _proto._onMouseMove = function _onMouseMove(
  98. /*object*/
  99. event) {
  100. var x = event.clientX;
  101. var y = event.clientY;
  102. this._deltaX += x - this._x;
  103. this._deltaY += y - this._y;
  104. if (this._animationFrameID === null) {
  105. // The mouse may move faster then the animation frame does.
  106. // Use `requestAnimationFramePolyfill` to avoid over-updating.
  107. this._animationFrameID = requestAnimationFramePolyfill(this._didMouseMove);
  108. }
  109. this._x = x;
  110. this._y = y;
  111. event.preventDefault();
  112. };
  113. _proto._didMouseMove = function _didMouseMove() {
  114. this._animationFrameID = null;
  115. this._onMove(this._deltaX, this._deltaY);
  116. this._deltaX = 0;
  117. this._deltaY = 0;
  118. };
  119. /**
  120. * Calls onMoveEnd passed into constructor and updates internal state.
  121. */
  122. _proto._onMouseUp = function _onMouseUp() {
  123. if (this._animationFrameID) {
  124. this._didMouseMove();
  125. }
  126. this._onMoveEnd();
  127. };
  128. return DOMMouseMoveTracker;
  129. }();
  130. module.exports = DOMMouseMoveTracker;