소스 검색

Introduce viewport styles. Improvements to the code

customisations
alemart 1 년 전
부모
커밋
883e0d7664
4개의 변경된 파일306개의 추가작업 그리고 159개의 파일을 삭제
  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 파일 보기

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.2.1
20
 
21
 
21
 **Returns**
22
 **Returns**
22
 
23
 
51
 
52
 
52
 The [resolution](resolution.md) of the virtual scene.
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
 ### canvas
61
 ### canvas
55
 
62
 
56
 `viewport.canvas: HTMLCanvasElement, read-only`
63
 `viewport.canvas: HTMLCanvasElement, read-only`
57
 
64
 
58
 A `<canvas>` on which the virtual scene is drawn.
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
 ## Events
81
 ## Events
67
 
82
 
69
 
84
 
70
 ### resize
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
 **Example**
89
 **Example**
75
 
90
 

+ 2
- 2
src/core/gizmos.ts 파일 보기

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

+ 4
- 4
src/core/session.ts 파일 보기

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

+ 281
- 149
src/core/viewport.ts 파일 보기

30
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
30
 import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
31
 
31
 
32
 
32
 
33
+
33
 /** Viewport container */
34
 /** Viewport container */
34
 export type ViewportContainer = HTMLDivElement;
35
 export type ViewportContainer = HTMLDivElement;
35
 
36
 
42
 /** An event emitted by a Viewport */
43
 /** An event emitted by a Viewport */
43
 class ViewportEvent extends AREvent<ViewportEventType> { }
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
  * Viewport interface
55
  * Viewport interface
47
  */
56
  */
48
-export interface Viewport extends AREventTarget<ViewportEventType>
57
+export interface Viewport extends ViewportEventTarget
49
 {
58
 {
50
     /** Resolution of the virtual scene */
59
     /** Resolution of the virtual scene */
51
     readonly resolution: Resolution;
60
     readonly resolution: Resolution;
53
     /** Viewport container */
62
     /** Viewport container */
54
     readonly container: ViewportContainer;
63
     readonly container: ViewportContainer;
55
 
64
 
65
+    /** Viewport style */
66
+    style: ViewportStyle;
67
+
56
     /** HUD */
68
     /** HUD */
57
     readonly hud: HUD;
69
     readonly hud: HUD;
58
 
70
 
59
-    /** Size of the drawing buffer of the foreground canvas */
60
-    readonly virtualSize: SpeedySize;
61
-
62
     /** Canvas on which the virtual scene will be drawn */
71
     /** Canvas on which the virtual scene will be drawn */
63
     readonly canvas: HTMLCanvasElement;
72
     readonly canvas: HTMLCanvasElement;
64
 
73
 
74
+    /** Size of the drawing buffer of the foreground canvas */
75
+    readonly virtualSize: SpeedySize;
76
+
65
     /** Canvas on which the physical scene will be drawn @internal */
77
     /** Canvas on which the physical scene will be drawn @internal */
66
-    readonly _background: HTMLCanvasElement;
78
+    readonly _backgroundCanvas: HTMLCanvasElement;
67
 
79
 
68
     /** Size of the drawing buffer of the background canvas @internal */
80
     /** Size of the drawing buffer of the background canvas @internal */
69
-    readonly _size: SpeedySize;
81
+    readonly _realSize: SpeedySize;
70
 
82
 
71
     /** Initialize the viewport @internal */
83
     /** Initialize the viewport @internal */
72
     _init(): void;
84
     _init(): void;
73
 
85
 
74
     /** Release the viewport @internal */
86
     /** Release the viewport @internal */
75
     _release(): void;
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
     /** Resolution of the canvas on which the virtual scene will be drawn */
101
     /** Resolution of the canvas on which the virtual scene will be drawn */
93
     resolution?: Resolution;
102
     resolution?: Resolution;
94
 
103
 
104
+    /** Viewport style */
105
+    style?: ViewportStyle;
106
+
95
     /** An existing <canvas> on which the virtual scene will be drawn */
107
     /** An existing <canvas> on which the virtual scene will be drawn */
96
     canvas?: Nullable<HTMLCanvasElement>;
108
     canvas?: Nullable<HTMLCanvasElement>;
97
 }
109
 }
101
     container: null,
113
     container: null,
102
     hudContainer: null,
114
     hudContainer: null,
103
     resolution: 'lg',
115
     resolution: 'lg',
116
+    style: 'best-fit',
104
     canvas: null,
117
     canvas: null,
105
 };
118
 };
106
 
119
 
120
+/** Z-index of the viewport container */
121
+const CONTAINER_ZINDEX = 1000000000;
122
+
107
 /** Base z-index of the children of the viewport container */
123
 /** Base z-index of the children of the viewport container */
