src/Gesture.js

  1. 'use strict';
  2. let g_id = 0;
  3. /**
  4. * The Gesture class that all gestures inherit from. A custom gesture class will
  5. * need to override some or all of the four phase "hooks": start, move, end, and
  6. * cancel.
  7. *
  8. * @memberof westures-core
  9. *
  10. * @param {string} type - The name of the gesture.
  11. * @param {Element} element - The element to which to associate the gesture.
  12. * @param {Function} handler - The function handler to execute when a gesture
  13. * is recognized on the associated element.
  14. * @param {object} [options] - Generic gesture options
  15. * @param {westures-core.STATE_KEYS[]} [options.enableKeys=[]] - List of keys
  16. * which will enable the gesture. The gesture will not be recognized unless one
  17. * of these keys is pressed while the interaction occurs. If not specified or an
  18. * empty list, the gesture is treated as though the enable key is always down.
  19. * @param {westures-core.STATE_KEYS[]} [options.disableKeys=[]] - List of keys
  20. * which will disable the gesture. The gesture will not be recognized if one of
  21. * these keys is pressed while the interaction occurs. If not specified or an
  22. * empty list, the gesture is treated as though the disable key is never down.
  23. * @param {number} [options.minInputs=1] - The minimum number of pointers that
  24. * must be active for the gesture to be recognized. Uses >=.
  25. * @param {number} [options.maxInputs=Number.MAX_VALUE] - The maximum number of
  26. * pointers that may be active for the gesture to be recognized. Uses <=.
  27. */
  28. class Gesture {
  29. constructor(type, element, handler, options = {}) {
  30. if (typeof type !== 'string') {
  31. throw new TypeError('Gestures require a string type / name');
  32. }
  33. /**
  34. * The name of the gesture. (e.g. 'pan' or 'tap' or 'pinch').
  35. *
  36. * @type {string}
  37. */
  38. this.type = type;
  39. /**
  40. * The unique identifier for each gesture. This allows for distinctions
  41. * across instances of Gestures that are created on the fly (e.g.
  42. * gesture-tap-1, gesture-tap-2).
  43. *
  44. * @type {string}
  45. */
  46. this.id = `gesture-${this.type}-${g_id++}`;
  47. /**
  48. * The element to which to associate the gesture.
  49. *
  50. * @type {Element}
  51. */
  52. this.element = element;
  53. /**
  54. * The function handler to execute when the gesture is recognized on the
  55. * associated element.
  56. *
  57. * @type {Function}
  58. */
  59. this.handler = handler;
  60. /**
  61. * The options. Can usually be adjusted live, though be careful doing this.
  62. *
  63. * @type {object}
  64. */
  65. this.options = { ...Gesture.DEFAULTS, ...options };
  66. }
  67. /**
  68. * Determines whether this gesture is enabled.
  69. *
  70. * @param {westures-core.State} state - The input state object of the current
  71. * region.
  72. *
  73. * @return {boolean} true if enabled, false otherwise.
  74. */
  75. isEnabled(state) {
  76. const count = state.active.length;
  77. const event = state.event;
  78. const { enableKeys, disableKeys, minInputs, maxInputs } = this.options;
  79. return (minInputs <= count) && (maxInputs >= count) &&
  80. (enableKeys.length === 0 || enableKeys.some(k => event[k])) &&
  81. !disableKeys.some(k => event[k]);
  82. }
  83. /**
  84. * Event hook for the start phase of a gesture.
  85. *
  86. * @param {westures-core.State} state - The input state object of the current
  87. * region.
  88. *
  89. * @return {?Object} Gesture is considered recognized if an Object is
  90. * returned.
  91. */
  92. start() {
  93. return null;
  94. }
  95. /**
  96. * Event hook for the move phase of a gesture.
  97. *
  98. * @param {westures-core.State} state - The input state object of the current
  99. * region.
  100. *
  101. * @return {?Object} Gesture is considered recognized if an Object is
  102. * returned.
  103. */
  104. move() {
  105. return null;
  106. }
  107. /**
  108. * Event hook for the end phase of a gesture.
  109. *
  110. * @param {westures-core.State} state - The input state object of the current
  111. * region.
  112. *
  113. * @return {?Object} Gesture is considered recognized if an Object is
  114. * returned.
  115. */
  116. end() {
  117. return null;
  118. }
  119. /**
  120. * Event hook for when an input is cancelled.
  121. *
  122. * @param {westures-core.State} state - The input state object of the current
  123. * region.
  124. *
  125. * @return {?Object} Gesture is considered recognized if an Object is
  126. * returned.
  127. */
  128. cancel() {
  129. return null;
  130. }
  131. /**
  132. * Evalutes the given gesture hook, and dispatches any data that is produced
  133. * by calling [recognize]{@link westures-core.Gesture#recognize}.
  134. *
  135. * @param {string} hook - Must be one of 'start', 'move', 'end', or 'cancel'.
  136. * @param {westures-core.State} state - The current State instance.
  137. */
  138. evaluateHook(hook, state) {
  139. const data = this[hook](state);
  140. if (data) {
  141. this.recognize(hook, state, data);
  142. }
  143. }
  144. /**
  145. * Recognize a Gesture by calling the handler. Standardizes the way the
  146. * handler is called so that classes extending Gesture can circumvent the
  147. * evaluateHook approach but still provide results that have a common format.
  148. *
  149. * Note that the properties in the "data" object will receive priority when
  150. * constructing the results. This can be used to override standard results
  151. * such as the phase or the centroid.
  152. *
  153. * @param {string} hook - Must be one of 'start', 'move', 'end', or 'cancel'.
  154. * @param {westures-core.State} state - current input state.
  155. * @param {Object} data - Results data specific to the recognized gesture.
  156. */
  157. recognize(hook, state, data) {
  158. this.handler({
  159. centroid: state.centroid,
  160. event: state.event,
  161. phase: hook,
  162. type: this.type,
  163. target: this.element,
  164. ...data,
  165. });
  166. }
  167. }
  168. Gesture.DEFAULTS = {
  169. enableKeys: [],
  170. disableKeys: [],
  171. minInputs: 1,
  172. maxInputs: Number.MAX_VALUE,
  173. };
  174. module.exports = Gesture;