-
Notifications
You must be signed in to change notification settings - Fork 7.1k
/
ScaleManager.js
1867 lines (1589 loc) · 59.6 KB
/
ScaleManager.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @author Richard Davey <rich@phaser.io>
* @copyright 2013-2024 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var CONST = require('./const');
var Class = require('../utils/Class');
var EventEmitter = require('eventemitter3');
var Events = require('./events');
var GameEvents = require('../core/events');
var GetInnerHeight = require('../dom/GetInnerHeight');
var GetTarget = require('../dom/GetTarget');
var GetScreenOrientation = require('../dom/GetScreenOrientation');
var NOOP = require('../utils/NOOP');
var Rectangle = require('../geom/rectangle/Rectangle');
var Size = require('../structs/Size');
var SnapFloor = require('../math/snap/SnapFloor');
var Vector2 = require('../math/Vector2');
var Camera = require('../cameras/2d/Camera');
/**
* @classdesc
* The Scale Manager handles the scaling, resizing and alignment of the game canvas.
*
* The way scaling is handled is by setting the game canvas to a fixed size, which is defined in the
* game configuration. You also define the parent container in the game config. If no parent is given,
* it will default to using the document body. The Scale Manager will then look at the available space
* within the _parent_ and scale the canvas accordingly. Scaling is handled by setting the canvas CSS
* width and height properties, leaving the width and height of the canvas element itself untouched.
* Scaling is therefore achieved by keeping the core canvas the same size and 'stretching'
* it via its CSS properties. This gives the same result and speed as using the `transform-scale` CSS
* property, without the need for browser prefix handling.
*
* The calculations for the scale are heavily influenced by the bounding parent size, which is the computed
* dimensions of the canvas's parent. The CSS rules of the parent element play an important role in the
* operation of the Scale Manager. For example, if the parent has no defined width or height, then actions
* like auto-centering will fail to achieve the required result. The Scale Manager works in tandem with the
* CSS you set-up on the page hosting your game, rather than taking control of it.
*
* #### Parent and Display canvas containment guidelines:
*
* - Style the Parent element (of the game canvas) to control the Parent size and thus the games size and layout.
*
* - The Parent element's CSS styles should _effectively_ apply maximum (and minimum) bounding behavior.
*
* - The Parent element should _not_ apply a padding as this is not accounted for.
* If a padding is required apply it to the Parent's parent or apply a margin to the Parent.
* If you need to add a border, margin or any other CSS around your game container, then use a parent element and
* apply the CSS to this instead, otherwise you'll be constantly resizing the shape of the game container.
*
* - The Display canvas layout CSS styles (i.e. margins, size) should not be altered / specified as
* they may be updated by the Scale Manager.
*
* #### Scale Modes
*
* The way the scaling is handled is determined by the `scaleMode` property. The default is `NONE`,
* which prevents Phaser from scaling or touching the canvas, or its parent, at all. In this mode, you are
* responsible for all scaling. The other scaling modes afford you automatic scaling.
*
* If you wish to scale your game so that it always fits into the available space within the parent, you
* should use the scale mode `FIT`. Look at the documentation for other scale modes to see what options are
* available. Here is a basic config showing how to set this scale mode:
*
* ```javascript
* scale: {
* parent: 'yourgamediv',
* mode: Phaser.Scale.FIT,
* width: 800,
* height: 600
* }
* ```
*
* Place the `scale` config object within your game config.
*
* If you wish for the canvas to be resized directly, so that the canvas itself fills the available space
* (i.e. it isn't scaled, it's resized) then use the `RESIZE` scale mode. This will give you a 1:1 mapping
* of canvas pixels to game size. In this mode CSS isn't used to scale the canvas, it's literally adjusted
* to fill all available space within the parent. You should be extremely careful about the size of the
* canvas you're creating when doing this, as the larger the area, the more work the GPU has to do and it's
* very easy to hit fill-rate limits quickly.
*
* For complex, custom-scaling requirements, you should probably consider using the `RESIZE` scale mode,
* with your own limitations in place re: canvas dimensions and managing the scaling with the game scenes
* yourself. For the vast majority of games, however, the `FIT` mode is likely to be the most used.
*
* Please appreciate that the Scale Manager cannot perform miracles. All it does is scale your game canvas
* as best it can, based on what it can infer from its surrounding area. There are all kinds of environments
* where it's up to you to guide and help the canvas position itself, especially when built into rendering
* frameworks like React and Vue. If your page requires meta tags to prevent user scaling gestures, or such
* like, then it's up to you to ensure they are present in the html.
*
* #### Centering
*
* You can also have the game canvas automatically centered. Again, this relies heavily on the parent being
* properly configured and styled, as the centering offsets are based entirely on the available space
* within the parent element. Centering is disabled by default, or can be applied horizontally, vertically,
* or both. Here's an example:
*
* ```javascript
* scale: {
* parent: 'yourgamediv',
* autoCenter: Phaser.Scale.CENTER_BOTH,
* width: 800,
* height: 600
* }
* ```
*
* #### Fullscreen API
*
* If the browser supports it, you can send your game into fullscreen mode. In this mode, the game will fill
* the entire display, removing all browser UI and anything else present on the screen. It will remain in this
* mode until your game either disables it, or until the user tabs out or presses ESCape if on desktop. It's a
* great way to achieve a desktop-game like experience from the browser, but it does require a modern browser
* to handle it. Some mobile browsers also support this.
*
* @class ScaleManager
* @memberof Phaser.Scale
* @extends Phaser.Events.EventEmitter
* @constructor
* @since 3.16.0
*
* @param {Phaser.Game} game - A reference to the Phaser.Game instance.
*/
var ScaleManager = new Class({
Extends: EventEmitter,
initialize:
function ScaleManager (game)
{
EventEmitter.call(this);
/**
* A reference to the Phaser.Game instance.
*
* @name Phaser.Scale.ScaleManager#game
* @type {Phaser.Game}
* @readonly
* @since 3.15.0
*/
this.game = game;
/**
* A reference to the HTML Canvas Element that Phaser uses to render the game.
*
* @name Phaser.Scale.ScaleManager#canvas
* @type {HTMLCanvasElement}
* @since 3.16.0
*/
this.canvas;
/**
* The DOM bounds of the canvas element.
*
* @name Phaser.Scale.ScaleManager#canvasBounds
* @type {Phaser.Geom.Rectangle}
* @since 3.16.0
*/
this.canvasBounds = new Rectangle();
/**
* The parent object of the Canvas. Often a div, or the browser window, or nothing in non-browser environments.
*
* This is set in the Game Config as the `parent` property. If undefined (or just not present), it will default
* to use the document body. If specifically set to `null` Phaser will ignore all parent operations.
*
* @name Phaser.Scale.ScaleManager#parent
* @type {?any}
* @since 3.16.0
*/
this.parent = null;
/**
* Is the parent element the browser window?
*
* @name Phaser.Scale.ScaleManager#parentIsWindow
* @type {boolean}
* @since 3.16.0
*/
this.parentIsWindow = false;
/**
* The Parent Size component.
*
* @name Phaser.Scale.ScaleManager#parentSize
* @type {Phaser.Structs.Size}
* @since 3.16.0
*/
this.parentSize = new Size();
/**
* The Game Size component.
*
* The un-modified game size, as requested in the game config (the raw width / height),
* as used for world bounds, cameras, etc
*
* @name Phaser.Scale.ScaleManager#gameSize
* @type {Phaser.Structs.Size}
* @since 3.16.0
*/
this.gameSize = new Size();
/**
* The Base Size component.
*
* The modified game size, which is the auto-rounded gameSize, used to set the canvas width and height
* (but not the CSS style)
*
* @name Phaser.Scale.ScaleManager#baseSize
* @type {Phaser.Structs.Size}
* @since 3.16.0
*/
this.baseSize = new Size();
/**
* The Display Size component.
*
* The size used for the canvas style, factoring in the scale mode, parent and other values.
*
* @name Phaser.Scale.ScaleManager#displaySize
* @type {Phaser.Structs.Size}
* @since 3.16.0
*/
this.displaySize = new Size();
/**
* The game scale mode.
*
* @name Phaser.Scale.ScaleManager#scaleMode
* @type {Phaser.Scale.ScaleModeType}
* @since 3.16.0
*/
this.scaleMode = CONST.SCALE_MODE.NONE;
/**
* The game zoom factor.
*
* This value allows you to multiply your games base size by the given zoom factor.
* This is then used when calculating the display size, even in `NONE` situations.
* If you don't want Phaser to touch the canvas style at all, this value should be 1.
*
* Can also be set to `MAX_ZOOM` in which case the zoom value will be derived based
* on the game size and available space within the parent.
*
* @name Phaser.Scale.ScaleManager#zoom
* @type {number}
* @since 3.16.0
*/
this.zoom = 1;
/**
* Internal flag set when the game zoom factor is modified.
*
* @name Phaser.Scale.ScaleManager#_resetZoom
* @type {boolean}
* @readonly
* @since 3.19.0
*/
this._resetZoom = false;
/**
* The scale factor between the baseSize and the canvasBounds.
*
* @name Phaser.Scale.ScaleManager#displayScale
* @type {Phaser.Math.Vector2}
* @since 3.16.0
*/
this.displayScale = new Vector2(1, 1);
/**
* If set, the canvas sizes will be automatically passed through Math.floor.
* This results in rounded pixel display values, which is important for performance on legacy
* and low powered devices, but at the cost of not achieving a 'perfect' fit in some browser windows.
*
* @name Phaser.Scale.ScaleManager#autoRound
* @type {boolean}
* @since 3.16.0
*/
this.autoRound = false;
/**
* Automatically center the canvas within the parent? The different centering modes are:
*
* 1. No centering.
* 2. Center both horizontally and vertically.
* 3. Center horizontally.
* 4. Center vertically.
*
* Please be aware that in order to center the game canvas, you must have specified a parent
* that has a size set, or the canvas parent is the document.body.
*
* @name Phaser.Scale.ScaleManager#autoCenter
* @type {Phaser.Scale.CenterType}
* @since 3.16.0
*/
this.autoCenter = CONST.CENTER.NO_CENTER;
/**
* The current device orientation.
*
* Orientation events are dispatched via the Device Orientation API, typically only on mobile browsers.
*
* @name Phaser.Scale.ScaleManager#orientation
* @type {Phaser.Scale.OrientationType}
* @since 3.16.0
*/
this.orientation = CONST.ORIENTATION.LANDSCAPE;
/**
* A reference to the Device.Fullscreen object.
*
* @name Phaser.Scale.ScaleManager#fullscreen
* @type {Phaser.Device.Fullscreen}
* @since 3.16.0
*/
this.fullscreen;
/**
* The DOM Element which is sent into fullscreen mode.
*
* @name Phaser.Scale.ScaleManager#fullscreenTarget
* @type {?any}
* @since 3.16.0
*/
this.fullscreenTarget = null;
/**
* Did Phaser create the fullscreen target div, or was it provided in the game config?
*
* @name Phaser.Scale.ScaleManager#_createdFullscreenTarget
* @type {boolean}
* @private
* @since 3.16.0
*/
this._createdFullscreenTarget = false;
/**
* The dirty state of the Scale Manager.
* Set if there is a change between the parent size and the current size.
*
* @name Phaser.Scale.ScaleManager#dirty
* @type {boolean}
* @since 3.16.0
*/
this.dirty = false;
/**
* How many milliseconds should elapse before checking if the browser size has changed?
*
* Most modern browsers dispatch a 'resize' event, which the Scale Manager will listen for.
* However, older browsers fail to do this, or do it consistently, so we fall back to a
* more traditional 'size check' based on a time interval. You can control how often it is
* checked here.
*
* @name Phaser.Scale.ScaleManager#resizeInterval
* @type {number}
* @since 3.16.0
*/
this.resizeInterval = 500;
/**
* Internal size interval tracker.
*
* @name Phaser.Scale.ScaleManager#_lastCheck
* @type {number}
* @private
* @since 3.16.0
*/
this._lastCheck = 0;
/**
* Internal flag to check orientation state.
*
* @name Phaser.Scale.ScaleManager#_checkOrientation
* @type {boolean}
* @private
* @since 3.16.0
*/
this._checkOrientation = false;
/**
* Internal object containing our defined event listeners.
*
* @name Phaser.Scale.ScaleManager#domlisteners
* @type {object}
* @private
* @since 3.16.0
*/
this.domlisteners = {
orientationChange: NOOP,
windowResize: NOOP,
fullScreenChange: NOOP,
fullScreenError: NOOP
};
},
/**
* Called _before_ the canvas object is created and added to the DOM.
*
* @method Phaser.Scale.ScaleManager#preBoot
* @protected
* @listens Phaser.Core.Events#BOOT
* @since 3.16.0
*/
preBoot: function ()
{
// Parse the config to get the scaling values we need
this.parseConfig(this.game.config);
this.game.events.once(GameEvents.BOOT, this.boot, this);
},
/**
* The Boot handler is called by Phaser.Game when it first starts up.
* The renderer is available by now and the canvas has been added to the DOM.
*
* @method Phaser.Scale.ScaleManager#boot
* @protected
* @fires Phaser.Scale.Events#RESIZE
* @since 3.16.0
*/
boot: function ()
{
var game = this.game;
this.canvas = game.canvas;
this.fullscreen = game.device.fullscreen;
if ((this.scaleMode !== CONST.SCALE_MODE.RESIZE) && (this.scaleMode !== CONST.SCALE_MODE.EXPAND))
{
this.displaySize.setAspectMode(this.scaleMode);
}
if (this.scaleMode === CONST.SCALE_MODE.NONE)
{
this.resize(this.width, this.height);
}
else
{
this.getParentBounds();
// Only set the parent bounds if the parent has an actual size
if (this.parentSize.width > 0 && this.parentSize.height > 0)
{
this.displaySize.setParent(this.parentSize);
}
this.refresh();
}
game.events.on(GameEvents.PRE_STEP, this.step, this);
game.events.once(GameEvents.READY, this.refresh, this);
game.events.once(GameEvents.DESTROY, this.destroy, this);
this.startListeners();
},
/**
* Parses the game configuration to set-up the scale defaults.
*
* @method Phaser.Scale.ScaleManager#parseConfig
* @protected
* @since 3.16.0
*
* @param {Phaser.Types.Core.GameConfig} config - The Game configuration object.
*/
parseConfig: function (config)
{
// Get the parent element, if any
this.getParent(config);
// Get the size of the parent element
// This can often set a height of zero (especially for un-styled divs)
this.getParentBounds();
var width = config.width;
var height = config.height;
var scaleMode = config.scaleMode;
var zoom = config.zoom;
var autoRound = config.autoRound;
// If width = '100%', or similar value
if (typeof width === 'string')
{
// Does width have a % character at the end? If not, we use it as a numeric value.
if (width.substr(-1) !== '%')
{
width = parseInt(width, 10);
}
else
{
// If we have a parent with a width, we'll work it out from that
var parentWidth = this.parentSize.width;
if (parentWidth === 0)
{
parentWidth = window.innerWidth;
}
var parentScaleX = parseInt(width, 10) / 100;
width = Math.floor(parentWidth * parentScaleX);
}
}
// If height = '100%', or similar value
if (typeof height === 'string')
{
// Does height have a % character at the end? If not, we use it as a numeric value.
if (height.substr(-1) !== '%')
{
height = parseInt(height, 10);
}
else
{
// If we have a parent with a height, we'll work it out from that
var parentHeight = this.parentSize.height;
if (parentHeight === 0)
{
parentHeight = window.innerHeight;
}
var parentScaleY = parseInt(height, 10) / 100;
height = Math.floor(parentHeight * parentScaleY);
}
}
this.scaleMode = scaleMode;
this.autoRound = autoRound;
this.autoCenter = config.autoCenter;
this.resizeInterval = config.resizeInterval;
if (autoRound)
{
width = Math.floor(width);
height = Math.floor(height);
}
// The un-modified game size, as requested in the game config (the raw width / height) as used for world bounds, etc
this.gameSize.setSize(width, height);
if (zoom === CONST.ZOOM.MAX_ZOOM)
{
zoom = this.getMaxZoom();
}
this.zoom = zoom;
if (zoom !== 1)
{
this._resetZoom = true;
}
// The modified game size
this.baseSize.setSize(width, height);
if (autoRound)
{
this.baseSize.width = Math.floor(this.baseSize.width);
this.baseSize.height = Math.floor(this.baseSize.height);
}
if (config.minWidth > 0)
{
this.displaySize.setMin(config.minWidth * zoom, config.minHeight * zoom);
}
if (config.maxWidth > 0)
{
this.displaySize.setMax(config.maxWidth * zoom, config.maxHeight * zoom);
}
// The size used for the canvas style, factoring in the scale mode and parent and zoom value
// We just use the w/h here as this is what sets the aspect ratio (which doesn't then change)
this.displaySize.setSize(width, height);
if (config.snapWidth > 0 || config.snapHeight > 0)
{
this.displaySize.setSnap(config.snapWidth, config.snapHeight);
}
this.orientation = GetScreenOrientation(width, height);
},
/**
* Determines the parent element of the game canvas, if any, based on the game configuration.
*
* @method Phaser.Scale.ScaleManager#getParent
* @since 3.16.0
*
* @param {Phaser.Types.Core.GameConfig} config - The Game configuration object.
*/
getParent: function (config)
{
var parent = config.parent;
if (parent === null)
{
// User is responsible for managing the parent
return;
}
this.parent = GetTarget(parent);
this.parentIsWindow = (this.parent === document.body);
if (config.expandParent && config.scaleMode !== CONST.SCALE_MODE.NONE)
{
var DOMRect = this.parent.getBoundingClientRect();
if (this.parentIsWindow || DOMRect.height === 0)
{
document.documentElement.style.height = '100%';
document.body.style.height = '100%';
DOMRect = this.parent.getBoundingClientRect();
// The parent STILL has no height, clearly no CSS
// has been set on it even though we fixed the body :(
if (!this.parentIsWindow && DOMRect.height === 0)
{
this.parent.style.overflow = 'hidden';
this.parent.style.width = '100%';
this.parent.style.height = '100%';
}
}
}
// And now get the fullscreenTarget
if (config.fullscreenTarget && !this.fullscreenTarget)
{
this.fullscreenTarget = GetTarget(config.fullscreenTarget);
}
},
/**
* Calculates the size of the parent bounds and updates the `parentSize`
* properties, only if the canvas has a dom parent.
*
* @method Phaser.Scale.ScaleManager#getParentBounds
* @since 3.16.0
*
* @return {boolean} `true` if the parent bounds have changed size or position, otherwise `false`.
*/
getParentBounds: function ()
{
if (!this.parent)
{
return false;
}
var parentSize = this.parentSize;
// Ref. http://msdn.microsoft.com/en-us/library/hh781509(v=vs.85).aspx for getBoundingClientRect
// The returned value is a DOMRect object which is the smallest rectangle which contains the entire element,
// including its padding and border-width. The left, top, right, bottom, x, y, width, and height properties
// describe the position and size of the overall rectangle in pixels. Properties other than width and height
// are relative to the top-left of the viewport.
var DOMRect = this.parent.getBoundingClientRect();
if (this.parentIsWindow && this.game.device.os.iOS)
{
DOMRect.height = GetInnerHeight(true);
}
var newWidth = DOMRect.width;
var newHeight = DOMRect.height;
if (parentSize.width !== newWidth || parentSize.height !== newHeight)
{
parentSize.setSize(newWidth, newHeight);
return true;
}
else if (this.canvas)
{
var canvasBounds = this.canvasBounds;
var canvasRect = this.canvas.getBoundingClientRect();
if (canvasRect.x !== canvasBounds.x || canvasRect.y !== canvasBounds.y)
{
return true;
}
}
return false;
},
/**
* Attempts to lock the orientation of the web browser using the Screen Orientation API.
*
* This API is only available on modern mobile browsers.
* See https://developer.mozilla.org/en-US/docs/Web/API/Screen/lockOrientation for details.
*
* @method Phaser.Scale.ScaleManager#lockOrientation
* @since 3.16.0
*
* @param {string} orientation - The orientation you'd like to lock the browser in. Should be an API string such as 'landscape', 'landscape-primary', 'portrait', etc.
*
* @return {boolean} `true` if the orientation was successfully locked, otherwise `false`.
*/
lockOrientation: function (orientation)
{
var lock = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation;
if (lock)
{
return lock.call(screen, orientation);
}
return false;
},
/**
* This method will set the size of the Parent Size component, which is used in scaling
* and centering calculations. You only need to call this method if you have explicitly
* disabled the use of a parent in your game config, but still wish to take advantage of
* other Scale Manager features.
*
* @method Phaser.Scale.ScaleManager#setParentSize
* @fires Phaser.Scale.Events#RESIZE
* @since 3.16.0
*
* @param {number} width - The new width of the parent.
* @param {number} height - The new height of the parent.
*
* @return {this} The Scale Manager instance.
*/
setParentSize: function (width, height)
{
this.parentSize.setSize(width, height);
return this.refresh();
},
/**
* This method will set a new size for your game.
*
* It should only be used if you're looking to change the base size of your game and are using
* one of the Scale Manager scaling modes, i.e. `FIT`. If you're using `NONE` and wish to
* change the game and canvas size directly, then please use the `resize` method instead.
*
* @method Phaser.Scale.ScaleManager#setGameSize
* @fires Phaser.Scale.Events#RESIZE
* @since 3.16.0
*
* @param {number} width - The new width of the game.
* @param {number} height - The new height of the game.
*
* @return {this} The Scale Manager instance.
*/
setGameSize: function (width, height)
{
var autoRound = this.autoRound;
if (autoRound)
{
width = Math.floor(width);
height = Math.floor(height);
}
var previousWidth = this.width;
var previousHeight = this.height;
// The un-modified game size, as requested in the game config (the raw width / height) as used for world bounds, etc
this.gameSize.resize(width, height);
// The modified game size
this.baseSize.resize(width, height);
if (autoRound)
{
this.baseSize.width = Math.floor(this.baseSize.width);
this.baseSize.height = Math.floor(this.baseSize.height);
}
// The size used for the canvas style, factoring in the scale mode and parent and zoom value
// Update the aspect ratio
this.displaySize.setAspectRatio(width / height);
this.canvas.width = this.baseSize.width;
this.canvas.height = this.baseSize.height;
return this.refresh(previousWidth, previousHeight);
},
/**
* Call this to modify the size of the Phaser canvas element directly.
* You should only use this if you are using the `NONE` scale mode,
* it will update all internal components completely.
*
* If all you want to do is change the size of the parent, see the `setParentSize` method.
*
* If all you want is to change the base size of the game, but still have the Scale Manager
* manage all the scaling (i.e. you're **not** using `NONE`), then see the `setGameSize` method.
*
* This method will set the `gameSize`, `baseSize` and `displaySize` components to the given
* dimensions. It will then resize the canvas width and height to the values given, by
* directly setting the properties. Finally, if you have set the Scale Manager zoom value
* to anything other than 1 (the default), it will set the canvas CSS width and height to
* be the given size multiplied by the zoom factor (the canvas pixel size remains untouched).
*
* If you have enabled `autoCenter`, it is then passed to the `updateCenter` method and
* the margins are set, allowing the canvas to be centered based on its parent element
* alone. Finally, the `displayScale` is adjusted and the RESIZE event dispatched.
*
* @method Phaser.Scale.ScaleManager#resize
* @fires Phaser.Scale.Events#RESIZE
* @since 3.16.0
*
* @param {number} width - The new width of the game.
* @param {number} height - The new height of the game.
*
* @return {this} The Scale Manager instance.
*/
resize: function (width, height)
{
var zoom = this.zoom;
var autoRound = this.autoRound;
if (autoRound)
{
width = Math.floor(width);
height = Math.floor(height);
}
var previousWidth = this.width;
var previousHeight = this.height;
// The un-modified game size, as requested in the game config (the raw width / height) as used for world bounds, etc
this.gameSize.resize(width, height);
// The modified game size
this.baseSize.resize(width, height);
if (autoRound)
{
this.baseSize.width = Math.floor(this.baseSize.width);
this.baseSize.height = Math.floor(this.baseSize.height);
}
// The size used for the canvas style, factoring in the scale mode and parent and zoom value
// We just use the w/h here as this is what sets the aspect ratio (which doesn't then change)
this.displaySize.setSize((width * zoom), (height * zoom));
this.canvas.width = this.baseSize.width;
this.canvas.height = this.baseSize.height;
var style = this.canvas.style;
var styleWidth = width * zoom;
var styleHeight = height * zoom;
if (autoRound)
{
styleWidth = Math.floor(styleWidth);
styleHeight = Math.floor(styleHeight);
}
if (styleWidth !== width || styleHeight !== height)
{
style.width = styleWidth + 'px';
style.height = styleHeight + 'px';
}
return this.refresh(previousWidth, previousHeight);
},
/**
* Sets the zoom value of the Scale Manager.
*
* @method Phaser.Scale.ScaleManager#setZoom
* @fires Phaser.Scale.Events#RESIZE
* @since 3.16.0
*
* @param {number} value - The new zoom value of the game.
*
* @return {this} The Scale Manager instance.
*/
setZoom: function (value)
{
this.zoom = value;
this._resetZoom = true;
return this.refresh();
},
/**
* Sets the zoom to be the maximum possible based on the _current_ parent size.
*
* @method Phaser.Scale.ScaleManager#setMaxZoom
* @fires Phaser.Scale.Events#RESIZE
* @since 3.16.0
*
* @return {this} The Scale Manager instance.
*/
setMaxZoom: function ()
{
this.zoom = this.getMaxZoom();
this._resetZoom = true;
return this.refresh();
},
/**
* By setting a Snap value, when the browser size is modified, its dimensions will automatically
* be snapped to the nearest grid slice, using floor. For example, if you have snap value of 16,
* and the width changes to 68, then it will snap down to 64 (the closest multiple of 16 when floored)
*
* This mode is best used with the `FIT` scale mode.
*
* Call this method with no arguments to reset the snap values.
*
* Calling this method automatically invokes `ScaleManager.refresh` which emits a `RESIZE` event.
*
* @method Phaser.Scale.ScaleManager#setSnap
* @fires Phaser.Scale.Events#RESIZE
* @since 3.80.0
*
* @param {number} [snapWidth=0] - The amount to snap the width to. If you don't want to snap the width, pass a value of zero.
* @param {number} [snapHeight=snapWidth] - The amount to snap the height to. If not provided it will use the `snapWidth` value. If you don't want to snap the height, pass a value of zero.
*
* @return {this} The Scale Manager instance.
*/
setSnap: function (snapWidth, snapHeight)
{
if (snapWidth === undefined) { snapWidth = 0; }
if (snapHeight === undefined) { snapHeight = snapWidth; }
this.displaySize.setSnap(snapWidth, snapHeight);
return this.refresh();
},
/**
* Refreshes the internal scale values, bounds sizes and orientation checks.
*
* Once finished, dispatches the resize event.
*
* This is called automatically by the Scale Manager when the browser window size changes,
* as long as it is using a Scale Mode other than 'NONE'.
*
* @method Phaser.Scale.ScaleManager#refresh
* @fires Phaser.Scale.Events#RESIZE
* @since 3.16.0
*
* @param {number} [previousWidth] - The previous width of the game. Only set if the gameSize has changed.
* @param {number} [previousHeight] - The previous height of the game. Only set if the gameSize has changed.
*
* @return {this} The Scale Manager instance.
*/
refresh: function (previousWidth, previousHeight)
{
if (previousWidth === undefined) { previousWidth = this.width; }
if (previousHeight === undefined) { previousHeight = this.height; }
this.updateScale();
this.updateBounds();
this.updateOrientation();
this.displayScale.set(this.baseSize.width / this.canvasBounds.width, this.baseSize.height / this.canvasBounds.height);
var domContainer = this.game.domContainer;
if (domContainer)
{
this.baseSize.setCSS(domContainer);
var canvasStyle = this.canvas.style;
var domStyle = domContainer.style;
domStyle.transform = 'scale(' + this.displaySize.width / this.baseSize.width + ',' + this.displaySize.height / this.baseSize.height + ')';
domStyle.marginLeft = canvasStyle.marginLeft;
domStyle.marginTop = canvasStyle.marginTop;
}
this.emit(Events.RESIZE, this.gameSize, this.baseSize, this.displaySize, previousWidth, previousHeight);
return this;
},
/**
* Internal method that checks the current screen orientation, only if the internal check flag is set.
*
* If the orientation has changed it updates the orientation property and then dispatches the orientation change event.
*
* @method Phaser.Scale.ScaleManager#updateOrientation