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