Explorar el Código

Introduce viewport styles. Improvements to the code

customisations
alemart hace 1 año
padre
commit
883e0d7664
Se han modificado 4 ficheros con 306 adiciones y 159 borrados
  1. 19
    4
      docs/api/viewport.md
  2. 2
    2
      src/core/gizmos.ts
  3. 4
    4
      src/core/session.ts
  4. 281
    149
      src/core/viewport.ts

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

@@ -17,6 +17,7 @@ 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.2.1
20 21
 
21 22
 **Returns**
22 23
 
@@ -51,17 +52,31 @@ The [HUD](hud.md).
51 52
 
52 53
 The [resolution](resolution.md) of the virtual scene.
53 54
 
55
+### virtualSize
56
+
57
+`viewport.virtualSize: SpeedySize, read-only`
58
+
59
+The size in pixels that matches the [resolution](#resolution) of the virtual scene.
60
+
54 61
 ### canvas
55 62
 
56 63
 `viewport.canvas: HTMLCanvasElement, read-only`
57 64
 
58 65
 A `<canvas>` on which the virtual scene is drawn.
59 66
 
60
-### virtualSize
67
+### style
61 68
 
62
-`viewport.virtualSize: SpeedySize, read-only`
69
+`viewport.style: string`
63 70
 
64
-The size in pixels that matches the [resolution](#resolution) of the virtual scene.
71
+The style determines the way the viewport appears on the screen. Different styles are applicable to different [session modes](session.md#mode). The following are valid styles:
72
+
73
+* `"best-fit"`: an immersive viewport that is scaled in a way that covers the page while preserving the aspect ratio of the augmented scene.
74
+* `"stretch"`: an immersive viewport that is scaled in a way that covers the entire page, stretching the augmented scene if necessary.
75
+* `"inline"`: an inline viewport that follows the typical flow of a web page.
76
+
77
+The default style is `"best-fit"` in immersive mode, or `"inline"` in inline mode.
78
+
79
+*Since:* 0.2.1
65 80
 
66 81
 ## Events
67 82
 
@@ -69,7 +84,7 @@ A viewport is an [AREventTarget](ar-event-target.md). You can listen to the foll
69 84
 
70 85
 ### resize
71 86
 
72
-The viewport has been resized. This may happen when the user resizes the window of the web browser or when the mobile device is flipped.
87
+The viewport has been resized. This will happen when the user resizes the window of the web browser or when the mobile device is flipped.
73 88
 
74 89
 **Example**
75 90
 

+ 2
- 2
src/core/gizmos.ts Ver fichero

@@ -84,8 +84,8 @@ export class Gizmos
84 84
             return;
85 85
 
86 86
         // viewport
87
-        const viewportSize = viewport._size;
88
-        const canvas = viewport._background;
87
+        const viewportSize = viewport._realSize;
88
+        const canvas = viewport._backgroundCanvas;
89 89
         const ctx = canvas.getContext('2d', { alpha: false });
90 90
         if(!ctx)
91 91
             throw new IllegalOperationError();

+ 4
- 4
src/core/session.ts Ver fichero

@@ -26,7 +26,7 @@ import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
26 26
 import { Nullable, Utils } from '../utils/utils';
27 27
 import { AREvent, AREventTarget } from '../utils/ar-events';
28 28
 import { IllegalArgumentError, IllegalOperationError, NotSupportedError } from '../utils/errors';
29
-import { Viewport, ImmersiveViewport, InlineViewport } from './viewport';
29
+import { Viewport, BaseViewport, ImmersiveViewport, InlineViewport } from './viewport';
30 30
 import { Settings } from './settings';
31 31
 import { Stats } from './stats';
32 32
 import { StatsPanel } from './stats-panel';
@@ -53,7 +53,7 @@ export interface SessionOptions
53 53
     sources: Source[];
54 54
 
55 55
     /** viewport */
56
-    viewport: Nullable<Viewport>;
56
+    viewport: Nullable<BaseViewport>;
57 57
 
58 58
     /** show stats? */
59 59
     stats?: boolean;
@@ -141,7 +141,7 @@ export class Session extends AREventTarget<SessionEventType>
141 141
      * @param stats render stats panel?
142 142
      * @param gizmos render gizmos?
143 143
      */
144
-    private constructor(sources: Source[], mode: SessionMode, viewport: Viewport, stats: boolean, gizmos: boolean)
144
+    private constructor(sources: Source[], mode: SessionMode, viewport: BaseViewport, stats: boolean, gizmos: boolean)
145 145
     {
146 146
         super();
147 147
 
@@ -495,7 +495,7 @@ export class Session extends AREventTarget<SessionEventType>
495 495
      */
496 496
     private _renderUserMedia(): void
497 497
     {
498
-        const canvas = this._viewport._background;
498
+        const canvas = this._viewport._backgroundCanvas;
499 499
         const ctx = canvas.getContext('2d', { alpha: false });
500 500
         
501 501
         if(ctx && this.media.type != 'data') {

+ 281
- 149
src/core/viewport.ts Ver fichero

@@ -30,6 +30,7 @@ import { HUD, HUDContainer } from './hud';
30 30
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
31 31
 
32 32
 
33
+
33 34
 /** Viewport container */
34 35
 export type ViewportContainer = HTMLDivElement;
35 36
 
@@ -42,10 +43,18 @@ type ViewportEventType = 'resize';
42 43
 /** An event emitted by a Viewport */
43 44
 class ViewportEvent extends AREvent<ViewportEventType> { }
44 45
 
46
+/** Viewport event target */
47
+class ViewportEventTarget extends AREventTarget<ViewportEventType> { }
48
+
49
+/** Viewport style (immersive mode) */
50
+type ViewportStyle = 'best-fit' | 'stretch' | 'inline';
51
+
52
+
53
+
45 54
 /**
46 55
  * Viewport interface
47 56
  */
48
-export interface Viewport extends AREventTarget<ViewportEventType>
57
+export interface Viewport extends ViewportEventTarget
49 58
 {
50 59
     /** Resolution of the virtual scene */
51 60
     readonly resolution: Resolution;
@@ -53,29 +62,29 @@ export interface Viewport extends AREventTarget<ViewportEventType>
53 62
     /** Viewport container */
54 63
     readonly container: ViewportContainer;
55 64
 
65
+    /** Viewport style */
66
+    style: ViewportStyle;
67
+
56 68
     /** HUD */
57 69
     readonly hud: HUD;
58 70
 
59
-    /** Size of the drawing buffer of the foreground canvas */
60
-    readonly virtualSize: SpeedySize;
61
-
62 71
     /** Canvas on which the virtual scene will be drawn */
63 72
     readonly canvas: HTMLCanvasElement;
64 73
 
74
+    /** Size of the drawing buffer of the foreground canvas */
75
+    readonly virtualSize: SpeedySize;
76
+
65 77
     /** Canvas on which the physical scene will be drawn @internal */
66
-    readonly _background: HTMLCanvasElement;
78
+    readonly _backgroundCanvas: HTMLCanvasElement;
67 79
 
68 80
     /** Size of the drawing buffer of the background canvas @internal */
69
-    readonly _size: SpeedySize;
81
+    readonly _realSize: SpeedySize;
70 82
 
71 83
     /** Initialize the viewport @internal */
72 84
     _init(): void;
73 85
 
74 86
     /** Release the viewport @internal */
75 87
     _release(): void;
76
-
77
-    /** Function to be called when the viewport is resized @internal */
78
-    _onResize(): void;
79 88
 }
80 89
 
81 90
 /**
@@ -92,6 +101,9 @@ export interface ViewportSettings
92 101
     /** Resolution of the canvas on which the virtual scene will be drawn */
93 102
     resolution?: Resolution;
94 103
 
104
+    /** Viewport style */
105
+    style?: ViewportStyle;
106
+
95 107
     /** An existing <canvas> on which the virtual scene will be drawn */
96 108
     canvas?: Nullable<HTMLCanvasElement>;
97 109
 }
@@ -101,12 +113,25 @@ const DEFAULT_VIEWPORT_SETTINGS: Readonly<Required<ViewportSettings>> = {
101 113
     container: null,
102 114
     hudContainer: null,
103 115
     resolution: 'lg',
116
+    style: 'best-fit',
104 117
     canvas: null,
105 118
 };
106 119
 
120
+/** Z-index of the viewport container */
121
+const CONTAINER_ZINDEX = 1000000000;
122
+
107 123
 /** Base z-index of the children of the viewport container */
108 124
 const BASE_ZINDEX = 0;
109 125
 
126
+/** Z-index of the background canvas */
127
+const BACKGROUND_ZINDEX = BASE_ZINDEX + 0;
128
+
129
+/** Z-index of the foreground canvas */
130
+const FOREGROUND_ZINDEX = BASE_ZINDEX + 1;
131
+
132
+/** Z-index of the HUD */
133
+const HUD_ZINDEX = BASE_ZINDEX + 2;
134
+
110 135
 /** Default viewport width, in pixels */
111 136
 const DEFAULT_VIEWPORT_WIDTH = 300;
112 137
 
@@ -118,7 +143,7 @@ const DEFAULT_VIEWPORT_HEIGHT = 150;
118 143
 /**
119 144
  * Viewport
120 145
  */
121
-export class BaseViewport extends AREventTarget<ViewportEventType> implements Viewport
146
+export class BaseViewport extends ViewportEventTarget implements Viewport
122 147
 {
123 148
     /** Viewport resolution (controls the size of the drawing buffer of the foreground canvas) */
124 149
     private readonly _resolution: Resolution;
@@ -129,8 +154,11 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
129 154
     /** An overlay displayed in front of the augmented scene */
130 155
     protected readonly _hud: HUD;
131 156
 
157
+    /** Viewport style */
158
+    protected _style: ViewportStyle;
159
+
132 160
     /** Internal canvas used to render the physical scene */
133
-    protected readonly _backgroundCanvas: HTMLCanvasElement;
161
+    private readonly __backgroundCanvas: HTMLCanvasElement;
134 162
 
135 163
     /** A canvas used to render the virtual scene */
136 164
     protected readonly _foregroundCanvas: HTMLCanvasElement;
@@ -148,23 +176,37 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
148 176
     {
149 177
         super();
150 178
 
151
-        // validate settings
152 179
         const settings = Object.assign({}, DEFAULT_VIEWPORT_SETTINGS, viewportSettings);
180
+        const size = Speedy.Size(DEFAULT_VIEWPORT_WIDTH, DEFAULT_VIEWPORT_HEIGHT);
181
+
182
+        // validate settings
153 183
         if(settings.container == null)
154 184
             throw new IllegalArgumentError('Unspecified viewport container');
185
+        else if(!(settings.container instanceof HTMLElement))
186
+            throw new IllegalArgumentError('Invalid viewport container');
155 187
 
156 188
         // initialize attributes
157 189
         this._resolution = settings.resolution;
158 190
         this._container = settings.container;
159 191
         this._hud = new HUD(settings.container, settings.hudContainer);
160
-        this._parentOfImportedForegroundCanvas = settings.canvas ? settings.canvas.parentNode : null;
161 192
 
162
-        // create canvas elements
163
-        const size = Speedy.Size(DEFAULT_VIEWPORT_WIDTH, DEFAULT_VIEWPORT_HEIGHT);
164
-        this._backgroundCanvas = this._createBackgroundCanvas(this._container, size);
165
-        this._foregroundCanvas = settings.canvas == null ?
166
-            this._createForegroundCanvas(this._container, size) :
167
-            this._foregroundCanvas = this._importForegroundCanvas(settings.canvas, this._container, size);
193
+        // make this more elegant?
194
+        // need to initialize this._style and validate settings.style
195
+        this._style = DEFAULT_VIEWPORT_SETTINGS.style;
196
+        this.style = settings.style;
197
+
198
+        // create the background canvas
199
+        this.__backgroundCanvas = this._createBackgroundCanvas(this._container, size);
200
+
201
+        // create the foreground canvas
202
+        if(settings.canvas == null) {
203
+            this._foregroundCanvas = this._createForegroundCanvas(this._container, size);
204
+            this._parentOfImportedForegroundCanvas = null;
205
+        }
206
+        else {
207
+            this._foregroundCanvas = settings.canvas;
208
+            this._parentOfImportedForegroundCanvas = settings.canvas.parentNode;
209
+        }
168 210
     }
169 211
 
170 212
     /**
@@ -176,6 +218,25 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
176 218
     }
177 219
 
178 220
     /**
221
+     * Viewport style
222
+     */
223
+    get style(): ViewportStyle
224
+    {
225
+        return this._style;
226
+    }
227
+
228
+    /**
229
+     * Set viewport style
230
+     */
231
+    set style(value: ViewportStyle)
232
+    {
233
+        if(value != 'best-fit' && value != 'stretch' && value != 'inline')
234
+            throw new IllegalArgumentError('Invalid viewport style: ' + value);
235
+
236
+        this._style = value;
237
+    }
238
+
239
+    /**
179 240
      * HUD
180 241
      */
181 242
     get hud(): HUD
@@ -210,19 +271,19 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
210 271
     }
211 272
 
212 273
     /**
213
-     * Background canvas
274
+     * The canvas on which the physical scene will be drawn
214 275
      * @internal
215 276
      */
216
-    get _background(): HTMLCanvasElement
277
+    get _backgroundCanvas(): HTMLCanvasElement
217 278
     {
218
-        return this._backgroundCanvas;
279
+        return this.__backgroundCanvas;
219 280
     }
220 281
 
221 282
     /**
222 283
      * Size of the drawing buffer of the background canvas, in pixels
223 284
      * @internal
224 285
      */
225
-    get _size(): SpeedySize
286
+    get _realSize(): SpeedySize
226 287
     {
227 288
         throw new IllegalOperationError();
228 289
     }
@@ -233,8 +294,17 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
233 294
      */
234 295
     _init(): void
235 296
     {
297
+        // import foreground canvas
298
+        if(this._parentOfImportedForegroundCanvas != null) {
299
+            const size = Speedy.Size(DEFAULT_VIEWPORT_WIDTH, DEFAULT_VIEWPORT_HEIGHT);
300
+            this._importForegroundCanvas(this._foregroundCanvas, this._container, size);
301
+        }
302
+
303
+        // setup CSS
236 304
         this._container.style.touchAction = 'none';
237
-        this._hud._init(BASE_ZINDEX + 2);
305
+
306
+        // initialize the HUD
307
+        this._hud._init(HUD_ZINDEX);
238 308
         this._hud.visible = true;
239 309
     }
240 310
 
@@ -244,29 +314,32 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
244 314
      */
245 315
     _release(): void
246 316
     {
247
-        //this._hud.visible = false; // depends on the type of the viewport
317
+        // release the HUD
248 318
         this._hud._release();
249
-        this._restoreImportedForegroundCanvas();
319
+
320
+        // reset the CSS
250 321
         this._container.style.touchAction = 'auto';
322
+
323
+        // restore imported canvas
324
+        if(this._parentOfImportedForegroundCanvas != null)
325
+            this._restoreImportedForegroundCanvas();
251 326
     }
252 327
 
253 328
     /**
254
-     * Function to be called when the viewport is resized
255
-     * @internal
329
+     * Create a canvas and attach it to another HTML element
330
+     * @param parent parent container
331
+     * @param size size of the drawing buffer
332
+     * @returns a new canvas as a child of parent
256 333
      */
257
-    _onResize(): void
334
+    private _createCanvas(parent: HTMLElement, size: SpeedySize): HTMLCanvasElement
258 335
     {
259
-        // Resize the drawing buffer of the foreground canvas, so that it
260
-        // matches the desired resolution and the aspect ratio of the
261
-        // background canvas
262
-        const virtualSize = this.virtualSize;
263
-        this._foregroundCanvas.width = virtualSize.width;
264
-        this._foregroundCanvas.height = virtualSize.height;
265
-        this._styleCanvas(this._foregroundCanvas, 'foreground');
336
+        const canvas = document.createElement('canvas') as HTMLCanvasElement;
266 337
 
267
-        // dispatch event
268
-        const event = new ViewportEvent('resize');
269
-        this.dispatchEvent(event);
338
+        canvas.width = size.width;
339
+        canvas.height = size.height;
340
+        parent.appendChild(canvas);
341
+
342
+        return canvas;
270 343
     }
271 344
 
272 345
     /**
@@ -278,7 +351,7 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
278 351
     private _createBackgroundCanvas(parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
279 352
     {
280 353
         const canvas = this._createCanvas(parent, size);
281
-        return this._styleCanvas(canvas, 'background');
354
+        return this._styleCanvas(canvas, BACKGROUND_ZINDEX);
282 355
     }
283 356
 
284 357
     /**
@@ -290,49 +363,7 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
290 363
     private _createForegroundCanvas(parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
291 364
     {
292 365
         const canvas = this._createCanvas(parent, size);
293
-        return this._styleCanvas(canvas, 'foreground');
294
-    }
295
-
296
-    /**
297
-     * Create a canvas and attach it to another HTML element
298
-     * @param parent parent container
299
-     * @param size size of the drawing buffer
300
-     * @returns a new canvas as a child of parent
301
-     */
302
-    private _createCanvas(parent: HTMLElement, size: SpeedySize): HTMLCanvasElement
303
-    {
304
-        const canvas = document.createElement('canvas') as HTMLCanvasElement;
305
-
306
-        canvas.width = size.width;
307
-        canvas.height = size.height;
308
-        parent.appendChild(canvas);
309
-
310
-        return canvas;
311
-    }
312
-
313
-    /**
314
-     * Add suitable CSS rules to a canvas
315
-     * @param canvas
316
-     * @param canvasType
317
-     * @returns canvas
318
-     */
319
-    private _styleCanvas(canvas: HTMLCanvasElement, canvasType: 'foreground' | 'background'): HTMLCanvasElement
320
-    {
321
-        const offset = (canvasType == 'foreground') ? 1 : 0;
322
-        const zIndex = BASE_ZINDEX + offset;
323
-
324
-        canvas.setAttribute('style', [
325
-            'position: absolute',
326
-            'left: 0px',
327
-            'top: 0px',
328
-
329
-            'z-index: ' + String(zIndex),
330
-
331
-            'width: 100% !important',
332
-            'height: 100% !important',
333
-        ].join('; '));
334
-
335
-        return canvas;
366
+        return this._styleCanvas(canvas, FOREGROUND_ZINDEX);
336 367
     }
337 368
 
338 369
     /**
@@ -345,7 +376,7 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
345 376
     private _importForegroundCanvas(canvas: HTMLCanvasElement, parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
346 377
     {
347 378
         if(!(canvas instanceof HTMLCanvasElement))
348
-            throw new IllegalArgumentError(`Not a <canvas>: ${canvas}`);
379
+            throw new IllegalArgumentError('Not a canvas: ' + canvas);
349 380
 
350 381
         // borrow the canvas; add it as a child of the viewport container
351 382
         canvas.remove();
@@ -356,7 +387,7 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
356 387
 
357 388
         canvas.dataset.cssText = canvas.style.cssText; // save CSS
358 389
         canvas.style.cssText = ''; // clear CSS
359
-        this._styleCanvas(canvas, 'foreground');
390
+        this._styleCanvas(canvas, FOREGROUND_ZINDEX);
360 391
 
361 392
         return canvas;
362 393
     }
@@ -368,19 +399,37 @@ export class BaseViewport extends AREventTarget<ViewportEventType> implements Vi
368 399
     {
369 400
         // not an imported canvas; nothing to do
370 401
         if(this._parentOfImportedForegroundCanvas == null)
371
-            return;
402
+            throw new IllegalOperationError();
372 403
 
373 404
         const canvas = this._foregroundCanvas;
374 405
         canvas.style.cssText = canvas.dataset.cssText || ''; // restore CSS
375 406
         canvas.remove();
376 407
         this._parentOfImportedForegroundCanvas.appendChild(canvas);
377 408
     }
409
+
410
+    /**
411
+     * Add suitable CSS rules to a canvas
412
+     * @param canvas
413
+     * @param canvasType
414
+     * @returns canvas
415
+     */
416
+    private _styleCanvas(canvas: HTMLCanvasElement, zIndex: number): HTMLCanvasElement
417
+    {
418
+        canvas.style.position = 'absolute';
419
+        canvas.style.left = '0px';
420
+        canvas.style.top = '0px';
421
+        canvas.style.width = '100%';
422
+        canvas.style.height = '100%';
423
+        canvas.style.zIndex = String(zIndex);
424
+
425
+        return canvas;
426
+    }
378 427
 }
379 428
 
380 429
 /**
381 430
  * Viewport decorator
382 431
  */
383
-abstract class ViewportDecorator extends AREventTarget<ViewportEventType> implements Viewport
432
+abstract class ViewportDecorator extends ViewportEventTarget implements Viewport
384 433
 {
385 434
     /** The decorated viewport */
386 435
     private _base: Viewport;
@@ -412,6 +461,22 @@ abstract class ViewportDecorator extends AREventTarget<ViewportEventType> implem
412 461
     }
413 462
 
414 463
     /**
464
+     * Viewport style
465
+     */
466
+    get style(): ViewportStyle
467
+    {
468
+        return this._base.style;
469
+    }
470
+
471
+    /**
472
+     * Set viewport style
473
+     */
474
+    set style(value: ViewportStyle)
475
+    {
476
+        this._base.style = value;
477
+    }
478
+
479
+    /**
415 480
      * HUD
416 481
      */
417 482
     get hud(): HUD
@@ -448,16 +513,16 @@ abstract class ViewportDecorator extends AREventTarget<ViewportEventType> implem
448 513
      * Background canvas
449 514
      * @internal
450 515
      */
451
-    get _background(): HTMLCanvasElement
516
+    get _backgroundCanvas(): HTMLCanvasElement
452 517
     {
453
-        return this._base._background;
518
+        return this._base._backgroundCanvas;
454 519
     }
455 520
 
456 521
     /**
457 522
      * Size of the drawing buffer of the background canvas, in pixels
458 523
      * @internal
459 524
      */
460
-    get _size(): SpeedySize
525
+    get _realSize(): SpeedySize
461 526
     {
462 527
         return this._getSize();
463 528
     }
@@ -481,15 +546,6 @@ abstract class ViewportDecorator extends AREventTarget<ViewportEventType> implem
481 546
     }
482 547
 
483 548
     /**
484
-     * Function to be called when the viewport is resized
485
-     * @internal
486
-     */
487
-    _onResize(): void
488
-    {
489
-        this._base._onResize();
490
-    }
491
-
492
-    /**
493 549
      * Add event listener
494 550
      * @param type event type
495 551
      * @param callback
@@ -529,6 +585,9 @@ abstract class ResizableViewport extends ViewportDecorator
529 585
     /** is this viewport subject to being resized? */
530 586
     private _active: boolean;
531 587
 
588
+    /** a bound _onResize */
589
+    private _resize: () => void;
590
+
532 591
 
533 592
 
534 593
     /**
@@ -536,18 +595,14 @@ abstract class ResizableViewport extends ViewportDecorator
536 595
      * @param base to be decorated
537 596
      * @param getSize size getter
538 597
      */
539
-    constructor(base: Viewport, getSize: ViewportSizeGetter)
598
+    constructor(base: BaseViewport, getSize: ViewportSizeGetter)
540 599
     {
541 600
         super(base, getSize);
542 601
         this._active = false;
602
+        this._resize = this._onResize.bind(this);
543 603
     }
544 604
 
545 605
     /**
546
-     * Resize the viewport
547
-     */
548
-    protected abstract _resize(): void;
549
-
550
-    /**
551 606
      * Initialize the viewport
552 607
      * @internal
553 608
      */
@@ -571,14 +626,20 @@ abstract class ResizableViewport extends ViewportDecorator
571 626
 
572 627
             timeout = setTimeout(() => {
573 628
                 timeout = null;
574
-                this._resize.call(this);
575
-                this._onResize.call(this);
629
+                this._resize();
576 630
             }, 100);
577 631
         };
578
-
579 632
         window.addEventListener('resize', onresize);
580
-        this._resize();
581
-        this._onResize();
633
+
634
+        // handle changes of orientation
635
+        // (is this needed? we already listen to resize events)
636
+        if(screen.orientation !== undefined)
637
+            screen.orientation.addEventListener('change', this._resize);
638
+        else
639
+            window.addEventListener('orientationchange', this._resize); // deprecated
640
+
641
+        // trigger a resize to setup the sizes / the CSS
642
+        setTimeout(this._resize, 0);
582 643
     }
583 644
 
584 645
     /**
@@ -587,9 +648,38 @@ abstract class ResizableViewport extends ViewportDecorator
587 648
      */
588 649
     _release(): void
589 650
     {
651
+        if(screen.orientation !== undefined)
652
+            screen.orientation.removeEventListener('change', this._resize);
653
+        else
654
+            window.removeEventListener('orientationchange', this._resize); // deprecated
655
+
590 656
         this._active = false;
591 657
         super._release();
592 658
     }
659
+
660
+    /**
661
+     * Function to be called when the viewport is resized
662
+     */
663
+    protected _onResize(): void
664
+    {
665
+        // Resize the drawing buffer of the foreground canvas, so that it
666
+        // matches the desired resolution, as well as the aspect ratio of the
667
+        // background canvas
668
+        const foregroundCanvas = this.canvas;
669
+        const virtualSize = this.virtualSize;
670
+        foregroundCanvas.width = virtualSize.width;
671
+        foregroundCanvas.height = virtualSize.height;
672
+
673
+        // Resize the drawing buffer of the background canvas
674
+        const backgroundCanvas = this._backgroundCanvas;
675
+        const realSize = this._realSize;
676
+        backgroundCanvas.width = realSize.width;
677
+        backgroundCanvas.height = realSize.height;
678
+
679
+        // dispatch event
680
+        const event = new ViewportEvent('resize');
681
+        this.dispatchEvent(event);
682
+    }
593 683
 }
