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