瀏覽代碼

Introduced a built-in fullscreen button

customisations
alemart 11 月之前
父節點
當前提交
513fccb55e
共有 5 個文件被更改,包括 194 次插入44 次删除
  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 查看文件

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.
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
     * `resolution: Resolution, optional`. The [resolution](resolution.md) of the virtual scene.
18
     * `resolution: Resolution, optional`. The [resolution](resolution.md) of the virtual scene.
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.
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
 **Returns**
23
 **Returns**
23
 
24
 
82
 
83
 
83
 `viewport.fullscreen: boolean, read-only`
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
 *Since:* 0.3.0
88
 *Since:* 0.3.0
88
 
89
 
90
 
91
 
91
 `viewport.fullscreenAvailable: boolean, read-only`
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
 *Since:* 0.3.0
96
 *Since:* 0.3.0
96
 
97
 

+ 24
- 8
plugins/aframe-with-encantar.js 查看文件

854
     {
854
     {
855
         const scene = this.el.sceneEl;
855
         const scene = this.el.sceneEl;
856
         const huds = [];
856
         const huds = [];
857
+        const fullscreenUI = this.el.components['ar-viewport-fullscreen-ui'];
857
 
858
 
858
         for(const child of this.el.children) {
859
         for(const child of this.el.children) {
859
             if(child.components !== undefined) {
860
             if(child.components !== undefined) {
870
         else if(huds.length == 0)
871
         else if(huds.length == 0)
871
             huds.push(undefined);
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
     },
891
     },
888
     mappings: {
892
     mappings: {
889
         'resolution': 'ar-viewport.resolution',
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
  * AR Heads-Up Display
911
  * AR Heads-Up Display
896
  */
912
  */

+ 14
- 0
src/core/viewport.ts 查看文件

28
 import { Resolution } from '../utils/resolution';
28
 import { Resolution } from '../utils/resolution';
29
 import { Utils } from '../utils/utils';
29
 import { Utils } from '../utils/utils';
30
 import { HUD, HUDContainer } from './hud';
30
 import { HUD, HUDContainer } from './hud';
31
+import { FullscreenButton } from '../ui/fullscreen-button';
31
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
32
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
32
 import { IllegalArgumentError, IllegalOperationError, NotSupportedError, AccessDeniedError } from '../utils/errors';
33
 import { IllegalArgumentError, IllegalOperationError, NotSupportedError, AccessDeniedError } from '../utils/errors';
33
 
34
 
74
 
75
 
75
     /** An existing <canvas> on which the virtual scene will be drawn */
76
     /** An existing <canvas> on which the virtual scene will be drawn */
76
     canvas?: Nullable<HTMLCanvasElement>;
77
     canvas?: Nullable<HTMLCanvasElement>;
78
+
79
+    /** Whether or not to include the built-in fullscreen button */
80
+    fullscreenUI?: boolean;
77
 }
81
 }
78
 
82
 
79
 /** Default viewport constructor settings */
83
 /** Default viewport constructor settings */
83
     resolution: 'lg',
87
     resolution: 'lg',
84
     style: 'best-fit',
88
     style: 'best-fit',
85
     canvas: null,
89
     canvas: null,
90
+    fullscreenUI: true,
86
 };
91
 };
87
 
92
 
88
 
93
 
786
     /** Fullscreen utilities */
791
     /** Fullscreen utilities */
787
     private readonly _fullscreen: ViewportFullscreenHelper;
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
         this._resizer.setStrategyByName(this._style);
822
         this._resizer.setStrategyByName(this._style);
815
 
823
 
816
         this._fullscreen = new ViewportFullscreenHelper(this);
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
         this._hud._init(HUD_ZINDEX);
965
         this._hud._init(HUD_ZINDEX);
954
         this._canvases.init();
966
         this._canvases.init();
955
         this._resizer.init();
967
         this._resizer.init();
968
+        this._fullscreenButton?.init();
956
     }
969
     }
957
 
970
 
958
     /**
971
     /**
965
         this._canvases.release();
978
         this._canvases.release();
966
         this._hud._release();
979
         this._hud._release();
967
         this._containers.release();
980
         this._containers.release();
981
+        this._fullscreenButton?.release();
968
     }
982
     }
969
 }
983
 }

+ 152
- 0
src/ui/fullscreen-button.ts 查看文件

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 查看文件

240
         print('<br>');
240
         print('<br>');
241
         print('OUT: <span class="_ar_out"></span>');
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
         return content;
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…
取消
儲存