lib/goog/math/size.js

1// Copyright 2007 The Closure Library Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS-IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/**
16 * @fileoverview A utility class for representing two-dimensional sizes.
17 * @author brenneman@google.com (Shawn Brenneman)
18 */
19
20
21goog.provide('goog.math.Size');
22
23
24
25/**
26 * Class for representing sizes consisting of a width and height. Undefined
27 * width and height support is deprecated and results in compiler warning.
28 * @param {number} width Width.
29 * @param {number} height Height.
30 * @constructor
31 */
32goog.math.Size = function(width, height) {
33 /**
34 * Width
35 * @type {number}
36 */
37 this.width = width;
38
39 /**
40 * Height
41 * @type {number}
42 */
43 this.height = height;
44};
45
46
47/**
48 * Compares sizes for equality.
49 * @param {goog.math.Size} a A Size.
50 * @param {goog.math.Size} b A Size.
51 * @return {boolean} True iff the sizes have equal widths and equal
52 * heights, or if both are null.
53 */
54goog.math.Size.equals = function(a, b) {
55 if (a == b) {
56 return true;
57 }
58 if (!a || !b) {
59 return false;
60 }
61 return a.width == b.width && a.height == b.height;
62};
63
64
65/**
66 * @return {!goog.math.Size} A new copy of the Size.
67 */
68goog.math.Size.prototype.clone = function() {
69 return new goog.math.Size(this.width, this.height);
70};
71
72
73if (goog.DEBUG) {
74 /**
75 * Returns a nice string representing size.
76 * @return {string} In the form (50 x 73).
77 * @override
78 */
79 goog.math.Size.prototype.toString = function() {
80 return '(' + this.width + ' x ' + this.height + ')';
81 };
82}
83
84
85/**
86 * @return {number} The longer of the two dimensions in the size.
87 */
88goog.math.Size.prototype.getLongest = function() {
89 return Math.max(this.width, this.height);
90};
91
92
93/**
94 * @return {number} The shorter of the two dimensions in the size.
95 */
96goog.math.Size.prototype.getShortest = function() {
97 return Math.min(this.width, this.height);
98};
99
100
101/**
102 * @return {number} The area of the size (width * height).
103 */
104goog.math.Size.prototype.area = function() {
105 return this.width * this.height;
106};
107
108
109/**
110 * @return {number} The perimeter of the size (width + height) * 2.
111 */
112goog.math.Size.prototype.perimeter = function() {
113 return (this.width + this.height) * 2;
114};
115
116
117/**
118 * @return {number} The ratio of the size's width to its height.
119 */
120goog.math.Size.prototype.aspectRatio = function() {
121 return this.width / this.height;
122};
123
124
125/**
126 * @return {boolean} True if the size has zero area, false if both dimensions
127 * are non-zero numbers.
128 */
129goog.math.Size.prototype.isEmpty = function() {
130 return !this.area();
131};
132
133
134/**
135 * Clamps the width and height parameters upward to integer values.
136 * @return {!goog.math.Size} This size with ceil'd components.
137 */
138goog.math.Size.prototype.ceil = function() {
139 this.width = Math.ceil(this.width);
140 this.height = Math.ceil(this.height);
141 return this;
142};
143
144
145/**
146 * @param {!goog.math.Size} target The target size.
147 * @return {boolean} True if this Size is the same size or smaller than the
148 * target size in both dimensions.
149 */
150goog.math.Size.prototype.fitsInside = function(target) {
151 return this.width <= target.width && this.height <= target.height;
152};
153
154
155/**
156 * Clamps the width and height parameters downward to integer values.
157 * @return {!goog.math.Size} This size with floored components.
158 */
159goog.math.Size.prototype.floor = function() {
160 this.width = Math.floor(this.width);
161 this.height = Math.floor(this.height);
162 return this;
163};
164
165
166/**
167 * Rounds the width and height parameters to integer values.
168 * @return {!goog.math.Size} This size with rounded components.
169 */
170goog.math.Size.prototype.round = function() {
171 this.width = Math.round(this.width);
172 this.height = Math.round(this.height);
173 return this;
174};
175
176
177/**
178 * Scales this size by the given scale factors. The width and height are scaled
179 * by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} is not
180 * given, then {@code sx} is used for both the width and height.
181 * @param {number} sx The scale factor to use for the width.
182 * @param {number=} opt_sy The scale factor to use for the height.
183 * @return {!goog.math.Size} This Size object after scaling.
184 */
185goog.math.Size.prototype.scale = function(sx, opt_sy) {
186 var sy = goog.isNumber(opt_sy) ? opt_sy : sx;
187 this.width *= sx;
188 this.height *= sy;
189 return this;
190};
191
192
193/**
194 * Uniformly scales the size to fit inside the dimensions of a given size. The
195 * original aspect ratio will be preserved.
196 *
197 * This function assumes that both Sizes contain strictly positive dimensions.
198 * @param {!goog.math.Size} target The target size.
199 * @return {!goog.math.Size} This Size object, after optional scaling.
200 */
201goog.math.Size.prototype.scaleToFit = function(target) {
202 var s = this.aspectRatio() > target.aspectRatio() ?
203 target.width / this.width :
204 target.height / this.height;
205
206 return this.scale(s);
207};