594 684
 
595 685
 /**
@@ -598,13 +688,25 @@ abstract class ResizableViewport extends ViewportDecorator
598 688
 export class ImmersiveViewport extends ResizableViewport
599 689
 {
600 690
     /**
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
+    /**
601 703
      * Release the viewport
602 704
      * @internal
603 705
      */
604 706
     _release(): void
605 707
     {
606 708
         this.canvas.remove();
607
-        this._background.remove();
709
+        this._backgroundCanvas.remove();
608 710
         this.hud.visible = false;
609 711
         this.container.style.cssText = ''; // reset CSS
610 712
 
@@ -615,40 +717,42 @@ export class ImmersiveViewport extends ResizableViewport
615 717
      * Resize the immersive viewport, so that it occupies the entire page.
616 718
      * We respect the aspect ratio of the source media
617 719
      */
618
-    protected _resize(): void
720
+    protected _onResize(): void
619 721
     {
620
-        const { width, height } = this._size;
621
-        const viewportSize = Speedy.Size(0, 0);
622
-        const viewportAspectRatio = width / height;
623
-        const windowSize = Speedy.Size(window.innerWidth, window.innerHeight);
624
-        const windowAspectRatio = windowSize.width / windowSize.height;
625
-
626
-        // figure out the viewport size
627
-        if(viewportAspectRatio <= windowAspectRatio) {
628
-            viewportSize.height = windowSize.height;
629
-            viewportSize.width = (viewportSize.height * viewportAspectRatio) | 0;
630
-        }
631
-        else {
632
-            viewportSize.width = windowSize.width;
633
-            viewportSize.height = (viewportSize.width / viewportAspectRatio) | 0;
634
-        }
722
+        super._onResize();
635 723
 
636
-        // position the viewport and set its size
637 724
         const container = this.container;
638 725
         container.style.position = 'fixed';
639
-        container.style.left = `calc(50% - ${viewportSize.width >>> 1}px)`;
640
-        container.style.top = `calc(50% - ${viewportSize.height >>> 1}px)`;
641
-        container.style.zIndex = '1000000000'; // 1B //String(2147483647);
642
-        container.style.width = viewportSize.width + 'px';
643
-        container.style.height = viewportSize.height + 'px';
644
-        container.style.backgroundColor = '#000';
645
-
646
-        // set the size of the drawing buffer of the background canvas
647
-        const backgroundCanvas = this._background;
648
-        const backgroundCanvasAspectRatio = viewportAspectRatio;
649
-        const referenceHeight = height;
650
-        backgroundCanvas.height = referenceHeight;
651
-        backgroundCanvas.width = (backgroundCanvas.height * backgroundCanvasAspectRatio) | 0;
726
+
727
+        if(this.style == 'best-fit') {
728
+            // cover the page while maintaining the aspect ratio
729
+            let viewportWidth = 0, viewportHeight = 0;
730
+            const windowAspectRatio = window.innerWidth / window.innerHeight;
731
+            const viewportAspectRatio = this._realSize.width / this._realSize.height;
732
+
733
+            if(viewportAspectRatio <= windowAspectRatio) {
734
+                viewportHeight = window.innerHeight;
735
+                viewportWidth = (viewportHeight * viewportAspectRatio) | 0;
736
+            }
737
+            else {
738
+                viewportWidth = window.innerWidth;
739
+                viewportHeight = (viewportWidth / viewportAspectRatio) | 0;
740
+            }
741
+
742
+            container.style.left = `calc(50% - ${viewportWidth >>> 1}px)`;
743
+            container.style.top = `calc(50% - ${viewportHeight >>> 1}px)`;
744
+            container.style.width = viewportWidth + 'px';
745
+            container.style.height = viewportHeight + 'px';
746
+        }
747
+        else if(this.style == 'stretch') {
748
+            // stretch to cover the entire page
749
+            container.style.left = '0px';
750
+            container.style.top = '0px';
751
+            container.style.width = window.innerWidth + 'px';
752
+            container.style.height = window.innerHeight + 'px';
753
+        }
754
+        else
755
+            throw new IllegalOperationError('Invalid immersive viewport style: ' + this.style);
652 756
     }
653 757
 }
