Updated Size component to handle fitting, ratios, locking and more.

This commit is contained in:
Richard Davey 2018-12-19 17:07:46 +00:00
parent c6f72241e3
commit f5fcea898c

View file

@ -4,12 +4,16 @@
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var Clamp = require('../math/Clamp');
var Class = require('../utils/Class');
/**
* @classdesc
* The Size component is a simple structure that helps you encapsulate a `width` and `height` and, if required, maintain
* the aspect ratios between them.
* The Size component allows you to set `width` and `height` properties and define the relationship between them.
*
* The component can automatically maintain the aspect ratios between the two values, and clamp them
* to a defined min-max range. You can also control the dominant axis. When dimensions are given to the Size component
* that would cause it to exceed its min-max range, the dimensions are adjusted based on the dominant axis.
*
* @class Size
* @memberof Phaser.Structs
@ -18,17 +22,19 @@ var Class = require('../utils/Class');
*
* @param {number} [width] - The width of the Size component.
* @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`.
* @param {boolean} [lockAspectRatio=false] - Should the aspect ratio between the `width` and `height` be locked?
* @param {boolean} [lockAspectRatio=false] - Should the aspect ratio be locked? It will be based on the given `width` and `height` arguments.
* @param {boolean} [lockWidth=true] - Set to `true` to make the `width` the dominant axis, or `false` to make `height` the dominant axis.
*/
var Size = new Class({
initialize:
function Size (width, height, lockAspectRatio)
function Size (width, height, lockAspectRatio, lockWidth)
{
if (width === undefined) { width = 0; }
if (height === undefined) { height = width; }
if (lockAspectRatio === undefined) { lockAspectRatio = false; }
if (lockWidth === undefined) { lockWidth = true; }
/**
* The width.
@ -61,7 +67,7 @@ var Size = new Class({
* @readonly
* @since 3.16.0
*/
this.ratioH = (height === 0) ? 0 : width / height;
this.ratioH = (height === 0) ? 1 : width / height;
/**
* The proportional relationship between the height and width.
@ -74,18 +80,70 @@ var Size = new Class({
* @readonly
* @since 3.16.0
*/
this.ratioV = (width === 0) ? 0 : height / width;
this.ratioV = (width === 0) ? 1 : height / width;
/**
* Lock the aspect ratio to its current value?
* Set this property to lock the aspect ratios to their current values.
*
* If enabled, changing the width or height properties will automatically adjust the other based on the aspect ratio.
* Once enabled, changing the `width` or `height` properties will automatically adjust the other based on the aspect ratio.
*
* @name Phaser.Structs.Size#lock
* @name Phaser.Structs.Size#lockAspectRatio
* @type {boolean}
* @since 3.16.0
*/
this.lock = lockAspectRatio;
this.lockAspectRatio = lockAspectRatio;
/**
* When scaling the Size based on the min-max range and the aspect ratio, this property controls the priority of
* the axis. If `true` (the default) the `width` will be the dominant axis, and the height will adjust to match it. If `false`,
* the `height` will be the dominant axis, and the `width` will adjust to match it.
*
* @name Phaser.Structs.Size#lockWidth
* @type {boolean}
* @default true
* @since 3.16.0
*/
this.lockWidth = lockWidth;
/**
* The minimum allowed width.
*
* @name Phaser.Structs.Size#_minWidth
* @type {number}
* @private
* @since 3.16.0
*/
this._minWidth = 0;
/**
* The minimum allowed height.
*
* @name Phaser.Structs.Size#_minHeight
* @type {number}
* @private
* @since 3.16.0
*/
this._minHeight = 0;
/**
* The maximum allowed width.
*
* @name Phaser.Structs.Size#_maxWidth
* @type {number}
* @private
* @since 3.16.0
*/
this._maxWidth = Number.MAX_VALUE;
/**
* The maximum allowed height.
*
* @name Phaser.Structs.Size#_maxHeight
* @type {number}
* @private
* @since 3.16.0
*/
this._maxHeight = Number.MAX_VALUE;
},
/**
@ -102,41 +160,247 @@ var Size = new Class({
*/
setAspectRatioLock: function (value)
{
this.lock = value;
this.lockAspectRatio = value;
return this;
},
/**
* Lock the aspect ratio to its current value?
* Set the minimum width and height values this Size component will allow.
*
* If enabled, changing the `width` or `height` properties will automatically adjust the other based on the aspect ratio.
* If enabled, the properties will be clamped to the min-max range, including when locked to their aspect ratios.
*
* Setting this will automatically adjust both the `width` and `height` properties to ensure they are within range.
*
* @method Phaser.Structs.Size#set
* @method Phaser.Structs.Size#setMin
* @since 3.16.0
*
* @param {number} [width] - The width of the Size component.
* @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`.
* @param {boolean} [lockAspectRatio=false] - Should the aspect ratio between the `width` and `height` be locked?
* @param {number} [width=0] - The minimum allowed width of the Size component.
* @param {number} [height=width] - The minimum allowed height of the Size component. If not given, it will use the `width`.
*
* @return {this} This Size instance.
*/
set: function (width, height)
setMin: function (width, height)
{
if (width === undefined) { width = 0; }
if (height === undefined) { height = width; }
if (this.lock)
this._minWidth = width;
this._minHeight = height;
return this.update();
},
/**
* Set the maximum width and height values this Size component will allow.
*
* If enabled, the properties will be clamped to the min-max range, including when locked to their aspect ratios.
*
* Setting this will automatically adjust both the `width` and `height` properties to ensure they are within range.
*
* @method Phaser.Structs.Size#setMax
* @since 3.16.0
*
* @param {number} [width=Number.MAX_VALUE] - The maximum allowed width of the Size component.
* @param {number} [height=width] - The maximum allowed height of the Size component. If not given, it will use the `width`.
*
* @return {this} This Size instance.
*/
setMax: function (width, height)
{
if (width === undefined) { width = Number.MAX_VALUE; }
if (height === undefined) { height = width; }
this._maxWidth = width;
this._maxHeight = height;
return this.update();
},
/**
* Calls `setSize` with the current width and height.
* This has the effect of applying min-max clamping and axis locking to the current values.
*
* @method Phaser.Structs.Size#update
* @since 3.16.0
*
* @return {this} This Size instance.
*/
update: function ()
{
return this.setSize(this._width, this._height);
},
/**
* Updates the `ratioH` and `ratioV` properties based on the current width and height.
*
* They are only updated if `lockAspectRatio` is `false`.
*
* @method Phaser.Structs.Size#updateRatios
* @since 3.16.0
*
* @return {this} This Size instance.
*/
updateRatios: function ()
{
if (!this.lockAspectRatio)
{
this._width = width * this.ratioH;
this._height = height * this.ratioV;
this.ratioH = (this._height === 0) ? 1 : this._width / this._height;
this.ratioV = (this._width === 0) ? 1 : this._height / this._width;
}
else
return this;
},
/**
* Sets a new width for this Size component.
*
* The new width is clamped to the min-max range automatically.
*
* Additionally, if the aspect ratio is locked, the height will also be adjusted based on the new width.
*
* @method Phaser.Structs.Size#updateWidth
* @since 3.16.0
*
* @param {number} width - The new width of the Size component.
*
* @return {this} This Size instance.
*/
updateWidth: function (width)
{
width = Clamp(width, this._minWidth, this._maxWidth);
if (this.lockAspectRatio)
{
this._width = width;
this.height = height;
// What's the new height?
var height = width * this.ratioV;
// height takes priority
if (!this.lockWidth)
{
if (height < this._minHeight)
{
height = this._minHeight;
}
else if (height > this._maxHeight)
{
height = this._maxHeight;
}
// Re-adjust the width based on the dominant height
width = height * this.ratioH;
}
}
this._width = width;
this._height = height;
return this.updateRatios();
},
/**
* Sets a new height for this Size component.
*
* The new height is clamped to the min-max range automatically.
*
* Additionally, if the aspect ratio is locked, the width will also be adjusted based on the new height.
*
* @method Phaser.Structs.Size#updateHeight
* @since 3.16.0
*
* @param {number} height - The new height of the Size component.
*
* @return {this} This Size instance.
*/
updateHeight: function (height)
{
height = Clamp(height, this._minHeight, this._maxHeight);
if (this.lockAspectRatio)
{
// What's the new width?
var width = height * this.ratioH;
// width takes priority
if (this.lockWidth)
{
if (width < this._minWidth)
{
width = this._minWidth;
}
else if (width > this._maxWidth)
{
width = this._maxWidth;
}
// Re-adjust the height based on the dominant width
height = width * this.ratioV;
}
}
this._width = width;
this._height = height;
return this.updateRatios();
},
/**
* Set the width and height of this Size component, adjusting for the aspect ratio, if locked.
*
* @method Phaser.Structs.Size#setSize
* @since 3.16.0
*
* @param {number} [width] - The width of the Size component.
* @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`.
*
* @return {this} This Size instance.
*/
setSize: function (width, height)
{
if (width === undefined) { width = 0; }
if (height === undefined) { height = width; }
return (this.lockWidth) ? this.updateWidth(width) : this.updateHeight(height);
},
/**
* The `width` and `height` are adjusted to fit inside the given dimensions, while keeping the current aspect ratio.
*
* There may be some space inside the parent area which is not covered if its aspect ratio differs.
*
* @method Phaser.Structs.Size#fitTo
* @since 3.16.0
*
* @param {number} width - The width of the Size component.
* @param {number} height - The height of the Size component.
*
* @return {this} This Size instance.
*/
fitTo: function (width, height)
{
// Get the aspect ratios in case we need to expand or shrink to fit
var newRatio = (height === 0) ? 1 : width / height;
var newWidth = width;
var newHeight = height;
// Get the larger aspect ratio of the two.
// If aspect ratio is 1 then no adjustment needed
if (this.ratioH > newRatio)
{
newHeight = width / this.ratioH;
}
else if (this.ratioH < newRatio)
{
newWidth = height * this.ratioH;
}
this._width = newWidth;
this._height = newHeight;
this.ratioH = (this._height === 0) ? 1 : this._width / this._height;
this.ratioV = (this._width === 0) ? 1 : this._height / this._width;
return this;
},
@ -154,9 +418,7 @@ var Size = new Class({
*/
setWidth: function (value)
{
this.width = value;
return this;
return this.updateWidth(value);
},
/**
@ -186,9 +448,7 @@ var Size = new Class({
*/
setHeight: function (value)
{
this.height = value;
return this;
return this.updateHeight(value);
},
/**
@ -214,11 +474,15 @@ var Size = new Class({
*/
toString: function ()
{
return '[{ Size (width=' + this._width + ' height=' + this._height + ' ratioH=' + this.ratioH + ' ratioV=' + this.ratioV + ' lock=' + this.lock + ') }]';
return '[{ Size (width=' + this._width + ' height=' + this._height + ' ratioH=' + this.ratioH + ' ratioV=' + this.ratioV + ' lockAspectRatio=' + this.lockAspectRatio + ') }]';
},
/**
* The width.
* The width of this Size component.
*
* This value is clamped to the range specified by `minWidth` and `maxWidth`, if enabled.
*
* A width can never be less than zero.
*
* Changing this value will automatically update the `height` if the aspect ratio lock is enabled.
* You can also use the `setWidth` and `getWidth` methods.
@ -236,23 +500,17 @@ var Size = new Class({
set: function (value)
{
this._width = value;
if (this.lock)
{
this._height = value * this.ratioV;
}
else
{
this.ratioH = (this._height === 0) ? 0 : value / this._height;
this.ratioV = (this._width === 0) ? 0 : this._height / value;
}
this.updateWidth(value);
}
},
/**
* The height.
* The height of this Size component.
*
* This value is clamped to the range specified by `minHeight` and `maxHeight`, if enabled.
*
* A height can never be less than zero.
*
* Changing this value will automatically update the `width` if the aspect ratio lock is enabled.
* You can also use the `setHeight` and `getHeight` methods.
@ -270,17 +528,7 @@ var Size = new Class({
set: function (value)
{
this._height = value;
if (this.lock)
{
this._width = value * this.ratioH;
}
else
{
this.ratioH = (this._height === 0) ? 0 : this._width / value;
this.ratioV = (this._width === 0) ? 0 : value / this._width;
}
this.updateHeight(value);
}
}