108
 const BASE_ZINDEX = 0;
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
 /** Default viewport width, in pixels */
135
 /** Default viewport width, in pixels */
111
 const DEFAULT_VIEWPORT_WIDTH = 300;
136
 const DEFAULT_VIEWPORT_WIDTH = 300;
112
 
137
 
118
 /**
143
 /**
119
  * Viewport
144
  * Viewport
120
  */
145
  */
121
-export class BaseViewport extends AREventTarget<ViewportEventType> implements Viewport
146
+export class BaseViewport extends ViewportEventTarget implements Viewport
122
 {
147
 {
123
     /** Viewport resolution (controls the size of the drawing buffer of the foreground canvas) */
148
     /** Viewport resolution (controls the size of the drawing buffer of the foreground canvas) */
124
     private readonly _resolution: Resolution;
149
     private readonly _resolution: Resolution;
129
     /** An overlay displayed in front of the augmented scene */
154
     /** An overlay displayed in front of the augmented scene */
130
     protected readonly _hud: HUD;
155
     protected readonly _hud: HUD;
131
 
156
 
157
+    /** Viewport style */
158
+    protected _style: ViewportStyle;
159
+
132
     /** Internal canvas used to render the physical scene */
160
     /** Internal canvas used to render the physical scene */
133
-    protected readonly _backgroundCanvas: HTMLCanvasElement;
161
+    private readonly __backgroundCanvas: HTMLCanvasElement;
134
 
162
 
135
     /** A canvas used to render the virtual scene */
163
     /** A canvas used to render the virtual scene */
136
     protected readonly _foregroundCanvas: HTMLCanvasElement;
164
     protected readonly _foregroundCanvas: HTMLCanvasElement;
148
     {
176
     {
149
         super();
177
         super();
150
 
178
 
151
-        // validate settings
152
         const settings = Object.assign({}, DEFAULT_VIEWPORT_SETTINGS, viewportSettings);
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
         if(settings.container == null)
183
         if(settings.container == null)
154
             throw new IllegalArgumentError('Unspecified viewport container');
184
             throw new IllegalArgumentError('Unspecified viewport container');
185
+        else if(!(settings.container instanceof HTMLElement))
186
+            throw new IllegalArgumentError('Invalid viewport container');
155
 
187
 
156
         // initialize attributes
188
         // initialize attributes
157
         this._resolution = settings.resolution;
189
         this._resolution = settings.resolution;
158
         this._container = settings.container;
190
         this._container = settings.container;
159
         this._hud = new HUD(settings.container, settings.hudContainer);
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
     }
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
      * HUD
240
      * HUD
180
      */
241
      */
181
     get hud(): HUD
242
     get hud(): HUD
210
     }
271
     }
211
 
272
 
212
     /**
273
     /**
213
-     * Background canvas
274
+     * The canvas on which the physical scene will be drawn
214
      * @internal
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
      * Size of the drawing buffer of the background canvas, in pixels
283
      * Size of the drawing buffer of the background canvas, in pixels
223
      * @internal
284
      * @internal
224
      */
285
      */
225
-    get _size(): SpeedySize
286
+    get _realSize(): SpeedySize
226
     {
287
     {
227
         throw new IllegalOperationError();
288
         throw new IllegalOperationError();
228
     }
289
     }
233
      */
294
      */
234
     _init(): void
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
         this._container.style.touchAction = 'none';
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
         this._hud.visible = true;
308
         this._hud.visible = true;
239
     }
309
     }
240
 
310
 
244
      */
314
      */
245
     _release(): void
315
     _release(): void
