Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

pointer-source.ts 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * encantar.js
  3. * GPU-accelerated Augmented Reality for the web
  4. * Copyright (C) 2022-2024 Alexandre Martins <alemartf(at)gmail.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published
  8. * by the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. *
  19. * pointer-source.ts
  20. * Source of data of pointer-based input: mouse, touch, pen...
  21. */
  22. import Speedy from 'speedy-vision';
  23. import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
  24. import { Source } from './source';
  25. import { Viewport } from '../core/viewport'
  26. import { Utils, Nullable } from '../utils/utils';
  27. /**
  28. * Source of data of pointer-based input: mouse, touch, pen...
  29. */
  30. export class PointerSource implements Source
  31. {
  32. /** a queue of incoming pointer events */
  33. private _queue: PointerEvent[];
  34. /** the viewport linked to this source of data */
  35. private _viewport: Nullable<Viewport>;
  36. /**
  37. * Constructor
  38. */
  39. constructor()
  40. {
  41. this._queue = [];
  42. this._viewport = null;
  43. this._onPointerEvent = this._onPointerEvent.bind(this);
  44. this._cancelEvent = this._cancelEvent.bind(this);
  45. }
  46. /**
  47. * A type-identifier of the source of data
  48. * @internal
  49. */
  50. get _type(): string
  51. {
  52. return 'pointer-source';
  53. }
  54. /**
  55. * Consume a pointer event
  56. * @returns the next pointer event to be consumed, or null if there are none
  57. * @internal
  58. */
  59. _consume(): PointerEvent | null
  60. {
  61. // producer-consumer mechanism
  62. return this._queue.shift() || null;
  63. }
  64. /**
  65. * Stats related to this source of data
  66. * @internal
  67. */
  68. get _stats(): string
  69. {
  70. return 'pointer input';
  71. }
  72. /**
  73. * Initialize this source of data
  74. * @returns a promise that resolves as soon as this source of data is initialized
  75. * @internal
  76. */
  77. _init(): SpeedyPromise<void>
  78. {
  79. Utils.log('Initializing PointerSource...');
  80. // nothing to do yet; we need the viewport
  81. return Speedy.Promise.resolve();
  82. }
  83. /**
  84. * Release this source of data
  85. * @returns a promise that resolves as soon as this source of data is released
  86. * @internal
  87. */
  88. _release(): SpeedyPromise<void>
  89. {
  90. this._setViewport(null);
  91. return Speedy.Promise.resolve();
  92. }
  93. /**
  94. * Link a viewport to this source of data
  95. * @param viewport possibly null
  96. * @internal
  97. */
  98. _setViewport(viewport: Viewport | null): void
  99. {
  100. // unlink previous viewport, if any
  101. if(this._viewport !== null) {
  102. this._viewport.hud.container.style.removeProperty('pointer-events');
  103. this._viewport._subContainer.style.removeProperty('pointer-events');
  104. this._viewport.container.style.removeProperty('pointer-events');
  105. this._viewport.canvas.style.removeProperty('pointer-events');
  106. this._removeEventListeners(this._viewport.canvas);
  107. }
  108. // link new viewport, if any
  109. if((this._viewport = viewport) !== null) {
  110. this._addEventListeners(this._viewport.canvas);
  111. this._viewport.canvas.style.pointerEvents = 'auto';
  112. this._viewport.container.style.pointerEvents = 'none';
  113. this._viewport._subContainer.style.pointerEvents = 'none';
  114. this._viewport.hud.container.style.pointerEvents = 'none';
  115. // Make HUD elements accept pointer events
  116. for(const element of this._viewport.hud.container.children) {
  117. const el = element as HTMLElement;
  118. if(el.style.getPropertyValue('pointer-events') == '')
  119. el.style.pointerEvents = 'auto';
  120. }
  121. }
  122. }
  123. /**
  124. * Event handler
  125. * @param event
  126. */
  127. private _onPointerEvent(event: PointerEvent): void
  128. {
  129. this._queue.push(event);
  130. event.preventDefault();
  131. }
  132. /**
  133. * Cancel event
  134. * @param event
  135. */
  136. private _cancelEvent(event: Event): void
  137. {
  138. if(event.cancelable)
  139. event.preventDefault();
  140. }
  141. /**
  142. * Add event listeners
  143. * @param canvas
  144. */
  145. private _addEventListeners(canvas: HTMLCanvasElement): void
  146. {
  147. canvas.addEventListener('pointerdown', this._onPointerEvent);
  148. canvas.addEventListener('pointerup', this._onPointerEvent);
  149. canvas.addEventListener('pointermove', this._onPointerEvent);
  150. canvas.addEventListener('pointercancel', this._onPointerEvent);
  151. canvas.addEventListener('pointerleave', this._onPointerEvent);
  152. canvas.addEventListener('pointerenter', this._onPointerEvent);
  153. canvas.addEventListener('touchstart', this._cancelEvent, { passive: false });
  154. }
  155. /**
  156. * Remove event listeners
  157. * @param canvas
  158. */
  159. private _removeEventListeners(canvas: HTMLCanvasElement): void
  160. {
  161. canvas.removeEventListener('touchstart', this._cancelEvent);
  162. canvas.removeEventListener('pointerenter', this._onPointerEvent);
  163. canvas.removeEventListener('pointerleave', this._onPointerEvent);
  164. canvas.removeEventListener('pointercancel', this._onPointerEvent);
  165. canvas.removeEventListener('pointermove', this._onPointerEvent);
  166. canvas.removeEventListener('pointerup', this._onPointerEvent);
  167. canvas.removeEventListener('pointerdown', this._onPointerEvent);
  168. }
  169. }