comparison client/digitallibrary/jquery/jquery.digilib.geometry.js @ 785:b9a75079aece jquery

geometry as first digilib plugin. special case that only exports classes.
author robcast
date Wed, 16 Feb 2011 14:31:50 +0100
parents
children 868c2e795aca
comparison
equal deleted inserted replaced
784:dde58c15bbd2 785:b9a75079aece
1 /** required digilib geometry plugin
2 */
3
4 (function($) {
5 //var dlGeometry = function() {
6 /*
7 * Size class
8 */
9 var size = function(w, h) {
10 var that;
11 if (typeof w === "object") {
12 // assume its size
13 that = {
14 width : w.width,
15 height : w.height
16 };
17 } else {
18 that = {
19 width : parseFloat(w),
20 height : parseFloat(h)
21 };
22 }
23 that.equals = function(other) {
24 return (this.width === other.width && this.height === other.height);
25 };
26 that.toString = function() {
27 return (this.width + "x" + this.height);
28 };
29 return that;
30 };
31
32 /*
33 * Position class
34 */
35 var position = function(x, y) {
36 var that;
37 if (typeof x === "object") {
38 if (x instanceof jQuery) {
39 // jQuery object
40 var pos = x.offset();
41 that = {
42 x : pos.left,
43 y : pos.top
44 };
45 } else {
46 if (x.x != null) {
47 // position object
48 that = {
49 x : x.x,
50 y : x.y
51 };
52 }
53 if (x.pageX != null) {
54 // event object
55 that = {
56 x : x.pageX,
57 y : x.pageY
58 };
59 }
60 }
61 } else {
62 that = {
63 x : parseFloat(x),
64 y : parseFloat(y)
65 };
66 }
67 that.equals = function(other) {
68 return (this.x === other.x && this.y === other.y);
69 };
70 // add position other to this
71 that.add = function(other) {
72 this.x += other.x;
73 this.y += other.y;
74 return this;
75 };
76 // returns negative position
77 that.neg = function() {
78 return position({
79 x : -this.x,
80 y : -this.y
81 });
82 };
83 // returns new position that is the difference between this and other
84 that.delta = function(other) {
85 return position({
86 x : other.x - this.x,
87 y : other.y - this.y
88 });
89 };
90 // adjusts position $elem to this position
91 that.adjustDiv = function($elem) {
92 $elem.offset({
93 left : this.x,
94 top : this.y
95 });
96 };
97 // returns distance of this position to pos (length if pos == null)
98 that.distance = function(pos) {
99 if (pos == null) {
100 pos = {
101 x : 0,
102 y : 0
103 };
104 }
105 var dx = pos.x - this.x;
106 var dy = pos.y - this.y;
107 return Math.sqrt(dx * dx + dy * dy);
108 };
109 that.toString = function() {
110 return (this.x + "," + this.y);
111 };
112 return that;
113 };
114 /*
115 * Rectangle class
116 */
117 var rectangle = function(x, y, w, h) {
118 var that = {};
119 if (typeof x === "object") {
120 if (x instanceof jQuery) {
121 // jQuery object
122 var pos = x.offset();
123 that = {
124 x : pos.left,
125 y : pos.top,
126 width : x.width(),
127 height : x.height()
128 };
129 } else if (y == null) {
130 // assume x is rectangle
131 that = {
132 x : x.x,
133 y : x.y,
134 width : x.width,
135 height : x.height
136 };
137 } else {
138 // assume x and y are Position
139 that = {
140 x : Math.min(x.x, y.x),
141 y : Math.min(x.y, y.y),
142 width : Math.abs(y.x - x.x),
143 height : Math.abs(y.y - x.y)
144 };
145 }
146 } else {
147 that = {
148 x : parseFloat(x),
149 y : parseFloat(y),
150 width : parseFloat(w),
151 height : parseFloat(h)
152 };
153 }
154 // returns a copy of this Rectangle
155 that.copy = function() {
156 return rectangle(this);
157 };
158 // returns the position of this Rectangle
159 that.getPosition = function() {
160 return position(this);
161 };
162 // returns the size of this Rectangle
163 that.getSize = function() {
164 return size(this);
165 };
166 // returns the upper left corner position
167 that.getPt1 = that.getPosition;
168 // returns the lower right corner position of this Rectangle
169 that.getPt2 = function() {
170 return position({
171 x : this.x + this.width,
172 y : this.y + this.height
173 });
174 };
175 // sets the upper left corner position to pos
176 that.setPosition = function(pos) {
177 this.x = pos.x;
178 this.y = pos.y;
179 return this;
180 };
181 that.setPt1 = that.setPosition; // TODO: not really the same
182 // adds pos to the position
183 that.addPosition = function(pos) {
184 this.x += pos.x;
185 this.y += pos.y;
186 return this;
187 };
188 // sets the lower right corner to position pos
189 that.setPt2 = function(pos) {
190 this.width = pos.x - this.x;
191 this.height = pos.y - this.y;
192 return this;
193 };
194 // returns the center position of this Rectangle
195 that.getCenter = function() {
196 return position({
197 x : this.x + this.width / 2,
198 y : this.y + this.height / 2
199 });
200 };
201 // moves this Rectangle's center to position pos
202 that.setCenter = function(pos) {
203 this.x = pos.x - this.width / 2;
204 this.y = pos.y - this.height / 2;
205 return this;
206 };
207 that.equals = function(other) {
208 // equal props
209 var eq = (this.x === other.x && this.y === other.y && this.width === other.width);
210 return eq;
211 };
212 // returns the area of this Rectangle
213 that.getArea = function() {
214 return (this.width * this.height);
215 };
216 // eliminates negative width and height
217 that.normalize = function() {
218 var p = this.getPt2();
219 this.x = Math.min(this.x, p.x);
220 this.y = Math.min(this.y, p.y);
221 this.width = Math.abs(this.width);
222 this.height = Math.abs(this.height);
223 return this;
224 };
225 // returns if Position "pos" lies inside of this rectangle
226 that.containsPosition = function(pos) {
227 var ct = ((pos.x >= this.x) && (pos.y >= this.y)
228 && (pos.x <= this.x + this.width) && (pos.y <= this.y
229 + this.height));
230 return ct;
231 };
232 // returns if rectangle "rect" is contained in this rectangle
233 that.containsRect = function(rect) {
234 return (this.containsPosition(rect.getPt1()) && this
235 .containsPosition(rect.getPt2()));
236 };
237 // changes this rectangle's x/y values so it stays inside of rectangle
238 // rect
239 // keeping the proportions
240 that.stayInside = function(rect) {
241 if (this.x < rect.x) {
242 this.x = rect.x;
243 }
244 if (this.y < rect.y) {
245 this.y = rect.y;
246 }
247 if (this.x + this.width > rect.x + rect.width) {
248 this.x = rect.x + rect.width - this.width;
249 }
250 if (this.y + this.height > rect.y + rect.height) {
251 this.y = rect.y + rect.height - this.height;
252 }
253 return this;
254 };
255 // clips this rectangle so it stays inside of rectangle rect
256 that.clipTo = function(rect) {
257 var p1 = rect.getPt1();
258 var p2 = rect.getPt2();
259 var this2 = this.getPt2();
260 this.setPosition(position(Math.max(this.x, p1.x), Math.max(this.y, p1.y)));
261 this.setPt2(position(Math.min(this2.x, p2.x), Math.min(this2.y, p2.y)));
262 return this;
263 };
264 // returns the intersection of the given Rectangle and this one
265 that.intersect = function(rect) {
266 // FIX ME: not really, it should return null if there is no overlap
267 var sec = rect.copy();
268 if (sec.x < this.x) {
269 sec.width = sec.width - (this.x - sec.x);
270 sec.x = this.x;
271 }
272 if (sec.y < this.y) {
273 sec.height = sec.height - (this.y - sec.y);
274 sec.y = this.y;
275 }
276 if (sec.x + sec.width > this.x + this.width) {
277 sec.width = (this.x + this.width) - sec.x;
278 }
279 if (sec.y + sec.height > this.y + this.height) {
280 sec.height = (this.y + this.height) - sec.y;
281 }
282 return sec;
283 };
284 // returns a Rectangle that fits into this one (by moving first)
285 that.fit = function(rect) {
286 var sec = rect.copy();
287 sec.x = Math.max(sec.x, this.x);
288 sec.y = Math.max(sec.y, this.x);
289 if (sec.x + sec.width > this.x + this.width) {
290 sec.x = this.x + this.width - sec.width;
291 }
292 if (sec.y + sec.height > this.y + this.height) {
293 sec.y = this.y + this.height - sec.height;
294 }
295 return sec.intersect(this);
296 };
297 // adjusts position and size of $elem to this rectangle
298 that.adjustDiv = function($elem) {
299 $elem.offset({
300 left : this.x,
301 top : this.y
302 });
303 $elem.width(this.width).height(this.height);
304 };
305 // returns size and position in css-compatible format
306 that.getAsCss = function() {
307 return {
308 left : this.x,
309 top : this.y,
310 width : this.width,
311 height : this.height
312 };
313 };
314 that.toString = function() {
315 return this.width + "x" + this.height + "@" + this.x + "," + this.y;
316 };
317 return that;
318 };
319
320 /*
321 * Transform class
322 *
323 * defines a class of affine transformations
324 */
325 var transform = function(spec) {
326 var that = {
327 m00 : 1.0,
328 m01 : 0.0,
329 m02 : 0.0,
330 m10 : 0.0,
331 m11 : 1.0,
332 m12 : 0.0,
333 m20 : 0.0,
334 m21 : 0.0,
335 m22 : 1.0
336 };
337 if (spec) {
338 jQuery.extend(that, spec);
339 }
340 ;
341 that.concat = function(trafA) {
342 // add Transform trafA to this Transform (i.e. this = trafC = trafA
343 // * this)
344 var trafC = {};
345 for ( var i = 0; i < 3; i++) {
346 for ( var j = 0; j < 3; j++) {
347 var c = 0.0;
348 for ( var k = 0; k < 3; k++) {
349 c += trafA["m" + i + k] * this["m" + k + j];
350 }
351 trafC["m" + i + j] = c;
352 }
353 }
354 jQuery.extend(this, trafC);
355 return this;
356 };
357 that.transform = function(rect) {
358 // returns transformed Rectangle or Position with this Transform
359 // applied
360 var x = this.m00 * rect.x + this.m01 * rect.y + this.m02;
361 var y = this.m10 * rect.x + this.m11 * rect.y + this.m12;
362 var pt = position(x, y);
363 if (rect.width) {
364 // transform the other corner point
365 var pt2 = this.transform(rect.getPt2());
366 return rectangle(pt, pt2);
367 }
368 return pt;
369 };
370 that.invtransform = function(rect) {
371 // returns transformed Rectangle or Position with the inverse of
372 // this Transform applied
373 var det = this.m00 * this.m11 - this.m01 * this.m10;
374 var x = (this.m11 * rect.x - this.m01 * rect.y - this.m11
375 * this.m02 + this.m01 * this.m12)
376 / det;
377 var y = (-this.m10 * rect.x + this.m00 * rect.y + this.m10
378 * this.m02 - this.m00 * this.m12)
379 / det;
380 var pt = position(x, y);
381 if (rect.width) {
382 // transform the other corner point
383 var pt2 = this.invtransform(rect.getPt2());
384 return rectangle(pt, pt2);
385 }
386 return pt;
387 };
388 that.toString = function(pretty) {
389 var s = '[';
390 if (pretty)
391 s += '\n';
392 for ( var i = 0; i < 3; ++i) {
393 s += '[';
394 for ( var j = 0; j < 3; ++j) {
395 if (j)
396 s += ',';
397 s += this['m' + i + j];
398 }
399 s += ']';
400 if (pretty)
401 s += '\n';
402 }
403 s += ']';
404 if (pretty)
405 s += '\n';
406 return s;
407 };
408 // add class methods to instance
409 that.getRotation = transform.getRotation;
410 that.getRotationAround = transform.getRotationAround;
411 that.getTranslation = transform.getTranslation;
412 that.getMirror = transform.getMirror;
413 that.getScale = transform.getScale;
414
415 return that;
416 };
417
418 transform.getRotation = function(angle) {
419 // returns a Transform that is a rotation by angle degrees around [0,0]
420 if (angle !== 0) {
421 var t = Math.PI * parseFloat(angle) / 180.0;
422 var cost = Math.cos(t);
423 var sint = Math.sin(t);
424 var traf = {
425 m00 : cost,
426 m01 : -sint,
427 m10 : sint,
428 m11 : cost
429 };
430 return transform(traf);
431 }
432 return transform();
433 };
434
435 transform.getRotationAround = function(angle, pos) {
436 // returns a Transform that is a rotation by angle degrees around pos
437 var traf = transform.getTranslation(pos.neg());
438 traf.concat(transform.getRotation(angle));
439 traf.concat(transform.getTranslation(pos));
440 return traf;
441 };
442
443 transform.getTranslation = function(pos) {
444 // returns a Transform that is a translation by [pos.x, pos,y]
445 var traf = {
446 m02 : pos.x,
447 m12 : pos.y
448 };
449 return transform(traf);
450 };
451
452 transform.getMirror = function(type) {
453 // returns a Transform that is a mirror about the axis type
454 if (type === 'x') {
455 var traf = {
456 m00 : 1,
457 m11 : -1
458 };
459 } else {
460 var traf = {
461 m00 : -1,
462 m11 : 1
463 };
464 }
465 return transform(traf);
466 };
467
468 transform.getScale = function(size) {
469 // returns a Transform that is a scale by [size.width, size.height]
470 var traf = {
471 m00 : size.width,
472 m11 : size.height
473 };
474 return transform(traf);
475 };
476
477 // export functions to digilib plugin
478 $.fn.digilib.geometry = {
479 size : size,
480 position : position,
481 rectangle : rectangle,
482 transform : transform
483 };
484
485 })(jQuery);