Explorar el Código

Introduced a built-in fullscreen button

customisations
alemart hace 11 meses
padre
commit
513fccb55e
Se han modificado 5 ficheros con 194 adiciones y 44 borrados
  1. 4
    3
      docs/api/viewport.md
  2. 24
    8
      plugins/aframe-with-encantar.js
  3. 14
    0
      src/core/viewport.ts
  4. 152
    0
      src/ui/fullscreen-button.ts
  5. 0
    33
      src/ui/stats-panel.ts

+ 4
- 3
docs/api/viewport.md Ver fichero

@@ -17,7 +17,8 @@ Create a new viewport with the specified `settings`.
17 17
     * `hudContainer: HTMLDivElement, optional`. An overlay that will be displayed in front of the augmented scene. It must be a direct child of `container` in the DOM tree.
18 18
     * `resolution: Resolution, optional`. The [resolution](resolution.md) of the virtual scene.
19 19
     * `canvas: HTMLCanvasElement, optional`. An existing canvas on which the virtual scene will be drawn. The engine automatically creates a canvas. You should only specify an existing canvas if you must. Experimental.
20
-    * `style: string, optional.` The [viewport style](#style). *Since:* 0.3.0
20
+    * `style: string, optional`. The [viewport style](#style). *Since:* 0.3.0
21
+    * `fullscreenUI: boolean, optional`. Whether or not to include, as a convenience, the built-in fullscreen button on platforms in which the fullscreen mode is [available](#fullscreenavailable). Defaults to `true`. *Since:* 0.3.0
21 22
 
22 23
 **Returns**
23 24
 
@@ -82,7 +83,7 @@ The default style is `"best-fit"` in immersive mode, or `"inline"` in inline mod
82 83
 
83 84
 `viewport.fullscreen: boolean, read-only`
84 85
 
85
-Whether or not the viewport [container](#container) is being displayed in fullscreen mode.
86
+Whether or not the viewport [container](#container) is being displayed in fullscreen mode. See also: [requestFullscreen](#requestfullscreen).
86 87
 
87 88
 *Since:* 0.3.0
88 89
 
@@ -90,7 +91,7 @@ Whether or not the viewport [container](#container) is being displayed in fullsc
90 91
 
91 92
 `viewport.fullscreenAvailable: boolean, read-only`
92 93
 
93
-Checks the availability of the fullscreen mode on the current platform and page.
94
+Used to check the availability of the fullscreen mode on the current platform and page.
94 95
 
95 96
 *Since:* 0.3.0
96 97
 

+ 24
- 8
plugins/aframe-with-encantar.js Ver fichero

@@ -854,6 +854,7 @@ AFRAME.registerComponent('ar-viewport', ARComponent({
854 854
     {
855 855
         const scene = this.el.sceneEl;
856 856
         const huds = [];
857
+        const fullscreenUI = this.el.components['ar-viewport-fullscreen-ui'];
857 858
 
858 859
         for(const child of this.el.children) {
859 860
             if(child.components !== undefined) {
@@ -870,13 +871,16 @@ AFRAME.registerComponent('ar-viewport', ARComponent({
870 871
         else if(huds.length == 0)
871 872
             huds.push(undefined);
872 873
 
873
-        return AR.Viewport({
874
-            container: this.el,
875
-            hudContainer: huds[0],
876
-            canvas: scene.canvas,
877
-            resolution: this.data.resolution,
878
-            style: this.data.style
879
-        });
874
+        return AR.Viewport(Object.assign(
875
+            {
876
+                container: this.el,
877
+                hudContainer: huds[0],
878
+                canvas: scene.canvas,
879
+                resolution: this.data.resolution,
880
+                style: this.data.style,
881
+            },
882
+            !fullscreenUI ? {} : { fullscreenUI: fullscreenUI.data.enabled }
883
+        ));
880 884
     },
881 885
 
882 886
 }));
@@ -887,10 +891,22 @@ AFRAME.registerPrimitive('ar-viewport', {
887 891
     },
888 892
     mappings: {
889 893
         'resolution': 'ar-viewport.resolution',
890
-        'style': 'ar-viewport.style'
894
+        'style': 'ar-viewport.style',
895
+        'fullscreen-ui': 'ar-viewport-fullscreen-ui'
891 896
     }
892 897
 });
893 898
 
899
+AFRAME.registerComponent('ar-viewport-fullscreen-ui', ARComponent({
900
+
901
+    schema: {
902
+
903
+        /** whether or not to include the built-in fullscreen button */
904
+        'enabled': { type: 'boolean', default: true },
905
+
906
+    }
907
+
908
+}));
909
+
894 910
 /**
895 911
  * AR Heads-Up Display
896 912
  */

+ 14
- 0
src/core/viewport.ts Ver fichero

@@ -28,6 +28,7 @@ import { Nullable } from '../utils/utils';
28 28
 import { Resolution } from '../utils/resolution';
29 29
 import { Utils } from '../utils/utils';
30 30
 import { HUD, HUDContainer } from './hud';
31
+import { FullscreenButton } from '../ui/fullscreen-button';
31 32
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
32 33
 import { IllegalArgumentError, IllegalOperationError, NotSupportedError, AccessDeniedError } from '../utils/errors';
33 34
 
@@ -74,6 +75,9 @@ export interface ViewportSettings
74 75
 
75 76
     /** An existing <canvas> on which the virtual scene will be drawn */
76 77
     canvas?: Nullable<HTMLCanvasElement>;
78
+
79
+    /** Whether or not to include the built-in fullscreen button */
80
+    fullscreenUI?: boolean;
77 81
 }
78 82
 
79 83
 /** Default viewport constructor settings */
@@ -83,6 +87,7 @@ const DEFAULT_VIEWPORT_SETTINGS: Readonly<Required<ViewportSettings>> = {
83 87
     resolution: 'lg',
84 88
     style: 'best-fit',
85 89
     canvas: null,
90
+    fullscreenUI: true,
86 91
 };
87 92
 
88 93
 
@@ -786,6 +791,9 @@ export class Viewport extends ViewportEventTarget
786 791
     /** Fullscreen utilities */
787 792
     private readonly _fullscreen: ViewportFullscreenHelper;
788 793
 
794
+    /** Built-in fullscreen button */
795
+    private readonly _fullscreenButton: Nullable<FullscreenButton>;
796
+
789 797
 
790 798
 
791 799
 
@@ -814,6 +822,10 @@ export class Viewport extends ViewportEventTarget
814 822
         this._resizer.setStrategyByName(this._style);
815 823
 
816 824
         this._fullscreen = new ViewportFullscreenHelper(this);
825
+        this._fullscreenButton = null;
826
+
827
+        if(settings.fullscreenUI && this.fullscreenAvailable)
828
+            this._fullscreenButton = new FullscreenButton(this);
817 829
     }
818 830
 
819 831
     /**
@@ -953,6 +965,7 @@ export class Viewport extends ViewportEventTarget
953 965
         this._hud._init(HUD_ZINDEX);
954 966
         this._canvases.init();
955 967
         this._resizer.init();
968
+        this._fullscreenButton?.init();
956 969
     }
957 970
 
958 971
     /**
@@ -965,5 +978,6 @@ export class Viewport extends ViewportEventTarget
965 978
         this._canvases.release();
966 979
         this._hud._release();
967 980
         this._containers.release();
981
+        this._fullscreenButton?.release();
968 982
     }
969 983
 }

+ 152
- 0
src/ui/fullscreen-button.ts Ver fichero

@@ -0,0 +1,152 @@
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
+ * fullscreen-button.ts
20
+ * A built-in fullscreen button introduced as a convenience
21
+ */
22
+
23
+import { Viewport } from '../core/viewport';
24
+
25
+/** Button icon to be displayed when the fullscreen mode is disabled */
26
+const BUTTON_ICON_OFF = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAbUlEQVRYR+2WOQ4AIAgE5f+PVhobDZANBZAsraAwXMoqFil+f9GBj8BW8dIiKt45at/XgShStHgvmfdekwAdIIEyAmh1Z/U5ikmABPoRsLZWtt+5DUlgHgGr6qM1Pf9XnO131L7fJEQjyOqXEzjP1YAhNmUTrgAAAABJRU5ErkJggg==';
27
+
28
+/** Button icon to be displayed when the fullscreen mode is enabled */
29
+const BUTTON_ICON_ON = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAZElEQVRYR+2WwRIAEAhE9f8fTQ5OhtkLxbzOyc5rJSvBYcH3FwTIBKpHb5d57Nqm5o0aCIBAPgLDxSunq69APT8RCBdwezTLHjglDAEQgEC+QZR2EqqbjprHRgSB9wjwHX9LoAHP1YAhXF4Z/QAAAABJRU5ErkJggg==';
30
+
31
+/** Button size, in pixels */
32
+const BUTTON_SIZE = 64;
33
+
34
+/** Button margin, in pixels */
35
+const BUTTON_MARGIN = 24;
36
+
37
+
38
+
39
+/**
40
+ * Built-in fullscreen button
41
+ */
42
+export class FullscreenButton
43
+{
44
+    /** The viewport associated to this panel */
45
+    private readonly _viewport: Viewport;
46
+
47
+    /** The HTML element of the button */
48
+    private readonly _button: HTMLButtonElement;
49
+
50
+    /** Bound event handler */
51
+    private readonly _boundEventHandler: EventListener;
52
+
53
+
54
+
55
+    /**
56
+     * Constructor
57
+     * @param viewport Viewport
58
+     */
59
+    constructor(viewport: Viewport)
60
+    {
61
+        this._viewport = viewport;
62
+        this._button = this._createButton();
63
+        this._boundEventHandler = this._handleFullscreenEvent.bind(this);
64
+    }
65
+
66
+    /**
67
+     * Initialize
68
+     */
69
+    init(): void
70
+    {
71
+        this._viewport.hud.container.appendChild(this._button);
72
+        this._viewport.addEventListener('fullscreenchange', this._boundEventHandler);
73
+    }
74
+
75
+    /**
76
+     * Release
77
+     */
78
+    release(): void
79
+    {
80
+        this._viewport.removeEventListener('fullscreenchange', this._boundEventHandler);
81
+        this._button.remove();
82
+    }
83
+
84
+    /**
85
+     * Create the <button> element
86
+     */
87
+    private _createButton(): HTMLButtonElement
88
+    {
89
+        const button = document.createElement('button');
90
+        const icon = document.createElement('img');
91
+
92
+        button.style.display = 'inline-block';
93
+        button.style.position = 'absolute';
94
+        button.style.bottom = BUTTON_MARGIN + 'px';
95
+        button.style.right = BUTTON_MARGIN + 'px';
96
+        button.style.width = BUTTON_SIZE + 'px';
97
+        button.style.height = BUTTON_SIZE + 'px';
98
+        button.style.padding = '2px';
99
+
100
+        button.style.backgroundColor = '#7c5ec2';
101
+        button.style.borderColor = '#5c3ba3';
102
+        button.style.borderStyle = 'solid';
103
+        button.style.borderWidth = '2px';
104
+        button.style.borderRadius = '8px';
105
+        button.style.cursor = 'pointer';
106
+        button.draggable = false;
107
+
108
+        icon.src = BUTTON_ICON_OFF;
109
+        icon.draggable = false;
110
+        icon.style.display = 'inline';
111
+        icon.style.width = '100%';
112
+        icon.style.height = '100%';
113
+        icon.style.imageRendering = 'pixelated';
114
+        button.appendChild(icon);
115
+
116
+        const highlight = () => {
117
+            button.style.backgroundColor = '#ffd500';
118
+            button.style.borderColor = '#bb9100';
119
+        };
120
+
121
+        const dehighlight = () => {
122
+            button.style.backgroundColor = '#7e56c2';
123
+            button.style.borderColor = '#5c3ba3';
124
+        };
125
+
126
+        button.addEventListener('pointerdown', highlight);
127
+        button.addEventListener('pointerup', dehighlight);
128
+        button.addEventListener('pointermove', dehighlight);
129
+
130
+        button.addEventListener('click', () => {
131
+            if(!this._viewport.fullscreen) {
132
+                this._viewport.requestFullscreen().catch(err => {
133
+                    alert(`Can't enable the fullscreen mode. ` + err.toString());
134
+                });
135
+            }
136
+            else {
137
+                this._viewport.exitFullscreen();
138
+            }
139
+        });
140
+
141
+        return button;
142
+    }
143
+
144
+    /**
145
+     * Handle a fullscreenchange event
146
+     */
147
+    private _handleFullscreenEvent(event: Event): void
148
+    {
149
+        const icon = this._button.querySelector('img') as HTMLImageElement;
150
+        icon.src = this._viewport.fullscreen ? BUTTON_ICON_ON : BUTTON_ICON_OFF;
151
+    }
152
+}

+ 0
- 33
src/ui/stats-panel.ts Ver fichero

@@ -240,39 +240,6 @@ export class StatsPanel
240 240
         print('<br>');
241 241
         print('OUT: <span class="_ar_out"></span>');
242 242
 
243
-        if(this._viewport.fullscreenAvailable) {
244
-            print('<br>');
245
-            content.appendChild(this._createFullscreenToggle());
246
-        }
247
-
248 243
         return content;
249 244
     }
250
-
251
-    /**
252
-     * Create a fullscreen toggle
253
-     * @returns a fullscreen toggle
254
-     */
255
-    private _createFullscreenToggle(): HTMLElement
256
-    {
257
-        const toggle = document.createElement('a');
258
-
259
-        Utils.assert(this._viewport != null);
260
-
261
-        toggle.href = 'javascript:void(0)';
262
-        toggle.innerText = 'Toggle fullscreen';
263
-        toggle.style.color = 'white';
264
-        toggle.setAttribute('role', 'button');
265
-        toggle.addEventListener('click', () => {
266
-            if(!this._viewport.fullscreen) {
267
-                this._viewport.requestFullscreen().catch(err => {
268
-                    alert(`Can't enable fullscreen mode. ` + err.toString());
269
-                });
270
-            }
271
-            else {
272
-                this._viewport.exitFullscreen();
273
-            }
274
-        });
275
-
276
-        return toggle;
277
-    }
278 245
 }

Loading…
Cancelar
Guardar