@vpmedia/phaser 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +20 -3
  2. package/dist/phaser.cjs +1 -1
  3. package/dist/phaser.cjs.LICENSE.txt +1 -1
  4. package/dist/phaser.cjs.map +1 -1
  5. package/dist/phaser.js +1 -1
  6. package/dist/phaser.js.LICENSE.txt +1 -1
  7. package/dist/phaser.js.map +1 -1
  8. package/package.json +23 -17
  9. package/src/index.js +142 -0
  10. package/src/phaser/core/animation.js +355 -0
  11. package/src/phaser/core/animation_manager.js +238 -0
  12. package/src/phaser/core/animation_parser.js +133 -0
  13. package/src/phaser/core/array_set.js +107 -0
  14. package/src/phaser/core/cache.js +558 -0
  15. package/src/phaser/core/const.js +106 -0
  16. package/src/phaser/core/device.js +67 -0
  17. package/src/phaser/core/device_util.js +388 -0
  18. package/src/phaser/core/dom.js +207 -0
  19. package/src/phaser/core/event_manager.js +243 -0
  20. package/src/phaser/core/factory.js +74 -0
  21. package/src/phaser/core/frame.js +75 -0
  22. package/src/phaser/core/frame_data.js +84 -0
  23. package/src/phaser/core/frame_util.js +33 -0
  24. package/src/phaser/core/game.js +412 -0
  25. package/src/phaser/core/input.js +401 -0
  26. package/src/phaser/core/input_button.js +102 -0
  27. package/src/phaser/core/input_handler.js +687 -0
  28. package/src/phaser/core/input_mouse.js +289 -0
  29. package/src/phaser/core/input_mspointer.js +197 -0
  30. package/src/phaser/core/input_pointer.js +427 -0
  31. package/src/phaser/core/input_touch.js +157 -0
  32. package/src/phaser/core/loader.js +1057 -0
  33. package/src/phaser/core/loader_parser.js +109 -0
  34. package/src/phaser/core/raf.js +46 -0
  35. package/src/phaser/core/raf_fb.js +75 -0
  36. package/src/phaser/core/raf_to.js +34 -0
  37. package/src/phaser/core/scale_manager.js +806 -0
  38. package/src/phaser/core/scene.js +65 -0
  39. package/src/phaser/core/scene_manager.js +309 -0
  40. package/src/phaser/core/signal.js +175 -0
  41. package/src/phaser/core/signal_binding.js +69 -0
  42. package/src/phaser/core/sound.js +538 -0
  43. package/src/phaser/core/sound_manager.js +364 -0
  44. package/src/phaser/core/stage.js +108 -0
  45. package/src/phaser/core/time.js +203 -0
  46. package/src/phaser/core/timer.js +276 -0
  47. package/src/phaser/core/timer_event.js +21 -0
  48. package/src/phaser/core/tween.js +329 -0
  49. package/src/phaser/core/tween_data.js +258 -0
  50. package/src/phaser/core/tween_easing.js +341 -0
  51. package/src/phaser/core/tween_manager.js +185 -0
  52. package/src/phaser/core/world.js +18 -0
  53. package/src/phaser/display/bitmap_text.js +322 -0
  54. package/src/phaser/display/button.js +194 -0
  55. package/src/phaser/display/canvas/buffer.js +36 -0
  56. package/src/phaser/display/canvas/graphics.js +227 -0
  57. package/src/phaser/display/canvas/masker.js +39 -0
  58. package/src/phaser/display/canvas/pool.js +126 -0
  59. package/src/phaser/display/canvas/renderer.js +123 -0
  60. package/src/phaser/display/canvas/tinter.js +144 -0
  61. package/src/phaser/display/canvas/util.js +159 -0
  62. package/src/phaser/display/display_object.js +597 -0
  63. package/src/phaser/display/graphics.js +723 -0
  64. package/src/phaser/display/graphics_data.js +27 -0
  65. package/src/phaser/display/graphics_data_util.js +15 -0
  66. package/src/phaser/display/group.js +227 -0
  67. package/src/phaser/display/image.js +288 -0
  68. package/src/phaser/display/sprite_batch.js +15 -0
  69. package/src/phaser/display/sprite_util.js +250 -0
  70. package/src/phaser/display/text.js +1089 -0
  71. package/src/phaser/display/webgl/abstract_filter.js +25 -0
  72. package/src/phaser/display/webgl/base_texture.js +68 -0
  73. package/src/phaser/display/webgl/blend_manager.js +35 -0
  74. package/src/phaser/display/webgl/earcut.js +662 -0
  75. package/src/phaser/display/webgl/earcut_node.js +28 -0
  76. package/src/phaser/display/webgl/fast_sprite_batch.js +242 -0
  77. package/src/phaser/display/webgl/filter_manager.js +46 -0
  78. package/src/phaser/display/webgl/filter_texture.js +61 -0
  79. package/src/phaser/display/webgl/graphics.js +624 -0
  80. package/src/phaser/display/webgl/graphics_data.js +42 -0
  81. package/src/phaser/display/webgl/mask_manager.js +36 -0
  82. package/src/phaser/display/webgl/render_texture.js +81 -0
  83. package/src/phaser/display/webgl/renderer.js +234 -0
  84. package/src/phaser/display/webgl/shader/complex.js +74 -0
  85. package/src/phaser/display/webgl/shader/fast.js +97 -0
  86. package/src/phaser/display/webgl/shader/normal.js +225 -0
  87. package/src/phaser/display/webgl/shader/primitive.js +72 -0
  88. package/src/phaser/display/webgl/shader/strip.js +77 -0
  89. package/src/phaser/display/webgl/shader_manager.js +89 -0
  90. package/src/phaser/display/webgl/sprite_batch.js +320 -0
  91. package/src/phaser/display/webgl/stencil_manager.js +170 -0
  92. package/src/phaser/display/webgl/texture.js +117 -0
  93. package/src/phaser/display/webgl/texture_util.js +34 -0
  94. package/src/phaser/display/webgl/util.js +78 -0
  95. package/src/phaser/geom/circle.js +186 -0
  96. package/src/phaser/geom/ellipse.js +65 -0
  97. package/src/phaser/geom/line.js +190 -0
  98. package/src/phaser/geom/matrix.js +147 -0
  99. package/src/phaser/geom/point.js +164 -0
  100. package/src/phaser/geom/polygon.js +140 -0
  101. package/src/phaser/geom/rectangle.js +306 -0
  102. package/src/phaser/geom/rounded_rectangle.js +36 -0
  103. package/src/phaser/geom/util/circle.js +122 -0
  104. package/src/phaser/geom/util/ellipse.js +34 -0
  105. package/src/phaser/geom/util/line.js +135 -0
  106. package/src/phaser/geom/util/matrix.js +53 -0
  107. package/src/phaser/geom/util/point.js +296 -0
  108. package/src/phaser/geom/util/polygon.js +28 -0
  109. package/src/phaser/geom/util/rectangle.js +229 -0
  110. package/src/phaser/geom/util/rounded_rectangle.js +32 -0
  111. package/src/phaser/util/math.js +297 -0
  112. package/src/phaser/util/string.js +32 -0
