Explorar el Código

Viewport: introduce fullscreen mode

customisations
alemart hace 1 año
padre
commit
2c6494c980
Se han modificado 2 ficheros con 186 adiciones y 18 borrados
  1. 58
    1
      docs/api/viewport.md
  2. 128
    17
      src/core/viewport.ts

+ 58
- 1
docs/api/viewport.md Ver fichero

@@ -1,6 +1,6 @@
1 1
 # Viewport
2 2
 
3
-The viewport is the area of the web page in which the augmented scene will be displayed.
3
+The viewport is the area of the web page in which the augmented scene is displayed.
4 4
 
5 5
 ## Instantiation
6 6
 
@@ -78,6 +78,63 @@ The default style is `"best-fit"` in immersive mode, or `"inline"` in inline mod
78 78
 
79 79
 *Since:* 0.2.1
80 80
 
81
+### fullscreen
82
+
83
+`viewport.fullscreen: boolean, read-only`
84
+
85
+Whether or not the viewport [container](#container) is being displayed in fullscreen mode.
86
+
87
+*Since:* 0.2.1
88
+
89
+## Methods
90
+
91
+### requestFullscreen
92
+
93
+`viewport.requestFullscreen(): SpeedyPromise<void>`
94
+
95
+Make a request to the user agent so that the viewport [container](#container) is displayed in fullscreen mode. The user must interact with the page (e.g., tap on a button) in order to comply with [browser policies](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen#security), otherwise the request will not succeed.
96
+
97
+!!! info "iPhone support"
98
+
99
+    At the time of this writing, the fullscreen mode is [not supported on iPhone](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen#browser_compatibility). An alternative way to create a fullscreen experience is to set the viewport [style](#style) to `"stretch"` in a [web app](https://developer.mozilla.org/en-US/docs/Web/Manifest/display).
100
+
101
+*Since:* 0.2.1
102
+
103
+**Returns**
104
+
105
+A promise that is resolved when the fullscreen mode is activated, or rejected on error.
106
+
107
+**Example**
108
+
109
+```js
110
+function toggleFullscreen()
111
+{
112
+    if(!viewport.fullscreen) {
113
+        viewport.requestFullscreen().catch(err => {
114
+            alert(`Can't enable fullscreen mode. ` + err.toString());
115
+        });
116
+    }
117
+    else {
118
+        viewport.exitFullscreen();
119
+    }
120
+}
121
+
122
+// require user interaction
123
+button.addEventListener('click', toggleFullscreen);
124
+```
125
+
126
+### exitFullscreen
127
+
128
+`viewport.exitFullscreen(): SpeedyPromise<void>`
129
+
130
+Exit fullscreen mode.
131
+
132
+*Since:* 0.2.1
133
+
134
+**Returns**
135
+
136
+A promise that is resolved once the fullscreen mode is no longer active, or rejected on error. The promise will be rejected if the method is called when not in fullscreen mode.
137
+
81 138
 ## Events
82 139
 
83 140
 A viewport is an [AREventTarget](ar-event-target.md). You can listen to the following events:

+ 128
- 17
src/core/viewport.ts Ver fichero

@@ -22,10 +22,11 @@
22 22
 
23 23
 import Speedy from 'speedy-vision';
24 24
 import { SpeedySize } from 'speedy-vision/types/core/speedy-size';
25
+import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
25 26
 import { Nullable } from '../utils/utils';
26 27
 import { Resolution } from './resolution';
27 28
 import { Utils } from '../utils/utils';
28
-import { IllegalArgumentError, IllegalOperationError } from '../utils/errors';
29
+import { IllegalArgumentError, IllegalOperationError, NotSupportedError, AccessDeniedError } from '../utils/errors';
29 30
 import { HUD, HUDContainer } from './hud';
30 31
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
31 32
 
@@ -68,12 +69,21 @@ export interface Viewport extends ViewportEventTarget
68 69
     /** HUD */
69 70
     readonly hud: HUD;
70 71
 
72
+    /** Fullscreen mode */
73
+    readonly fullscreen: boolean;
74
+
71 75
     /** Canvas on which the virtual scene will be drawn */
72 76
     readonly canvas: HTMLCanvasElement;
73 77
 
74 78
     /** Size of the drawing buffer of the foreground canvas */
75 79
     readonly virtualSize: SpeedySize;
76 80
 
81
+    /** Request fullscreen mode */
82
+    requestFullscreen(): SpeedyPromise<void>;
83
+
84
+    /** Exit fullscreen mode */
85
+    exitFullscreen(): SpeedyPromise<void>;
86
+
77 87
     /** Canvas on which the physical scene will be drawn @internal */
78 88
     readonly _backgroundCanvas: HTMLCanvasElement;
79 89
 
@@ -210,6 +220,96 @@ export class BaseViewport extends ViewportEventTarget implements Viewport
210 220
     }
211 221
 
212 222
     /**
223
+     * Make a request to the user agent so that the viewport container is
224
+     * displayed in fullscreen mode. The container must be a compatible element[1]
225
+     * and the user must interact with the page in order to comply with browser
226
+     * policies[2]. In case of error, the returned promise is rejected.
227
+     * [1] https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen#compatible_elements
228
+     * [2] https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen#security
229
+     */
230
+    requestFullscreen(): SpeedyPromise<void>
231
+    {
232
+        const container = this._container;
233
+
234
+        // fallback for older WebKit versions
235
+        if(container.requestFullscreen === undefined) {
236
+            if((container as any).webkitRequestFullscreen === undefined)
237
+                return Speedy.Promise.reject(new NotSupportedError());
238
+            else if(!(document as any).webkitFullscreenEnabled)
239
+                return Speedy.Promise.reject(new AccessDeniedError());
240
+
241
+            // webkitRequestFullscreen() does not return a value
242
+            (container as any).webkitRequestFullscreen();
243
+
244
+            return new Speedy.Promise<void>((resolve, reject) => {
245
+                setTimeout(() => {
246
+                    if(container === (document as any).webkitFullscreenElement)
247
+                        resolve();
248
+                    else
249
+                        reject(new AccessDeniedError());
250
+                }, 100);
251
+            });
252
+        }
253
+
254
+        // check if fullscreen is supported
255
+        if(!document.fullscreenEnabled)
256
+            return Speedy.Promise.reject(new AccessDeniedError());
257
+
258
+        // request fullscreen
259
+        return new Speedy.Promise<void>((resolve, reject) => {
260
+            container.requestFullscreen({
261
+                navigationUI: 'hide'
262
+            }).then(resolve, reject);
263
+        });
264
+    }
265
+
266
+    /**
267
+     * Exit fullscreen mode
268
+     */
269
+    exitFullscreen(): SpeedyPromise<void>
270
+    {
271
+        // fallback for older WebKit versions
272
+        if(document.exitFullscreen === undefined) {
273
+            const doc = document as any;
274
+
275
+            if(doc.webkitExitFullscreen === undefined)
276
+                return Speedy.Promise.reject(new NotSupportedError());
277
+            else if(doc.webkitFullscreenElement === null)
278
+                return Speedy.Promise.reject(new TypeError('Not in fullscreen mode'));
279
+
280
+            // webkitExitFullscreen() does not return a value
281
+            doc.webkitExitFullscreen();
282
+
283
+            return new Speedy.Promise<void>((resolve, reject) => {
284
+                setTimeout(() => {
285
+                    if(doc.webkitFullscreenElement === null)
286
+                        resolve();
287
+                    else
288
+                        reject(new TypeError());
289
+                }, 100);
290
+            });
291
+        }
292
+
293
+        // exit fullscreen
294
+        return new Speedy.Promise<void>((resolve, reject) => {
295
+            document.exitFullscreen().then(resolve, reject);
296
+        });
297
+    }
298
+
299
+    /**
300
+     * True if the viewport is being displayed in fullscreen mode
301
+     */
302
+    get fullscreen(): boolean
303
+    {
304
+        if(document.fullscreenElement !== undefined)
305
+            return document.fullscreenElement === this._container;
306
+        else if((document as any).webkitFullscreenElement !== undefined)
307
+            return (document as any).webkitFullscreenElement === this._container;
308
+        else
309
+            return false;
310
+    }
311
+
312
+    /**
213 313
      * Viewport container
214 314
      */
215 315
     get container(): ViewportContainer
@@ -302,6 +402,8 @@ export class BaseViewport extends ViewportEventTarget implements Viewport
302 402
 
303 403
         // setup CSS
304 404
         this._container.style.touchAction = 'none';
405
+        this._container.style.backgroundColor = 'black';
406
+        this._container.style.zIndex = String(CONTAINER_ZINDEX);
305 407
 
306 408
         // initialize the HUD
307 409
         this._hud._init(HUD_ZINDEX);
@@ -485,6 +587,14 @@ abstract class ViewportDecorator extends ViewportEventTarget implements Viewport
485 587
     }
486 588
 
487 589
     /**
590
+     * Fullscreen mode
591
+     */
592
+    get fullscreen(): boolean
593
+    {
594
+        return this._base.fullscreen;
595
+    }
596
+
597
+    /**
488 598
      * Resolution of the virtual scene
489 599
      */
490 600
     get resolution(): Resolution
@@ -510,6 +620,22 @@ abstract class ViewportDecorator extends ViewportEventTarget implements Viewport
510 620
     }
511 621
 
512 622
     /**
623
+     * Request fullscreen mode
624
+     */
625
+    requestFullscreen(): SpeedyPromise<void>
626
+    {
627
+        return this._base.requestFullscreen();
628
+    }
629
+
630
+    /**
631
+     * Exit fullscreen mode
632
+     */
633
+    exitFullscreen(): SpeedyPromise<void>
634
+    {
635
+        return this._base.exitFullscreen();
636
+    }
637
+
638
+    /**
513 639
      * Background canvas
514 640
      * @internal
515 641
      */
@@ -688,18 +814,6 @@ abstract class ResizableViewport extends ViewportDecorator
688 814
 export class ImmersiveViewport extends ResizableViewport
689 815
 {
690 816
     /**
691
-     * Initialize the viewport
692
-     * @internal
693
-     */
694
-    _init(): void
695
-    {
696
-        super._init();
697
-
698
-        this.container.style.zIndex = String(CONTAINER_ZINDEX);
699
-        this.container.style.backgroundColor = 'black';
700
-    }
701
-
702
-    /**
703 817
      * Release the viewport
704 818
      * @internal
705 819
      */
@@ -769,9 +883,6 @@ export class InlineViewport extends ResizableViewport
769 883
     {
770 884
         super._init();
771 885
         this.style = 'inline';
772
-
773
-        this.container.style.zIndex = String(CONTAINER_ZINDEX);
774
-        this.container.style.backgroundColor = 'black';
775 886
     }
776 887
 
777 888
     /**
@@ -786,7 +897,7 @@ export class InlineViewport extends ResizableViewport
786 897
 
787 898
     /**
788 899
      * Resize the inline viewport
789
-     * (we still take into account orientation changes)
900
+     * (we still take orientation changes into account)
790 901
      */
791 902
     protected _onResize(): void
792 903
     {

Loading…
Cancelar
Guardar