浏览代码

Viewport: introduce fullscreen mode

customisations
alemart 1年前
父节点
当前提交
2c6494c980
共有 2 个文件被更改,包括 186 次插入18 次删除
  1. 58
    1
      docs/api/viewport.md
  2. 128
    17
      src/core/viewport.ts

+ 58
- 1
docs/api/viewport.md 查看文件

1
 # Viewport
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
 ## Instantiation
5
 ## Instantiation
6
 
6
 
78
 
78
 
79
 *Since:* 0.2.1
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
 ## Events
138
 ## Events
82
 
139
 
83
 A viewport is an [AREventTarget](ar-event-target.md). You can listen to the following events:
140
 A viewport is an [AREventTarget](ar-event-target.md). You can listen to the following events:

+ 128
- 17
src/core/viewport.ts 查看文件

22
 
22
 
23
 import Speedy from 'speedy-vision';
23
 import Speedy from 'speedy-vision';
24
 import { SpeedySize } from 'speedy-vision/types/core/speedy-size';
24
 import { SpeedySize } from 'speedy-vision/types/core/speedy-size';
25
+import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
25
 import { Nullable } from '../utils/utils';
26
 import { Nullable } from '../utils/utils';
26
 import { Resolution } from './resolution';
27
 import { Resolution } from './resolution';
27
 import { Utils } from '../utils/utils';
28
 import { Utils } from '../utils/utils';
28
-import { IllegalArgumentError, IllegalOperationError } from '../utils/errors';
29
+import { IllegalArgumentError, IllegalOperationError, NotSupportedError, AccessDeniedError } from '../utils/errors';
29
 import { HUD, HUDContainer } from './hud';
30
 import { HUD, HUDContainer } from './hud';
30
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
31
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
31
 
32
 
68
     /** HUD */
69
     /** HUD */
69
     readonly hud: HUD;
70
     readonly hud: HUD;
70
 
71
 
72
+    /** Fullscreen mode */
73
+    readonly fullscreen: boolean;
74
+
71
     /** Canvas on which the virtual scene will be drawn */
75
     /** Canvas on which the virtual scene will be drawn */
72
     readonly canvas: HTMLCanvasElement;
76
     readonly canvas: HTMLCanvasElement;
73
 
77
 
74
     /** Size of the drawing buffer of the foreground canvas */
78
     /** Size of the drawing buffer of the foreground canvas */
75
     readonly virtualSize: SpeedySize;
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
     /** Canvas on which the physical scene will be drawn @internal */
87
     /** Canvas on which the physical scene will be drawn @internal */
78
     readonly _backgroundCanvas: HTMLCanvasElement;
88
     readonly _backgroundCanvas: HTMLCanvasElement;
79
 
89
 
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
      * Viewport container
313
      * Viewport container
214
      */
314
      */
215
     get container(): ViewportContainer
315
     get container(): ViewportContainer
302
 
402
 
303
         // setup CSS
403
         // setup CSS
304
         this._container.style.touchAction = 'none';
404
         this._container.style.touchAction = 'none';
405
+        this._container.style.backgroundColor = 'black';
406
+        this._container.style.zIndex = String(CONTAINER_ZINDEX);
305
 
407
 
306
         // initialize the HUD
408
         // initialize the HUD
307
         this._hud._init(HUD_ZINDEX);
409
         this._hud._init(HUD_ZINDEX);
485
     }
587
     }
486
 
588
 
487
     /**
589
     /**
590
+     * Fullscreen mode
591
+     */
592
+    get fullscreen(): boolean
593
+    {
594
+        return this._base.fullscreen;
595
+    }
596
+
597
+    /**
488
      * Resolution of the virtual scene
598
      * Resolution of the virtual scene
489
      */
599
      */
490
     get resolution(): Resolution
600
     get resolution(): Resolution
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
      * Background canvas
639
      * Background canvas
514
      * @internal
640
      * @internal
515
      */
641
      */
688
 export class ImmersiveViewport extends ResizableViewport
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
      * Release the viewport
817
      * Release the viewport
704
      * @internal
818
      * @internal
705
      */
819
      */
769
     {
883
     {
770
         super._init();
884
         super._init();
771
         this.style = 'inline';
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
 
897
 
787
     /**
898
     /**
788
      * Resize the inline viewport
899
      * Resize the inline viewport
789
-     * (we still take into account orientation changes)
900
+     * (we still take orientation changes into account)
790
      */
901
      */
791
     protected _onResize(): void
902
     protected _onResize(): void
792
     {
903
     {

正在加载...
取消
保存