246
     {
316
     {
247
-        //this._hud.visible = false; // depends on the type of the viewport
317
+        // release the HUD
248
         this._hud._release();
318
         this._hud._release();
249
-        this._restoreImportedForegroundCanvas();
319
+
320
+        // reset the CSS
250
         this._container.style.touchAction = 'auto';
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
     private _createBackgroundCanvas(parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
351
     private _createBackgroundCanvas(parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
279
     {
352
     {
280
         const canvas = this._createCanvas(parent, size);
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
     private _createForegroundCanvas(parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
363
     private _createForegroundCanvas(parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
291
     {
364
     {
292
         const canvas = this._createCanvas(parent, size);
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
     private _importForegroundCanvas(canvas: HTMLCanvasElement, parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
376
     private _importForegroundCanvas(canvas: HTMLCanvasElement, parent: ViewportContainer, size: SpeedySize): HTMLCanvasElement
346
     {
377
     {
347
         if(!(canvas instanceof HTMLCanvasElement))
378
         if(!(canvas instanceof HTMLCanvasElement))
348
-            throw new IllegalArgumentError(`Not a <canvas>: ${canvas}`);
379
+            throw new IllegalArgumentError('Not a canvas: ' + canvas);
349
 
380
 
350
         // borrow the canvas; add it as a child of the viewport container
381
         // borrow the canvas; add it as a child of the viewport container
351
         canvas.remove();
382
         canvas.remove();
356
 
387
 
357
         canvas.dataset.cssText = canvas.style.cssText; // save CSS
388
         canvas.dataset.cssText = canvas.style.cssText; // save CSS
358
         canvas.style.cssText = ''; // clear CSS
389
         canvas.style.cssText = ''; // clear CSS
359
-        this._styleCanvas(canvas, 'foreground');
390
+        this._styleCanvas(canvas, FOREGROUND_ZINDEX);
360
 
391
 
361
         return canvas;
392
         return canvas;
362
     }
393
     }
368
     {
399
     {
369
         // not an imported canvas; nothing to do
400
         // not an imported canvas; nothing to do
370
         if(this._parentOfImportedForegroundCanvas == null)
401
         if(this._parentOfImportedForegroundCanvas == null)
371
-            return;
402
+            throw new IllegalOperationError();
372
 
403
 
373
         const canvas = this._foregroundCanvas;
404
         const canvas = this._foregroundCanvas;
374
         canvas.style.cssText = canvas.dataset.cssText || ''; // restore CSS
405
         canvas.style.cssText = canvas.dataset.cssText || ''; // restore CSS
375
         canvas.remove();
406
         canvas.remove();
376
         this._parentOfImportedForegroundCanvas.appendChild(canvas);
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
  * Viewport decorator
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
     /** The decorated viewport */
434
     /** The decorated viewport */
386
     private _base: Viewport;
435
     private _base: Viewport;
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
      * HUD
480
      * HUD
416
      */
481
      */
417
     get hud(): HUD
482
     get hud(): HUD
448
      * Background canvas
513
      * Background canvas
449
      * @internal
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
      * Size of the drawing buffer of the background canvas, in pixels
522
      * Size of the drawing buffer of the background canvas, in pixels
458
      * @internal
523
      * @internal
459
      */
524
      */
460
-    get _size(): SpeedySize
525
+    get _realSize(): SpeedySize
461
     {
526
     {
462
         return this._getSize();
527
         return this._getSize();
463
     }
528
     }
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
      * Add event listener
549
      * Add event listener
494
      * @param type event type
550
      * @param type event type
495
      * @param callback
551
      * @param callback
529
     /** is this viewport subject to being resized? */
585
     /** is this viewport subject to being resized? */
530
     private _active: boolean;
586
     private _active: boolean;
531
 
587
 
588
+    /** a bound _onResize */
589
+    private _resize: () => void;
590
+
532
 
591
 
533
 
592
 
534
     /**
593
     /**
536
      * @param base to be decorated
595
      * @param base to be decorated
537
      * @param getSize size getter
596
      * @param getSize size getter
538
      */
597
      */
539
-    constructor(base: Viewport, getSize: ViewportSizeGetter)
598
+    constructor(base: BaseViewport, getSize: ViewportSizeGetter)
540
     {
599
     {
541
         super(base, getSize);
600
         super(base, getSize);
542
         this._active = false;
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
      * Initialize the viewport
606
      * Initialize the viewport
552
      * @internal
607
      * @internal
553
      */
608
      */
571
 
626
 
572
             timeout = setTimeout(() => {
627
             timeout = setTimeout(() => {
573
                 timeout = null;
628
                 timeout = null;
574
-                this._resize.call(this);
575
-                this._onResize.call(this);
629
+                this._resize();
576
             }, 100);
630
             }, 100);
577
         };
631
         };
578
-
579
         window.addEventListener('resize', onresize);
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
      */
648
      */
588
     _release(): void
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
         this._active = false;
656
         this._active = false;
591
         super._release();
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
 export class ImmersiveViewport extends ResizableViewport
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
      * Release the viewport
703
      * Release the viewport
602
      * @internal
704
      * @internal
603
      */
705
      */
604
     _release(): void
706
     _release(): void
605
     {
707
     {
606
         this.canvas.remove();
708
         this.canvas.remove();
607
-        this._background.remove();
709
+        this._backgroundCanvas.remove();
608
         this.hud.visible = false;
710
         this.hud.visible = false;
609
         this.container.style.cssText = ''; // reset CSS
711
         this.container.style.cssText = ''; // reset CSS
610
 
712
 
615
      * Resize the immersive viewport, so that it occupies the entire page.
717
      * Resize the immersive viewport, so that it occupies the entire page.
616
      * We respect the aspect ratio of the source media
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
         const container = this.container;
724
         const container = this.container;
638
         container.style.position = 'fixed';
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
 export class InlineViewport extends ResizableViewport
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
      * Resize the inline viewport
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…
취소
저장