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 * @struct
31 * @constructor
32 */
33goog.math.Size = function(width, height) {
34 /**
35 * Width
36 * @type {number}
37 */
38 this.width = width;
39
40 /**
41 * Height
42 * @type {number}
43 */
44 this.height = height;
45};
46
47
48/**
49 * Compares sizes for equality.
50 * @param {goog.math.Size} a A Size.
51 * @param {goog.math.Size} b A Size.
52 * @return {boolean} True iff the sizes have equal widths and equal
53 * heights, or if both are null.
54 */
55goog.math.Size.equals = function(a, b) {
56 if (a == b) {
57 return true;
58 }
59 if (!a || !b) {
60 return false;
61 }
62 return a.width == b.width && a.height == b.height;
63};
64
65
66/**
67 * @return {!goog.math.Size} A new copy of the Size.
68 */
69goog.math.Size.prototype.clone = function() {
70 return new goog.math.Size(this.width, this.height);
71};
72
73
74if (goog.DEBUG) {
75 /**
76 * Returns a nice string representing size.
77 * @return {string} In the form (50 x 73).
78 * @override
79 */
80 goog.math.Size.prototype.toString = function() {
81 return '(' + this.width + ' x ' + this.height + ')';
82 };
83}
84
85
86/**
87 * @return {number} The longer of the two dimensions in the size.
88 */
89goog.math.Size.prototype.getLongest = function() {
90 return Math.max(this.width, this.height);
91};
92
93
94/**
95 * @return {number} The shorter of the two dimensions in the size.
96 */
97goog.math.Size.prototype.getShortest = function() {
98 return Math.min(this.width, this.height);
99};
100
101
102/**
103 * @return {number} The area of the size (width * height).
104 */
105goog.math.Size.prototype.area = function() {
106 return this.width * this.height;
107};
108
109
110/**
111 * @return {number} The perimeter of the size (width + height) * 2.
112 */
113goog.math.Size.prototype.perimeter = function() {
114 return (this.width + this.height) * 2;
115};
116
117
118/**
119 * @return {number} The ratio of the size's width to its height.
120 */
121goog.math.Size.prototype.aspectRatio = function() {
122 return this.width / this.height;
123};
124
125
126/**
127 * @return {boolean} True if the size has zero area, false if both dimensions
128 * are non-zero numbers.
129 */
130goog.math.Size.prototype.isEmpty = function() {
131 return !this.area();
132};
133
134
135/**
136 * Clamps the width and height parameters upward to integer values.
137 * @return {!goog.math.Size} This size with ceil'd components.
138 */
139goog.math.Size.prototype.ceil = function() {
140 this.width = Math.ceil(this.width);
141 this.height = Math.ceil(this.height);
142 return this;
143};
144
145
146/**
147 * @param {!goog.math.Size} target The target size.
148 * @return {boolean} True if this Size is the same size or smaller than the
149 * target size in both dimensions.
150 */
151goog.math.Size.prototype.fitsInside = function(target) {
152 return this.width <= target.width && this.height <= target.height;
153};
154
155
156/**
157 * Clamps the width and height parameters downward to integer values.
158 * @return {!goog.math.Size} This size with floored components.
159 */
160goog.math.Size.prototype.floor = function() {
161 this.width = Math.floor(this.width);
162 this.height = Math.floor(this.height);
163 return this;
164};
165
166
167/**
168 * Rounds the width and height parameters to integer values.
169 * @return {!goog.math.Size} This size with rounded components.
170 */
171goog.math.Size.prototype.round = function() {
172 this.width = Math.round(this.width);
173 this.height = Math.round(this.height);
174 return this;
175};
176
177
178/**
179 * Scales this size by the given scale factors. The width and height are scaled
180 * by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} is not
181 * given, then {@code sx} is used for both the width and height.
182 * @param {number} sx The scale factor to use for the width.
183 * @param {number=} opt_sy The scale factor to use for the height.
184 * @return {!goog.math.Size} This Size object after scaling.
185 */
186goog.math.Size.prototype.scale = function(sx, opt_sy) {
187 var sy = goog.isNumber(opt_sy) ? opt_sy : sx;
188 this.width *= sx;
189 this.height *= sy;
190 return this;
191};
192
193
194/**
195 * Uniformly scales the size to perfectly cover the dimensions of a given size.
196 * If the size is already larger than the target, it will be scaled down to the
197 * minimum size at which it still covers the entire target. The original aspect
198 * ratio will be preserved.
199 *
200 * This function assumes that both Sizes contain strictly positive dimensions.
201 * @param {!goog.math.Size} target The target size.
202 * @return {!goog.math.Size} This Size object, after optional scaling.
203 */
204goog.math.Size.prototype.scaleToCover = function(target) {
205 var s = this.aspectRatio() <= target.aspectRatio() ?
206 target.width / this.width :
207 target.height / this.height;
208
209 return this.scale(s);
210};
211
212
213/**
214 * Uniformly scales the size to fit inside the dimensions of a given size. The
215 * original aspect ratio will be preserved.
216 *
217 * This function assumes that both Sizes contain strictly positive dimensions.
218 * @param {!goog.math.Size} target The target size.
219 * @return {!goog.math.Size} This Size object, after optional scaling.
220 */
221goog.math.Size.prototype.scaleToFit = function(target) {
222 var s = this.aspectRatio() > target.aspectRatio() ?
223 target.width / this.width :
224 target.height / this.height;
225
226 return this.scale(s);
227};