@@ -0,0 +1,806 @@
1
+ /**
2
+ * @author Andras Csizmadia <andras@vpmedia.hu>
3
+ * @author Richard Davey <rich@photonstorm.com>
4
+ * @copyright Copyright (c) 2018-present Richard Davey, Photon Storm Ltd., Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
5
+ */
6
+ import Signal from './signal';
7
+ import DOM from './dom';
8
+ import Point from '../geom/point';
9
+ import Rectangle from '../geom/rectangle';
10
+ import { SCALE_OFF, SCALE_RESIZE, SCALE_EXACT_FIT, SCALE_USER, SCALE_SHOW_ALL, RENDER_CANVAS } from './const';
11
+
12
+ export default class {
13
+
14
+ constructor(game, width, height) {
15
+ this.game = game;
16
+ this.dom = new DOM(game.device);
17
+ this.width = 0;
18
+ this.height = 0;
19
+ this.minWidth = null;
20
+ this.maxWidth = null;
21
+ this.minHeight = null;
22
+ this.maxHeight = null;
23
+ this.offset = new Point();
24
+ this.forceLandscape = false;
25
+ this.forcePortrait = false;
26
+ this.incorrectOrientation = false;
27
+ this._pageAlignHorizontally = false;
28
+ this._pageAlignVertically = false;
29
+ this.onOrientationChange = new Signal();
30
+ this.enterIncorrectOrientation = new Signal();
31
+ this.leaveIncorrectOrientation = new Signal();
32
+ this.hasPhaserSetFullScreen = false;
33
+ this.fullScreenTarget = null;
34
+ this._createdFullScreenTarget = null;
35
+ this.onFullScreenInit = new Signal();
36
+ this.onFullScreenChange = new Signal();
37
+ this.onFullScreenError = new Signal();
38
+ this.screenOrientation = this.dom.getScreenOrientation();
39
+ this.scaleFactor = new Point(1, 1);
40
+ this.scaleFactorInversed = new Point(1, 1);
41
+ this.margin = {
42
+ left: 0,
43
+ top: 0,
44
+ right: 0,
45
+ bottom: 0,
46
+ x: 0,
47
+ y: 0,
48
+ };
49
+ this.bounds = new Rectangle();
50
+ this.aspectRatio = 0;
51
+ this.sourceAspectRatio = 0;
52
+ this.event = null;
53
+ this.windowConstraints = {
54
+ right: 'layout',
55
+ bottom: '',
56
+ };
57
+ this.compatibility = {
58
+ supportsFullScreen: false,
59
+ orientationFallback: null,
60
+ noMargins: false,
61
+ scrollTo: null,
62
+ forceMinimumDocumentHeight: false,
63
+ canExpandParent: true,
64
+ clickTrampoline: '',
65
+ };
66
+ this._scaleMode = SCALE_OFF;
67
+ this._fullScreenScaleMode = SCALE_OFF;
68
+ this.parentIsWindow = false;
69
+ this.parentNode = null;
70
+ this.parentScaleFactor = new Point(1, 1);
71
+ this.trackParentInterval = 2000;
72
+ this.onSizeChange = new Signal();
73
+ this.onResize = null;
74
+ this.onResizeContext = null;
75
+ this._pendingScaleMode = null;
76
+ this._fullScreenRestore = null;
77
+ this._gameSize = new Rectangle();
78
+ this._userScaleFactor = new Point(1, 1);
79
+ this._userScaleTrim = new Point(0, 0);
80
+ this._lastUpdate = 0;
81
+ this._updateThrottle = 0;
82
+ this._updateThrottleReset = 100;
83
+ this._parentBounds = new Rectangle();
84
+ this._tempBounds = new Rectangle();
85
+ this._lastReportedCanvasSize = new Rectangle();
86
+ this._lastReportedGameSize = new Rectangle();
87
+ this._booted = false;
88
+ if (game.config) {
89
+ this.parseConfig(game.config);
90
+ }
91
+ this.setupScale(width, height);
92
+ }
93
+
94
+ boot() {
95
+ // Configure device-dependent compatibility
96
+ const compat = this.compatibility;
97
+ compat.supportsFullScreen = this.game.device.fullscreen && !this.game.device.cocoonJS;
98
+ // We can't do anything about the status bars in iPads, web apps or desktops
99
+ /*
100
+ if (!this.game.device.iPad && !this.game.device.webApp && !this.game.device.desktop) {
101
+ if (this.game.device.android && !this.game.device.chrome) {
102
+ compat.scrollTo = new Point(0, 1);
103
+ } else {
104
+ compat.scrollTo = new Point(0, 0);
105
+ }
106
+ }
107
+ */
108
+ if (this.game.device.desktop) {
109
+ compat.orientationFallback = 'screen';
110
+ compat.clickTrampoline = 'when-not-mouse';
111
+ } else {
112
+ compat.orientationFallback = '';
113
+ compat.clickTrampoline = '';
114
+ }
115
+ // Configure event listeners
116
+ const scope = this;
117
+ this._orientationChange = event => scope.orientationChange(event);
118
+ this._windowResize = event => scope.windowResize(event);
119
+ // This does not appear to be on the standards track
120
+ window.addEventListener('orientationchange', this._orientationChange, false);
121
+ window.addEventListener('resize', this._windowResize, false);
122
+ if (this.compatibility.supportsFullScreen) {
123
+ this._fullScreenChange = event => scope.fullScreenChange(event);
124
+ this._fullScreenError = event => scope.fullScreenError(event);
125
+ document.addEventListener('webkitfullscreenchange', this._fullScreenChange, false);
126
+ document.addEventListener('mozfullscreenchange', this._fullScreenChange, false);
127
+ document.addEventListener('MSFullscreenChange', this._fullScreenChange, false);
128
+ document.addEventListener('fullscreenchange', this._fullScreenChange, false);
129
+ document.addEventListener('webkitfullscreenerror', this._fullScreenError, false);
130
+ document.addEventListener('mozfullscreenerror', this._fullScreenError, false);
131
+ document.addEventListener('MSFullscreenError', this._fullScreenError, false);
132
+ document.addEventListener('fullscreenerror', this._fullScreenError, false);
133
+ }
134
+ this.game.onResume.add(this._gameResumed, this);
135
+ // Initialize core bounds
136
+ this.dom.getOffset(this.game.canvas, this.offset);
137
+ this.bounds.setTo(this.offset.x, this.offset.y, this.width, this.height);
138
+ this.setGameSize(this.game.width, this.game.height);
139
+ // Don't use updateOrientationState so events are not fired
140
+ this.screenOrientation = this.dom.getScreenOrientation(this.compatibility.orientationFallback);
141
+ this._booted = true;
142
+ if (this._pendingScaleMode !== null) {
143
+ this.scaleMode = this._pendingScaleMode;
144
+ this._pendingScaleMode = null;
145
+ }
146
+ }
147
+
148
+ parseConfig(config) {
149
+ if (config.scaleMode !== undefined) {
150
+ if (this._booted) {
151
+ this.scaleMode = config.scaleMode;
152
+ } else {
153
+ this._pendingScaleMode = config.scaleMode;
154
+ }
155
+ }
156
+ if (config.fullScreenScaleMode !== undefined) {
157
+ this.fullScreenScaleMode = config.fullScreenScaleMode;
158
+ }
159
+ if (config.fullScreenTarget) {
160
+ this.fullScreenTarget = config.fullScreenTarget;
161
+ } else {
162
+ this.fullScreenTarget = document.documentElement;
163
+ }
164
+ }
165
+
166
+ setupScale(width, height) {
167
+ let target;
168
+ const rect = new Rectangle();
169
+ if (this.game.parent !== '') {
170
+ if (typeof this.game.parent === 'string') {
171
+ // hopefully an element ID
172
+ target = document.getElementById(this.game.parent);
173
+ } else if (this.game.parent && this.game.parent.nodeType === 1) {
174
+ // quick test for a HTMLelement
175
+ target = this.game.parent;
176
+ }
177
+ }
178
+ // Fallback, covers an invalid ID and a non HTMLelement object
179
+ if (!target) {
180
+ // Use the full window
181
+ this.parentNode = null;
182
+ this.parentIsWindow = true;
183
+ rect.width = this.dom.visualBounds.width;
184
+ rect.height = this.dom.visualBounds.height;
185
+ this.offset.set(0, 0);
186
+ } else {
187
+ this.parentNode = target;
188
+ this.parentIsWindow = false;
189
+ this.getParentBounds(this._parentBounds);
190
+ rect.width = this._parentBounds.width;
191
+ rect.height = this._parentBounds.height;
192
+ this.offset.set(this._parentBounds.x, this._parentBounds.y);
193
+ }
194
+ let newWidth = 0;
195
+ let newHeight = 0;
196
+ if (typeof width === 'number') {
197
+ newWidth = width;
198
+ } else {
199
+ // Percentage based
200
+ this.parentScaleFactor.x = parseInt(width, 10) / 100;
201
+ newWidth = rect.width * this.parentScaleFactor.x;
202
+ }
203
+ if (typeof height === 'number') {
204
+ newHeight = height;
205
+ } else {
206
+ // Percentage based
207
+ this.parentScaleFactor.y = parseInt(height, 10) / 100;
208
+ newHeight = rect.height * this.parentScaleFactor.y;
209
+ }
210
+ newWidth = Math.floor(newWidth);
211
+ newHeight = Math.floor(newHeight);
212
+ this._gameSize.setTo(0, 0, newWidth, newHeight);
213
+ this.updateDimensions(newWidth, newHeight, false);
214
+ }
215
+
216
+ _gameResumed() {
217
+ this.queueUpdate(true);
218
+ }
219
+
220
+ setGameSize(width, height) {
221
+ this._gameSize.setTo(0, 0, width, height);
222
+ if (this.currentScaleMode !== SCALE_RESIZE) {
223
+ this.updateDimensions(width, height, true);
224
+ }
225
+ this.queueUpdate(true);
226
+ }
227
+
228
+ setUserScale(hScale, vScale, hTrim, vTrim) {
229
+ this._userScaleFactor.setTo(hScale, vScale);
230
+ this._userScaleTrim.setTo(hTrim | 0, vTrim | 0);
231
+ this.queueUpdate(true);
232
+ }
233
+
234
+ setResizeCallback(callback, context) {
235
+ this.onResize = callback;
236
+ this.onResizeContext = context;
237
+ }
238
+
239
+ signalSizeChange() {
240
+ if (this.width !== this._lastReportedCanvasSize.width || this.height !== this._lastReportedCanvasSize.height || this.game.width !== this._lastReportedGameSize.width || this.game.height !== this._lastReportedGameSize.height) {
241
+ const width = this.width;
242
+ const height = this.height;
243
+ this._lastReportedCanvasSize.setTo(0, 0, width, height);
244
+ this._lastReportedGameSize.setTo(0, 0, this.game.width, this.game.height);
245
+ this.onSizeChange.dispatch(this, width, height);
246
+ // Per StateManager#onResizeCallback, it only occurs when in RESIZE mode.
247
+ if (this.currentScaleMode === SCALE_RESIZE) {
248
+ this.game.state.resize(width, height);
249
+ this.game.load.resize(width, height);
250
+ }
251
+ }
252
+ }
253
+
254
+ setMinMax(minWidth, minHeight, maxWidth, maxHeight) {
255
+ this.minWidth = minWidth;
256
+ this.minHeight = minHeight;
257
+ if (typeof maxWidth !== 'undefined') {
258
+ this.maxWidth = maxWidth;
259
+ }
260
+ if (typeof maxHeight !== 'undefined') {
261
+ this.maxHeight = maxHeight;
262
+ }
263
+ }
264
+
265
+ preUpdate() {
266
+ if (this.game.time.time < (this._lastUpdate + this._updateThrottle)) {
267
+ return;
268
+ }
269
+ const prevThrottle = this._updateThrottle;
270
+ this._updateThrottleReset = prevThrottle >= 400 ? 0 : 100;
271
+ this.dom.getOffset(this.game.canvas, this.offset);
272
+ const prevWidth = this._parentBounds.width;
273
+ const prevHeight = this._parentBounds.height;
274
+ const bounds = this.getParentBounds(this._parentBounds);
275
+ const boundsChanged = bounds.width !== prevWidth || bounds.height !== prevHeight;
276
+ // Always invalidate on a newly detected orientation change
277
+ const orientationChanged = this.updateOrientationState();
278
+ if (boundsChanged || orientationChanged) {
279
+ if (this.onResize) {
280
+ this.onResize.call(this.onResizeContext, this, bounds);
281
+ }
282
+ this.updateLayout();
283
+ this.signalSizeChange();
284
+ }
285
+ // Next throttle, eg. 25, 50, 100, 200..
286
+ let throttle = this._updateThrottle * 2;
287
+ // Don't let an update be too eager about resetting the throttle.
288
+ if (this._updateThrottle < prevThrottle) {
289
+ throttle = Math.min(prevThrottle, this._updateThrottleReset);
290
+ }
291
+ this._updateThrottle = Math.max(25, Math.min(this.trackParentInterval, throttle));
292
+ this._lastUpdate = this.game.time.time;
293
+ }
294
+
295
+ pauseUpdate() {
296
+ this.preUpdate();
297
+ // Updates at slowest.
298
+ this._updateThrottle = this.trackParentInterval;
299
+ }
300
+
301
+ updateDimensions(width, height, resize) {
302
+ this.width = width * this.parentScaleFactor.x;
303
+ this.height = height * this.parentScaleFactor.y;
304
+ this.game.width = this.width;
305
+ this.game.height = this.height;
306
+ this.sourceAspectRatio = this.width / this.height;
307
+ this.updateScalingAndBounds();
308
+ if (resize) {
309
+ // Resize the renderer (which in turn resizes the Display canvas!)
310
+ this.game.renderer.resize(this.width, this.height);
311
+ }
312
+ }
313
+
314
+ updateScalingAndBounds() {
315
+ this.scaleFactor.x = this.game.width / this.width;
316
+ this.scaleFactor.y = this.game.height / this.height;
317
+ this.scaleFactorInversed.x = this.width / this.game.width;
318
+ this.scaleFactorInversed.y = this.height / this.game.height;
319
+ this.aspectRatio = this.width / this.height;
320
+ // This can be invoked in boot pre-canvas
321
+ if (this.game.canvas) {
322
+ this.dom.getOffset(this.game.canvas, this.offset);
323
+ }
324
+ this.bounds.setTo(this.offset.x, this.offset.y, this.width, this.height);
325
+ // Can be invoked in boot pre-input
326
+ if (this.game.input && this.game.input.scale) {
327
+ this.game.input.scale.setTo(this.scaleFactor.x, this.scaleFactor.y);
328
+ }
329
+ }
330
+
331
+ forceOrientation(forceLandscape = false, forcePortrait = false) {
332
+ this.forceLandscape = forceLandscape;
333
+ this.forcePortrait = forcePortrait;
334
+ this.queueUpdate(true);
335
+ }
336
+
337
+ classifyOrientation(orientation) {
338
+ if (orientation === 'portrait-primary' || orientation === 'portrait-secondary') {
339
+ return 'portrait';
340
+ } else if (orientation === 'landscape-primary' || orientation === 'landscape-secondary') {
341
+ return 'landscape';
342
+ }
343
+ return null;
344
+ }
345
+
346
+ updateOrientationState() {
347
+ const previousOrientation = this.screenOrientation;
348
+ const previouslyIncorrect = this.incorrectOrientation;
349
+ this.screenOrientation = this.dom.getScreenOrientation(this.compatibility.orientationFallback);
350
+ this.incorrectOrientation = (this.forceLandscape && !this.isLandscape) || (this.forcePortrait && !this.isPortrait);
351
+ const changed = previousOrientation !== this.screenOrientation;
352
+ const correctnessChanged = previouslyIncorrect !== this.incorrectOrientation;
353
+ if (correctnessChanged) {
354
+ if (this.incorrectOrientation) {
355
+ this.enterIncorrectOrientation.dispatch();
356
+ } else {
357
+ this.leaveIncorrectOrientation.dispatch();
358
+ }
359
+ }
360
+ if (changed || correctnessChanged) {
361
+ this.onOrientationChange.dispatch(this, previousOrientation, previouslyIncorrect);
362
+ }
363
+ return changed || correctnessChanged;
364
+ }
365
+
366
+ orientationChange(event) {
367
+ this.event = event;
368
+ this.queueUpdate(true);
369
+ }
370
+
371
+ windowResize(event) {
372
+ this.event = event;
373
+ this.queueUpdate(true);
374
+ }
375
+
376
+ scrollTop() {
377
+ const scrollTo = this.compatibility.scrollTo;
378
+ if (scrollTo) {
379
+ window.scrollTo(scrollTo.x, scrollTo.y);
380
+ }
381
+ }
382
+
383
+ refresh() {
384
+ this.scrollTop();
385
+ this.queueUpdate(true);
386
+ }
387
+
388
+ updateLayout() {
389
+ const scaleMode = this.currentScaleMode;
390
+ if (scaleMode === SCALE_RESIZE) {
391
+ this.reflowGame();
392
+ return;
393
+ }
394
+ this.scrollTop();
395
+ if (this.compatibility.forceMinimumDocumentHeight) {
396
+ // (This came from older code, by why is it here?)
397
+ // Set minimum height of content to new window height
398
+ document.documentElement.style.minHeight = window.innerHeight + 'px';
399
+ }
400
+ if (this.incorrectOrientation) {
401
+ this.setMaximum();
402
+ } else if (scaleMode === SCALE_EXACT_FIT) {
403
+ this.setExactFit();
404
+ } else if (scaleMode === SCALE_SHOW_ALL) {
405
+ if (!this.isFullScreen && this.boundingParent && this.compatibility.canExpandParent) {
406
+ // Try to expand parent out, but choosing maximizing dimensions.
407
+ // Then select minimize dimensions which should then honor parent
408
+ // maximum bound applications.
409
+ this.setShowAll(true);
410
+ this.resetCanvas();
411
+ this.setShowAll();
412
+ } else {
413
+ this.setShowAll();
414
+ }
415
+ } else if (scaleMode === SCALE_OFF) {
416
+ this.width = this.game.width;
417
+ this.height = this.game.height;
418
+ } else if (scaleMode === SCALE_USER) {
419
+ this.width = (this.game.width * this._userScaleFactor.x) - this._userScaleTrim.x;
420
+ this.height = (this.game.height * this._userScaleFactor.y) - this._userScaleTrim.y;
421
+ }
422
+ if (!this.compatibility.canExpandParent && (scaleMode === SCALE_SHOW_ALL || scaleMode === SCALE_USER)) {
423
+ const bounds = this.getParentBounds(this._tempBounds);
424
+ this.width = Math.min(this.width, bounds.width);
425
+ this.height = Math.min(this.height, bounds.height);
426
+ }
427
+ // Always truncate / force to integer
428
+ this.width = this.width | 0;
429
+ this.height = this.height | 0;
430
+ this.reflowCanvas();
431
+ }
432
+
433
+ getParentBounds(target) {
434
+ const bounds = target || new Rectangle();
435
+ const parentNode = this.boundingParent;
436
+ const visualBounds = this.dom.visualBounds;
437
+ const layoutBounds = this.dom.layoutBounds;
438
+ if (!parentNode) {
439
+ bounds.setTo(0, 0, visualBounds.width, visualBounds.height);
440
+ } else {
441
+ // Ref. http://msdn.microsoft.com/en-us/library/hh781509(v=vs.85).aspx for getBoundingClientRect
442
+ const clientRect = parentNode.getBoundingClientRect();
443
+ const parentRect = (parentNode.offsetParent) ? parentNode.offsetParent.getBoundingClientRect() : parentNode.getBoundingClientRect();
444
+ bounds.setTo(clientRect.left - parentRect.left, clientRect.top - parentRect.top, clientRect.width, clientRect.height);
445
+ const wc = this.windowConstraints;
446
+ if (wc.right) {
447
+ const windowBounds = wc.right === 'layout' ? layoutBounds : visualBounds;
448
+ bounds.right = Math.min(bounds.right, windowBounds.width);
449
+ }
450
+ if (wc.bottom) {
451
+ const windowBounds = wc.bottom === 'layout' ? layoutBounds : visualBounds;
452
+ bounds.bottom = Math.min(bounds.bottom, windowBounds.height);
453
+ }
454
+ }
455
+ bounds.setTo(Math.round(bounds.x), Math.round(bounds.y), Math.round(bounds.width), Math.round(bounds.height));
456
+ return bounds;
457
+ }
458
+
459
+ alignCanvas(horizontal, vertical) {
460
+ const parentBounds = this.getParentBounds(this._tempBounds);
461
+ const canvas = this.game.canvas;
462
+ const margin = this.margin;
463
+ if (horizontal) {
464
+ margin.left = 0;
465
+ margin.right = 0;
466
+ const canvasBounds = canvas.getBoundingClientRect();
467
+ if (this.width < parentBounds.width && !this.incorrectOrientation) {
468
+ const currentEdge = canvasBounds.left - parentBounds.x;
469
+ let targetEdge = (parentBounds.width / 2) - (this.width / 2);
470
+ targetEdge = Math.max(targetEdge, 0);
471
+ const offset = targetEdge - currentEdge;
472
+ margin.left = Math.round(offset);
473
+ }
474
+ canvas.style.marginLeft = margin.left + 'px';
475
+ if (margin.left !== 0) {
476
+ margin.right = -(parentBounds.width - canvasBounds.width - margin.left);
477
+ canvas.style.marginRight = margin.right + 'px';
478
+ }
479
+ }
480
+ if (vertical) {
481
+ margin.top = 0;
482
+ margin.bottom = 0;
483
+ const canvasBounds = canvas.getBoundingClientRect();
484
+ if (this.height < parentBounds.height && !this.incorrectOrientation) {
485
+ const currentEdge = canvasBounds.top - parentBounds.y;
486
+ let targetEdge = (parentBounds.height / 2) - (this.height / 2);
487
+ targetEdge = Math.max(targetEdge, 0);
488
+ const offset = targetEdge - currentEdge;
489
+ margin.top = Math.round(offset);
490
+ }
491
+ canvas.style.marginTop = margin.top + 'px';
492
+ if (margin.top !== 0) {
493
+ margin.bottom = -(parentBounds.height - canvasBounds.height - margin.top);
494
+ canvas.style.marginBottom = margin.bottom + 'px';
495
+ }
496
+ }
497
+ // Silly backwards compatibility..
498
+ margin.x = margin.left;
499
+ margin.y = margin.top;
500
+ }
501
+
502
+ reflowGame() {
503
+ this.resetCanvas('', '');
504
+ const bounds = this.getParentBounds(this._tempBounds);
505
+ this.updateDimensions(bounds.width, bounds.height, true);
506
+ }
507
+
508
+ reflowCanvas() {
509
+ if (!this.incorrectOrientation) {
510
+ this.width = Math.max(this.minWidth || 0, Math.min(this.maxWidth || this.width, this.width));
511
+ this.height = Math.max(this.minHeight || 0, Math.min(this.maxHeight || this.height, this.height));
512
+ }
513
+ this.resetCanvas();
514
+ if (!this.compatibility.noMargins) {
515
+ if (this.isFullScreen && this._createdFullScreenTarget) {
516
+ this.alignCanvas(true, true);
517
+ } else {
518
+ this.alignCanvas(this.pageAlignHorizontally, this.pageAlignVertically);
519
+ }
520
+ }
521
+ this.updateScalingAndBounds();
522
+ }
523
+
524
+ resetCanvas(cssWidth = this.width + 'px', cssHeight = this.height + 'px') {
525
+ const canvas = this.game.canvas;
526
+ if (!this.compatibility.noMargins) {
527
+ canvas.style.marginLeft = '';
528
+ canvas.style.marginTop = '';
529
+ canvas.style.marginRight = '';
530
+ canvas.style.marginBottom = '';
531
+ }
532
+ canvas.style.width = cssWidth;
533
+ canvas.style.height = cssHeight;
534
+ }
535
+
536
+ queueUpdate(force) {
537
+ if (force) {
538
+ this._parentBounds.width = 0;
539
+ this._parentBounds.height = 0;
540
+ }
541
+ this._updateThrottle = this._updateThrottleReset;
542
+ }
543
+
544
+ reset() {
545
+ // pass
546
+ }
547
+
548
+ setMaximum() {
549
+ this.width = this.dom.visualBounds.width;
550
+ this.height = this.dom.visualBounds.height;
551
+ }
552
+
553
+ setShowAll(expanding = false) {
554
+ const bounds = this.getParentBounds(this._tempBounds);
555
+ const width = bounds.width;
556
+ const height = bounds.height;
557
+ let multiplier;
558
+ if (expanding) {
559
+ multiplier = Math.max((height / this.game.height), (width / this.game.width));
560
+ } else {
561
+ multiplier = Math.min((height / this.game.height), (width / this.game.width));
562
+ }
563
+ this.width = Math.round(this.game.width * multiplier);
564
+ this.height = Math.round(this.game.height * multiplier);
565
+ }
566
+
567
+ setExactFit() {
568
+ const bounds = this.getParentBounds(this._tempBounds);
569
+ this.width = bounds.width;
570
+ this.height = bounds.height;
571
+ if (this.isFullScreen) {
572
+ // Max/min not honored fullscreen
573
+ return;
574
+ }
575
+ if (this.maxWidth) {
576
+ this.width = Math.min(this.width, this.maxWidth);
577
+ }
578
+ if (this.maxHeight) {
579
+ this.height = Math.min(this.height, this.maxHeight);
580
+ }
581
+ }
582
+
583
+ createFullScreenTarget() {
584
+ const fsTarget = document.createElement('div');
585
+ fsTarget.style.margin = '0';
586
+ fsTarget.style.padding = '0';
587
+ fsTarget.style.background = '#000';
588
+ return fsTarget;
589
+ }
590
+
591
+ startFullScreen(antialias, allowTrampoline) {
592
+ if (this.isFullScreen) {
593
+ return false;
594
+ }
595
+ if (!this.compatibility.supportsFullScreen) {
596
+ // Error is called in timeout to emulate the real fullscreenerror event better
597
+ const scope = this;
598
+ setTimeout(() => {
599
+ scope.fullScreenError();
600
+ }, 10);
601
+ return false;
602
+ }
603
+ if (this.compatibility.clickTrampoline === 'when-not-mouse') {
604
+ const input = this.game.input;
605
+ if (input.activePointer && input.activePointer !== input.mousePointer && (allowTrampoline || allowTrampoline !== false)) {
606
+ input.activePointer.addClickTrampoline('startFullScreen', this.startFullScreen, this, [antialias, false]);
607
+ return false;
608
+ }
609
+ }
610
+ if (antialias !== undefined && this.game.renderer.type === RENDER_CANVAS) {
611
+ this.game.stage.smoothed = antialias;
612
+ }
613
+ let fsTarget = this.fullScreenTarget;
614
+ if (!fsTarget) {
615
+ this.cleanupCreatedTarget();
616
+ this._createdFullScreenTarget = this.createFullScreenTarget();
617
+ fsTarget = this._createdFullScreenTarget;
618
+ }
619
+ this.hasPhaserSetFullScreen = true;
620
+ this.onFullScreenInit.dispatch(this, { targetElement: fsTarget });
621
+ if (this._createdFullScreenTarget) {
622
+ // Move the Display canvas inside of the target and add the target to the DOM
623
+ // (The target has to be added for the Fullscreen API to work.)
624
+ const canvas = this.game.canvas;
625
+ const parent = canvas.parentNode;
626
+ parent.insertBefore(fsTarget, canvas);
627
+ fsTarget.appendChild(canvas);
628
+ }
629
+ if (this.game.device.fullscreenKeyboard) {
630
+ fsTarget[this.game.device.requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
631
+ } else {
632
+ fsTarget[this.game.device.requestFullscreen]();
633
+ }
634
+ return true;
635
+ }
636
+
637
+ stopFullScreen() {
638
+ if (!this.isFullScreen || !this.compatibility.supportsFullScreen) {
639
+ return false;
640
+ }
641
+ this.hasPhaserSetFullScreen = false;
642
+ document[this.game.device.cancelFullscreen]();
643
+ return true;
644
+ }
645
+
646
+ cleanupCreatedTarget() {
647
+ const fsTarget = this._createdFullScreenTarget;
648
+ if (fsTarget && fsTarget.parentNode) {
649
+ // Make sure to cleanup synthetic target for sure;
650
+ // swap the canvas back to the parent.
651
+ const parent = fsTarget.parentNode;
652
+ parent.insertBefore(this.game.canvas, fsTarget);
653
+ parent.removeChild(fsTarget);
654
+ }
655
+ this._createdFullScreenTarget = null;
656
+ }
657
+
658
+ prepScreenMode(enteringFullscreen) {
659
+ const fsTarget = this._createdFullScreenTarget || this.fullScreenTarget;
660
+ if (!fsTarget) {
661
+ return;
662
+ }
663
+ if (enteringFullscreen) {
664
+ if (this._createdFullScreenTarget || this.fullScreenScaleMode === SCALE_EXACT_FIT) {
665
+ // Resize target, as long as it's not the canvas
666
+ if (fsTarget !== this.game.canvas) {
667
+ this._fullScreenRestore = {
668
+ targetWidth: fsTarget.style.width,
669
+ targetHeight: fsTarget.style.height,
670
+ };
671
+ fsTarget.style.width = '100%';
672
+ fsTarget.style.height = '100%';
673
+ }
674
+ }
675
+ } else {
676
+ // Have restore information
677
+ if (this._fullScreenRestore) {
678
+ fsTarget.style.width = this._fullScreenRestore.targetWidth;
679
+ fsTarget.style.height = this._fullScreenRestore.targetHeight;
680
+ this._fullScreenRestore = null;
681
+ }
682
+ // Always reset to game size
683
+ this.updateDimensions(this._gameSize.width, this._gameSize.height, true);
684
+ this.resetCanvas();
685
+ }
686
+ }
687
+
688
+ fullScreenChange(event) {
689
+ this.event = event;
690
+ if (this.isFullScreen) {
691
+ this.prepScreenMode(true);
692
+ this.updateLayout();
693
+ this.queueUpdate(true);
694
+ } else {
695
+ this.prepScreenMode(false);
696
+ this.cleanupCreatedTarget();
697
+ this.updateLayout();
698
+ this.queueUpdate(true);
699
+ }
700
+ this.onFullScreenChange.dispatch(this, this.width, this.height);
701
+ }
702
+
703
+ fullScreenError(event) {
704
+ this.event = event;
705
+ this.cleanupCreatedTarget();
706
+ this.onFullScreenError.dispatch(this);
707
+ }
708
+
709
+ scaleSprite(sprite, width, height, letterBox) {
710
+ // TODO
711
+ console.warn('scale_manager.scaleSprite() is not implemented');
712
+ return sprite;
713
+ }
714
+
715
+ destroy() {
716
+ this.game.onResume.remove(this._gameResumed, this);
717
+ window.removeEventListener('orientationchange', this._orientationChange, false);
718
+ window.removeEventListener('resize', this._windowResize, false);
719
+ if (this.compatibility.supportsFullScreen) {
720
+ document.removeEventListener('webkitfullscreenchange', this._fullScreenChange, false);
721
+ document.removeEventListener('mozfullscreenchange', this._fullScreenChange, false);
722
+ document.removeEventListener('MSFullscreenChange', this._fullScreenChange, false);
723
+ document.removeEventListener('fullscreenchange', this._fullScreenChange, false);
724
+
725
+ document.removeEventListener('webkitfullscreenerror', this._fullScreenError, false);
726
+ document.removeEventListener('mozfullscreenerror', this._fullScreenError, false);
727
+ document.removeEventListener('MSFullscreenError', this._fullScreenError, false);
728
+ document.removeEventListener('fullscreenerror', this._fullScreenError, false);
729
+ }
730
+ }
731
+
732
+ get boundingParent() {
733
+ if (this.parentIsWindow || (this.isFullScreen && this.hasPhaserSetFullScreen && !this._createdFullScreenTarget)) {
734
+ return null;
735
+ }
736
+ const parentNode = this.game.canvas && this.game.canvas.parentNode;
737
+ return parentNode || null;
738
+ }
739
+
740
+ get scaleMode() {
741
+ return this._scaleMode;
742
+ }
743
+
744
+ set scaleMode(value) {
745
+ if (value !== this._scaleMode) {
746
+ if (!this.isFullScreen) {
747
+ this.updateDimensions(this._gameSize.width, this._gameSize.height, true);
748
+ this.queueUpdate(true);
749
+ }
750
+ this._scaleMode = value;
751
+ }
752
+ // return this._scaleMode;
753
+ }
754
+
755
+ get fullScreenScaleMode() {
756
+ return this._fullScreenScaleMode;
757
+ }
758
+
759
+ set fullScreenScaleMode(value) {
760
+ if (value !== this._fullScreenScaleMode) {
761
+ // If in fullscreen then need a wee bit more work
762
+ if (this.isFullScreen) {
763
+ this.prepScreenMode(false);
764
+ this._fullScreenScaleMode = value;
765
+ this.prepScreenMode(true);
766
+ this.queueUpdate(true);
767
+ } else {
768
+ this._fullScreenScaleMode = value;
769
+ }
770
+ }
771
+ // return this._fullScreenScaleMode;
772
+ }
773
+
774
+ get currentScaleMode() {
775
+ return this.isFullScreen ? this._fullScreenScaleMode : this._scaleMode;
776
+ }
777
+
778
+ get pageAlignHorizontally() {
779
+ return this._pageAlignHorizontally;
780
+ }
781
+
782
+ get pageAlignVertically() {
783
+ return this._pageAlignVertically;
784
+ }
785
+
786
+ get isFullScreen() {
787
+ return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
788
+ }
789
+
790
+ get isPortrait() {
791
+ return this.classifyOrientation(this.screenOrientation) === 'portrait';
792
+ }
793
+
794
+ get isLandscape() {
795
+ return this.classifyOrientation(this.screenOrientation) === 'landscape';
796
+ }
797
+
798
+ get isGamePortrait() {
799
+ return this.height > this.width;
800
+ }
801
+
802
+ get isGameLandscape() {
803
+ return this.width > this.height;
804
+ }
805
+
806
+ }