Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

hud.ts 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * encantar.js
  3. * GPU-accelerated Augmented Reality for the web
  4. * Copyright (C) 2022-2025 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. * hud.ts
  20. * Heads Up Display
  21. */
  22. import { Viewport } from './viewport';
  23. import { StatsPanel } from '../ui/stats-panel';
  24. import { FullscreenButton } from '../ui/fullscreen-button';
  25. import { Nullable, Utils } from '../utils/utils';
  26. /** HUD container */
  27. export type HUDContainer = HTMLDivElement;
  28. /**
  29. * Heads Up Display: an overlay displayed in front of the augmented scene
  30. */
  31. export class HUD
  32. {
  33. /** Container */
  34. private _container: HUDContainer;
  35. /** Whether or not we have created our own container */
  36. private _isOwnContainer: boolean;
  37. /** Container for the internal components */
  38. private _internalContainer: ShadowRoot;
  39. /** Stats panel */
  40. #statsPanel: StatsPanel;
  41. /** Fullscreen button */
  42. #fullscreenButton: FullscreenButton;
  43. /**
  44. * Constructor
  45. * @param viewport viewport
  46. * @param parent parent of the hud container
  47. * @param hudContainer an existing hud container (optional)
  48. */
  49. constructor(viewport: Viewport, parent: HTMLElement, hudContainer: Nullable<HUDContainer> = null)
  50. {
  51. this._container = hudContainer || this._createContainer(parent);
  52. this._isOwnContainer = (hudContainer == null);
  53. // move the HUD container to the parent node
  54. if(this._container.parentElement !== parent) {
  55. this._container.remove();
  56. parent.insertAdjacentElement('afterbegin', this._container);
  57. }
  58. // the HUD should be hidden initially
  59. if(!this._container.hidden) {
  60. Utils.warning(`The container of the HUD should have the hidden attribute`);
  61. this._container.hidden = true;
  62. }
  63. // create a shadow tree for the internal components
  64. this._internalContainer = parent.attachShadow({ mode: 'closed' });
  65. this._internalContainer.appendChild(document.createElement('slot'));
  66. // create internal components
  67. this.#statsPanel = new StatsPanel();
  68. this.#fullscreenButton = new FullscreenButton(viewport);
  69. }
  70. /**
  71. * The container of the HUD
  72. */
  73. get container(): HUDContainer
  74. {
  75. return this._container;
  76. }
  77. /**
  78. * Whether or not the HUD is visible
  79. * @deprecated what's the purpose of this being public?
  80. */
  81. get visible(): boolean
  82. {
  83. return this._visible;
  84. }
  85. /**
  86. * Whether or not the HUD is visible
  87. * @deprecated what's the purpose of this being public?
  88. */
  89. set visible(visible: boolean)
  90. {
  91. // this setter does nothing since 0.4.3
  92. }
  93. /**
  94. * Stats panel
  95. * @internal
  96. */
  97. get _statsPanel(): StatsPanel
  98. {
  99. return this.#statsPanel; // same name
  100. }
  101. /**
  102. * Initialize the HUD
  103. * @param zIndex the z-index of the container
  104. * @param wantStatsPanel
  105. * @param wantFullscreenButton
  106. * @internal
  107. */
  108. _init(zIndex: number, wantStatsPanel: boolean, wantFullscreenButton: boolean): void
  109. {
  110. const parent = this._internalContainer;
  111. this.#statsPanel.init(parent, wantStatsPanel);
  112. this.#fullscreenButton.init(parent, wantFullscreenButton);
  113. for(const element of parent.children as any as HTMLElement[]) {
  114. if(element.style.getPropertyValue('pointer-events') == '')
  115. element.style.pointerEvents = 'auto'; // accept pointer input
  116. if(element.style.getPropertyValue('z-index') == '')
  117. element.style.zIndex = '1000000';
  118. }
  119. const container = this._container;
  120. container.style.position = 'absolute';
  121. container.style.left = container.style.top = '0px';
  122. container.style.right = container.style.bottom = '0px';
  123. container.style.padding = container.style.margin = '0px';
  124. container.style.zIndex = String(zIndex);
  125. container.style.userSelect = 'none';
  126. this._visible = true;
  127. }
  128. /**
  129. * Release the HUD
  130. * @internal
  131. */
  132. _release(): void
  133. {
  134. this._visible = false;
  135. this.#fullscreenButton.release();
  136. this.#statsPanel.release();
  137. if(this._isOwnContainer) {
  138. this._isOwnContainer = false;
  139. this._container.remove();
  140. }
  141. }
  142. /**
  143. * Create a HUD container as an immediate child of the input node
  144. * @param parent parent container
  145. * @returns HUD container
  146. */
  147. private _createContainer(parent: HTMLElement): HUDContainer
  148. {
  149. const node = document.createElement('div');
  150. node.hidden = true;
  151. parent.insertAdjacentElement('afterbegin', node);
  152. return node;
  153. }
  154. /**
  155. * Whether or not the HUD is visible
  156. */
  157. private get _visible(): boolean
  158. {
  159. return !this._container.hidden;
  160. }
  161. /**
  162. * Whether or not the HUD is visible
  163. */
  164. private set _visible(visible: boolean)
  165. {
  166. this._container.hidden = !visible;
  167. }
  168. }