654 758
 
@@ -658,18 +762,46 @@ export class ImmersiveViewport extends ResizableViewport
658 762
 export class InlineViewport extends ResizableViewport
659 763
 {
660 764
     /**
765
+     * Initialize the viewport
766
+     * @internal
767
+     */
768
+    _init(): void
769
+    {
770
+        super._init();
771
+        this.style = 'inline';
772
+
773
+        this.container.style.zIndex = String(CONTAINER_ZINDEX);
774
+        this.container.style.backgroundColor = 'black';
775
+    }
776
+
777
+    /**
778
+     * Release the viewport
779
+     * @internal
780
+     */
781
+    _release(): void
782
+    {
783
+        this.container.style.cssText = ''; // reset CSS
784
+        super._release();
785
+    }
786
+
787
+    /**
661 788
      * Resize the inline viewport
789
+     * (we still take into account orientation changes)
662 790
      */
663
-    protected _resize(): void
791
+    protected _onResize(): void
664 792
     {
665
-        const { width, height } = this._size;
793
+        super._onResize();
666 794
 
667
-        this.container.style.position = 'relative';
668
-        this.container.style.width = width + 'px';
669
-        this.container.style.height = height + 'px';
670
-        //this.container.style.display = 'inline-block';
795
+        const container = this.container;
796
+        container.style.position = 'relative';
671 797
 
672
-        this._background.width = width;
673
-        this._background.height = height;
798
+        if(this.style == 'inline') {
799
+            container.style.left = '0px';
800
+            container.style.top = '0px';
801
+            container.style.width = this._realSize.width + 'px';
802
+            container.style.height = this._realSize.height + 'px';
803
+        }
804
+        else
805
+            throw new IllegalOperationError('Invalid inline viewport style: ' + this.style);
674 806
     }
675 807
 }

Loading…
Cancelar
Guardar