root / trunk / web / dojo / dojox / gfx.js.uncompressed.js @ 11
History | View | Annotate | Download (30.8 KB)
1 | 9 | andrej.cim | /*
|
---|---|---|---|
2 | Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
|
||
3 | Available via Academic Free License >= 2.1 OR the modified BSD license.
|
||
4 | see: http://dojotoolkit.org/license for details
|
||
5 | */
|
||
6 | |||
7 | /*
|
||
8 | This is an optimized version of Dojo, built for deployment and not for
|
||
9 | development. To get sources and documentation, please visit:
|
||
10 | |||
11 | http://dojotoolkit.org
|
||
12 | */
|
||
13 | |||
14 | if(!dojo._hasResource["dojox.gfx.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
||
15 | dojo._hasResource["dojox.gfx.matrix"] = true; |
||
16 | dojo.provide("dojox.gfx.matrix");
|
||
17 | |||
18 | (function(){
|
||
19 | var m = dojox.gfx.matrix;
|
||
20 | |||
21 | // candidates for dojox.math:
|
||
22 | var _degToRadCache = {};
|
||
23 | m._degToRad = function(degree){ |
||
24 | return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180)); |
||
25 | }; |
||
26 | m._radToDeg = function(radian){ return radian / Math.PI * 180; }; |
||
27 | |||
28 | m.Matrix2D = function(arg){ |
||
29 | // summary: a 2D matrix object
|
||
30 | // description: Normalizes a 2D matrix-like object. If arrays is passed,
|
||
31 | // all objects of the array are normalized and multiplied sequentially.
|
||
32 | // arg: Object
|
||
33 | // a 2D matrix-like object, a number, or an array of such objects
|
||
34 | if(arg){
|
||
35 | if(typeof arg == "number"){ |
||
36 | this.xx = this.yy = arg; |
||
37 | }else if(arg instanceof Array){ |
||
38 | if(arg.length > 0){ |
||
39 | var matrix = m.normalize(arg[0]); |
||
40 | // combine matrices
|
||
41 | for(var i = 1; i < arg.length; ++i){ |
||
42 | var l = matrix, r = dojox.gfx.matrix.normalize(arg[i]);
|
||
43 | matrix = new m.Matrix2D();
|
||
44 | matrix.xx = l.xx * r.xx + l.xy * r.yx; |
||
45 | matrix.xy = l.xx * r.xy + l.xy * r.yy; |
||
46 | matrix.yx = l.yx * r.xx + l.yy * r.yx; |
||
47 | matrix.yy = l.yx * r.xy + l.yy * r.yy; |
||
48 | matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx; |
||
49 | matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy; |
||
50 | } |
||
51 | dojo.mixin(this, matrix);
|
||
52 | } |
||
53 | }else{
|
||
54 | dojo.mixin(this, arg);
|
||
55 | } |
||
56 | } |
||
57 | }; |
||
58 | |||
59 | // the default (identity) matrix, which is used to fill in missing values
|
||
60 | dojo.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0}); |
||
61 | |||
62 | dojo.mixin(m, { |
||
63 | // summary: class constants, and methods of dojox.gfx.matrix
|
||
64 | |||
65 | // matrix constants
|
||
66 | |||
67 | // identity: dojox.gfx.matrix.Matrix2D
|
||
68 | // an identity matrix constant: identity * (x, y) == (x, y)
|
||
69 | identity: new m.Matrix2D(), |
||
70 | |||
71 | // flipX: dojox.gfx.matrix.Matrix2D
|
||
72 | // a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y)
|
||
73 | flipX: new m.Matrix2D({xx: -1}), |
||
74 | |||
75 | // flipY: dojox.gfx.matrix.Matrix2D
|
||
76 | // a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y)
|
||
77 | flipY: new m.Matrix2D({yy: -1}), |
||
78 | |||
79 | // flipXY: dojox.gfx.matrix.Matrix2D
|
||
80 | // a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y)
|
||
81 | flipXY: new m.Matrix2D({xx: -1, yy: -1}), |
||
82 | |||
83 | // matrix creators
|
||
84 | |||
85 | translate: function(a, b){ |
||
86 | // summary: forms a translation matrix
|
||
87 | // description: The resulting matrix is used to translate (move) points by specified offsets.
|
||
88 | // a: Number: an x coordinate value
|
||
89 | // b: Number: a y coordinate value
|
||
90 | if(arguments.length > 1){ |
||
91 | return new m.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D |
||
92 | } |
||
93 | // branch
|
||
94 | // a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions
|
||
95 | // b: null
|
||
96 | return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D |
||
97 | }, |
||
98 | scale: function(a, b){ |
||
99 | // summary: forms a scaling matrix
|
||
100 | // description: The resulting matrix is used to scale (magnify) points by specified offsets.
|
||
101 | // a: Number: a scaling factor used for the x coordinate
|
||
102 | // b: Number: a scaling factor used for the y coordinate
|
||
103 | if(arguments.length > 1){ |
||
104 | return new m.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D |
||
105 | } |
||
106 | if(typeof a == "number"){ |
||
107 | // branch
|
||
108 | // a: Number: a uniform scaling factor used for the both coordinates
|
||
109 | // b: null
|
||
110 | return new m.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D |
||
111 | } |
||
112 | // branch
|
||
113 | // a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions
|
||
114 | // b: null
|
||
115 | return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D |
||
116 | }, |
||
117 | rotate: function(angle){ |
||
118 | // summary: forms a rotating matrix
|
||
119 | // description: The resulting matrix is used to rotate points
|
||
120 | // around the origin of coordinates (0, 0) by specified angle.
|
||
121 | // angle: Number: an angle of rotation in radians (>0 for CW)
|
||
122 | var c = Math.cos(angle);
|
||
123 | var s = Math.sin(angle);
|
||
124 | return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx.matrix.Matrix2D |
||
125 | }, |
||
126 | rotateg: function(degree){ |
||
127 | // summary: forms a rotating matrix
|
||
128 | // description: The resulting matrix is used to rotate points
|
||
129 | // around the origin of coordinates (0, 0) by specified degree.
|
||
130 | // See dojox.gfx.matrix.rotate() for comparison.
|
||
131 | // degree: Number: an angle of rotation in degrees (>0 for CW)
|
||
132 | return m.rotate(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
||
133 | }, |
||
134 | skewX: function(angle) { |
||
135 | // summary: forms an x skewing matrix
|
||
136 | // description: The resulting matrix is used to skew points in the x dimension
|
||
137 | // around the origin of coordinates (0, 0) by specified angle.
|
||
138 | // angle: Number: an skewing angle in radians
|
||
139 | return new m.Matrix2D({xy: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D |
||
140 | }, |
||
141 | skewXg: function(degree){ |
||
142 | // summary: forms an x skewing matrix
|
||
143 | // description: The resulting matrix is used to skew points in the x dimension
|
||
144 | // around the origin of coordinates (0, 0) by specified degree.
|
||
145 | // See dojox.gfx.matrix.skewX() for comparison.
|
||
146 | // degree: Number: an skewing angle in degrees
|
||
147 | return m.skewX(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
||
148 | }, |
||
149 | skewY: function(angle){ |
||
150 | // summary: forms a y skewing matrix
|
||
151 | // description: The resulting matrix is used to skew points in the y dimension
|
||
152 | // around the origin of coordinates (0, 0) by specified angle.
|
||
153 | // angle: Number: an skewing angle in radians
|
||
154 | return new m.Matrix2D({yx: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D |
||
155 | }, |
||
156 | skewYg: function(degree){ |
||
157 | // summary: forms a y skewing matrix
|
||
158 | // description: The resulting matrix is used to skew points in the y dimension
|
||
159 | // around the origin of coordinates (0, 0) by specified degree.
|
||
160 | // See dojox.gfx.matrix.skewY() for comparison.
|
||
161 | // degree: Number: an skewing angle in degrees
|
||
162 | return m.skewY(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
||
163 | }, |
||
164 | reflect: function(a, b){ |
||
165 | // summary: forms a reflection matrix
|
||
166 | // description: The resulting matrix is used to reflect points around a vector,
|
||
167 | // which goes through the origin.
|
||
168 | // a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection
|
||
169 | // b: null
|
||
170 | if(arguments.length == 1){ |
||
171 | b = a.y; |
||
172 | a = a.x; |
||
173 | } |
||
174 | // branch
|
||
175 | // a: Number: an x coordinate value
|
||
176 | // b: Number: a y coordinate value
|
||
177 | |||
178 | // make a unit vector
|
||
179 | var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2; |
||
180 | return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox.gfx.matrix.Matrix2D |
||
181 | }, |
||
182 | project: function(a, b){ |
||
183 | // summary: forms an orthogonal projection matrix
|
||
184 | // description: The resulting matrix is used to project points orthogonally on a vector,
|
||
185 | // which goes through the origin.
|
||
186 | // a: dojox.gfx.Point: a point-like object, which specifies a vector of projection
|
||
187 | // b: null
|
||
188 | if(arguments.length == 1){ |
||
189 | b = a.y; |
||
190 | a = a.x; |
||
191 | } |
||
192 | // branch
|
||
193 | // a: Number: an x coordinate value
|
||
194 | // b: Number: a y coordinate value
|
||
195 | |||
196 | // make a unit vector
|
||
197 | var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2;
|
||
198 | return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox.gfx.matrix.Matrix2D |
||
199 | }, |
||
200 | |||
201 | // ensure matrix 2D conformance
|
||
202 | normalize: function(matrix){ |
||
203 | // summary: converts an object to a matrix, if necessary
|
||
204 | // description: Converts any 2D matrix-like object or an array of
|
||
205 | // such objects to a valid dojox.gfx.matrix.Matrix2D object.
|
||
206 | // matrix: Object: an object, which is converted to a matrix, if necessary
|
||
207 | return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D |
||
208 | }, |
||
209 | |||
210 | // common operations
|
||
211 | |||
212 | clone: function(matrix){ |
||
213 | // summary: creates a copy of a 2D matrix
|
||
214 | // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned
|
||
215 | var obj = new m.Matrix2D(); |
||
216 | for(var i in matrix){ |
||
217 | if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i]; |
||
218 | } |
||
219 | return obj; // dojox.gfx.matrix.Matrix2D |
||
220 | }, |
||
221 | invert: function(matrix){ |
||
222 | // summary: inverts a 2D matrix
|
||
223 | // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted
|
||
224 | var M = m.normalize(matrix),
|
||
225 | D = M.xx * M.yy - M.xy * M.yx, |
||
226 | M = new m.Matrix2D({
|
||
227 | xx: M.yy/D, xy: -M.xy/D, |
||
228 | yx: -M.yx/D, yy: M.xx/D, |
||
229 | dx: (M.xy * M.dy - M.yy * M.dx) / D,
|
||
230 | dy: (M.yx * M.dx - M.xx * M.dy) / D
|
||
231 | }); |
||
232 | return M; // dojox.gfx.matrix.Matrix2D |
||
233 | }, |
||
234 | _multiplyPoint: function(matrix, x, y){ |
||
235 | // summary: applies a matrix to a point
|
||
236 | // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
|
||
237 | // x: Number: an x coordinate of a point
|
||
238 | // y: Number: a y coordinate of a point
|
||
239 | return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox.gfx.Point |
||
240 | }, |
||
241 | multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b){ |
||
242 | // summary: applies a matrix to a point
|
||
243 | // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
|
||
244 | // a: Number: an x coordinate of a point
|
||
245 | // b: Number: a y coordinate of a point
|
||
246 | var M = m.normalize(matrix);
|
||
247 | if(typeof a == "number" && typeof b == "number"){ |
||
248 | return m._multiplyPoint(M, a, b); // dojox.gfx.Point |
||
249 | } |
||
250 | // branch
|
||
251 | // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
|
||
252 | // a: dojox.gfx.Point: a point
|
||
253 | // b: null
|
||
254 | return m._multiplyPoint(M, a.x, a.y); // dojox.gfx.Point |
||
255 | }, |
||
256 | multiply: function(matrix){ |
||
257 | // summary: combines matrices by multiplying them sequentially in the given order
|
||
258 | // matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object,
|
||
259 | // all subsequent arguments are matrix-like objects too
|
||
260 | var M = m.normalize(matrix);
|
||
261 | // combine matrices
|
||
262 | for(var i = 1; i < arguments.length; ++i){ |
||
263 | var l = M, r = m.normalize(arguments[i]); |
||
264 | M = new m.Matrix2D();
|
||
265 | M.xx = l.xx * r.xx + l.xy * r.yx; |
||
266 | M.xy = l.xx * r.xy + l.xy * r.yy; |
||
267 | M.yx = l.yx * r.xx + l.yy * r.yx; |
||
268 | M.yy = l.yx * r.xy + l.yy * r.yy; |
||
269 | M.dx = l.xx * r.dx + l.xy * r.dy + l.dx; |
||
270 | M.dy = l.yx * r.dx + l.yy * r.dy + l.dy; |
||
271 | } |
||
272 | return M; // dojox.gfx.matrix.Matrix2D |
||
273 | }, |
||
274 | |||
275 | // high level operations
|
||
276 | |||
277 | _sandwich: function(matrix, x, y){ |
||
278 | // summary: applies a matrix at a centrtal point
|
||
279 | // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point
|
||
280 | // x: Number: an x component of the central point
|
||
281 | // y: Number: a y component of the central point
|
||
282 | return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D |
||
283 | }, |
||
284 | scaleAt: function(a, b, c, d){ |
||
285 | // summary: scales a picture using a specified point as a center of scaling
|
||
286 | // description: Compare with dojox.gfx.matrix.scale().
|
||
287 | // a: Number: a scaling factor used for the x coordinate
|
||
288 | // b: Number: a scaling factor used for the y coordinate
|
||
289 | // c: Number: an x component of a central point
|
||
290 | // d: Number: a y component of a central point
|
||
291 | |||
292 | // accepts several signatures:
|
||
293 | // 1) uniform scale factor, Point
|
||
294 | // 2) uniform scale factor, x, y
|
||
295 | // 3) x scale, y scale, Point
|
||
296 | // 4) x scale, y scale, x, y
|
||
297 | |||
298 | switch(arguments.length){ |
||
299 | case 4: |
||
300 | // a and b are scale factor components, c and d are components of a point
|
||
301 | return m._sandwich(m.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D |
||
302 | case 3: |
||
303 | if(typeof c == "number"){ |
||
304 | // branch
|
||
305 | // a: Number: a uniform scaling factor used for both coordinates
|
||
306 | // b: Number: an x component of a central point
|
||
307 | // c: Number: a y component of a central point
|
||
308 | // d: null
|
||
309 | return m._sandwich(m.scale(a), b, c); // dojox.gfx.matrix.Matrix2D |
||
310 | } |
||
311 | // branch
|
||
312 | // a: Number: a scaling factor used for the x coordinate
|
||
313 | // b: Number: a scaling factor used for the y coordinate
|
||
314 | // c: dojox.gfx.Point: a central point
|
||
315 | // d: null
|
||
316 | return m._sandwich(m.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D |
||
317 | } |
||
318 | // branch
|
||
319 | // a: Number: a uniform scaling factor used for both coordinates
|
||
320 | // b: dojox.gfx.Point: a central point
|
||
321 | // c: null
|
||
322 | // d: null
|
||
323 | return m._sandwich(m.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D |
||
324 | }, |
||
325 | rotateAt: function(angle, a, b){ |
||
326 | // summary: rotates a picture using a specified point as a center of rotation
|
||
327 | // description: Compare with dojox.gfx.matrix.rotate().
|
||
328 | // angle: Number: an angle of rotation in radians (>0 for CW)
|
||
329 | // a: Number: an x component of a central point
|
||
330 | // b: Number: a y component of a central point
|
||
331 | |||
332 | // accepts several signatures:
|
||
333 | // 1) rotation angle in radians, Point
|
||
334 | // 2) rotation angle in radians, x, y
|
||
335 | |||
336 | if(arguments.length > 2){ |
||
337 | return m._sandwich(m.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D |
||
338 | } |
||
339 | |||
340 | // branch
|
||
341 | // angle: Number: an angle of rotation in radians (>0 for CCW)
|
||
342 | // a: dojox.gfx.Point: a central point
|
||
343 | // b: null
|
||
344 | return m._sandwich(m.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
||
345 | }, |
||
346 | rotategAt: function(degree, a, b){ |
||
347 | // summary: rotates a picture using a specified point as a center of rotation
|
||
348 | // description: Compare with dojox.gfx.matrix.rotateg().
|
||
349 | // degree: Number: an angle of rotation in degrees (>0 for CW)
|
||
350 | // a: Number: an x component of a central point
|
||
351 | // b: Number: a y component of a central point
|
||
352 | |||
353 | // accepts several signatures:
|
||
354 | // 1) rotation angle in degrees, Point
|
||
355 | // 2) rotation angle in degrees, x, y
|
||
356 | |||
357 | if(arguments.length > 2){ |
||
358 | return m._sandwich(m.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
||
359 | } |
||
360 | |||
361 | // branch
|
||
362 | // degree: Number: an angle of rotation in degrees (>0 for CCW)
|
||
363 | // a: dojox.gfx.Point: a central point
|
||
364 | // b: null
|
||
365 | return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
||
366 | }, |
||
367 | skewXAt: function(angle, a, b){ |
||
368 | // summary: skews a picture along the x axis using a specified point as a center of skewing
|
||
369 | // description: Compare with dojox.gfx.matrix.skewX().
|
||
370 | // angle: Number: an skewing angle in radians
|
||
371 | // a: Number: an x component of a central point
|
||
372 | // b: Number: a y component of a central point
|
||
373 | |||
374 | // accepts several signatures:
|
||
375 | // 1) skew angle in radians, Point
|
||
376 | // 2) skew angle in radians, x, y
|
||
377 | |||
378 | if(arguments.length > 2){ |
||
379 | return m._sandwich(m.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D |
||
380 | } |
||
381 | |||
382 | // branch
|
||
383 | // angle: Number: an skewing angle in radians
|
||
384 | // a: dojox.gfx.Point: a central point
|
||
385 | // b: null
|
||
386 | return m._sandwich(m.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
||
387 | }, |
||
388 | skewXgAt: function(degree, a, b){ |
||
389 | // summary: skews a picture along the x axis using a specified point as a center of skewing
|
||
390 | // description: Compare with dojox.gfx.matrix.skewXg().
|
||
391 | // degree: Number: an skewing angle in degrees
|
||
392 | // a: Number: an x component of a central point
|
||
393 | // b: Number: a y component of a central point
|
||
394 | |||
395 | // accepts several signatures:
|
||
396 | // 1) skew angle in degrees, Point
|
||
397 | // 2) skew angle in degrees, x, y
|
||
398 | |||
399 | if(arguments.length > 2){ |
||
400 | return m._sandwich(m.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
||
401 | } |
||
402 | |||
403 | // branch
|
||
404 | // degree: Number: an skewing angle in degrees
|
||
405 | // a: dojox.gfx.Point: a central point
|
||
406 | // b: null
|
||
407 | return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
||
408 | }, |
||
409 | skewYAt: function(angle, a, b){ |
||
410 | // summary: skews a picture along the y axis using a specified point as a center of skewing
|
||
411 | // description: Compare with dojox.gfx.matrix.skewY().
|
||
412 | // angle: Number: an skewing angle in radians
|
||
413 | // a: Number: an x component of a central point
|
||
414 | // b: Number: a y component of a central point
|
||
415 | |||
416 | // accepts several signatures:
|
||
417 | // 1) skew angle in radians, Point
|
||
418 | // 2) skew angle in radians, x, y
|
||
419 | |||
420 | if(arguments.length > 2){ |
||
421 | return m._sandwich(m.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D |
||
422 | } |
||
423 | |||
424 | // branch
|
||
425 | // angle: Number: an skewing angle in radians
|
||
426 | // a: dojox.gfx.Point: a central point
|
||
427 | // b: null
|
||
428 | return m._sandwich(m.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
||
429 | }, |
||
430 | skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){ |
||
431 | // summary: skews a picture along the y axis using a specified point as a center of skewing
|
||
432 | // description: Compare with dojox.gfx.matrix.skewYg().
|
||
433 | // degree: Number: an skewing angle in degrees
|
||
434 | // a: Number: an x component of a central point
|
||
435 | // b: Number: a y component of a central point
|
||
436 | |||
437 | // accepts several signatures:
|
||
438 | // 1) skew angle in degrees, Point
|
||
439 | // 2) skew angle in degrees, x, y
|
||
440 | |||
441 | if(arguments.length > 2){ |
||
442 | return m._sandwich(m.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
||
443 | } |
||
444 | |||
445 | // branch
|
||
446 | // degree: Number: an skewing angle in degrees
|
||
447 | // a: dojox.gfx.Point: a central point
|
||
448 | // b: null
|
||
449 | return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
||
450 | } |
||
451 | |||
452 | //TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions)
|
||
453 | |||
454 | }); |
||
455 | })(); |
||
456 | |||
457 | // propagate Matrix2D up
|
||
458 | dojox.gfx.Matrix2D = dojox.gfx.matrix.Matrix2D; |
||
459 | |||
460 | } |
||
461 | |||
462 | if(!dojo._hasResource["dojox.gfx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
||
463 | dojo._hasResource["dojox.gfx._base"] = true; |
||
464 | dojo.provide("dojox.gfx._base");
|
||
465 | |||
466 | (function(){
|
||
467 | var g = dojox.gfx, b = g._base;
|
||
468 | |||
469 | // candidates for dojox.style (work on VML and SVG nodes)
|
||
470 | g._hasClass = function(/*DomNode*/node, /*String*/classStr){ |
||
471 | // summary:
|
||
472 | // Returns whether or not the specified classes are a portion of the
|
||
473 | // class list currently applied to the node.
|
||
474 | // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean
|
||
475 | var cls = node.getAttribute("className"); |
||
476 | return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0; // Boolean |
||
477 | } |
||
478 | g._addClass = function(/*DomNode*/node, /*String*/classStr){ |
||
479 | // summary:
|
||
480 | // Adds the specified classes to the end of the class list on the
|
||
481 | // passed node.
|
||
482 | var cls = node.getAttribute("className") || ""; |
||
483 | if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){ |
||
484 | node.setAttribute("className", cls + (cls ? " " : "") + classStr); |
||
485 | } |
||
486 | } |
||
487 | g._removeClass = function(/*DomNode*/node, /*String*/classStr){ |
||
488 | // summary: Removes classes from node.
|
||
489 | var cls = node.getAttribute("className"); |
||
490 | if(cls){
|
||
491 | node.setAttribute( |
||
492 | "className",
|
||
493 | cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2") |
||
494 | ); |
||
495 | } |
||
496 | } |
||
497 | |||
498 | // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here)
|
||
499 | |||
500 | // derived from Morris John's emResized measurer
|
||
501 | b._getFontMeasurements = function(){ |
||
502 | // summary:
|
||
503 | // Returns an object that has pixel equivilents of standard font
|
||
504 | // size values.
|
||
505 | var heights = {
|
||
506 | '1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0, |
||
507 | 'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0, |
||
508 | 'xx-large': 0 |
||
509 | }; |
||
510 | |||
511 | if(dojo.isIE){
|
||
512 | // we do a font-size fix if and only if one isn't applied already.
|
||
513 | // NOTE: If someone set the fontSize on the HTML Element, this will kill it.
|
||
514 | dojo.doc.documentElement.style.fontSize="100%";
|
||
515 | } |
||
516 | |||
517 | // set up the measuring node.
|
||
518 | var div = dojo.doc.createElement("div"); |
||
519 | var s = div.style;
|
||
520 | s.position = "absolute";
|
||
521 | s.left = "-100px";
|
||
522 | s.top = "0px";
|
||
523 | s.width = "30px";
|
||
524 | s.height = "1000em";
|
||
525 | s.borderWidth = "0px";
|
||
526 | s.margin = "0px";
|
||
527 | s.padding = "0px";
|
||
528 | s.outline = "none";
|
||
529 | s.lineHeight = "1";
|
||
530 | s.overflow = "hidden";
|
||
531 | dojo.body().appendChild(div); |
||
532 | |||
533 | // do the measurements.
|
||
534 | for(var p in heights){ |
||
535 | div.style.fontSize = p; |
||
536 | heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000; |
||
537 | } |
||
538 | |||
539 | dojo.body().removeChild(div); |
||
540 | div = null;
|
||
541 | return heights; // object |
||
542 | }; |
||
543 | |||
544 | var fontMeasurements = null; |
||
545 | |||
546 | b._getCachedFontMeasurements = function(recalculate){ |
||
547 | if(recalculate || !fontMeasurements){
|
||
548 | fontMeasurements = b._getFontMeasurements(); |
||
549 | } |
||
550 | return fontMeasurements;
|
||
551 | }; |
||
552 | |||
553 | // candidate for dojox.html.metrics
|
||
554 | |||
555 | var measuringNode = null, empty = {}; |
||
556 | b._getTextBox = function( /*String*/ text, |
||
557 | /*Object*/ style,
|
||
558 | /*String?*/ className){
|
||
559 | var m, s, al = arguments.length; |
||
560 | if(!measuringNode){
|
||
561 | m = measuringNode = dojo.doc.createElement("div");
|
||
562 | s = m.style; |
||
563 | s.position = "absolute";
|
||
564 | s.left = "-10000px";
|
||
565 | s.top = "0";
|
||
566 | dojo.body().appendChild(m); |
||
567 | }else{
|
||
568 | m = measuringNode; |
||
569 | s = m.style; |
||
570 | } |
||
571 | // reset styles
|
||
572 | m.className = "";
|
||
573 | s.borderWidth = "0";
|
||
574 | s.margin = "0";
|
||
575 | s.padding = "0";
|
||
576 | s.outline = "0";
|
||
577 | // set new style
|
||
578 | if(al > 1 && style){ |
||
579 | for(var i in style){ |
||
580 | if(i in empty){ continue; } |
||
581 | s[i] = style[i]; |
||
582 | } |
||
583 | } |
||
584 | // set classes
|
||
585 | if(al > 2 && className){ |
||
586 | m.className = className; |
||
587 | } |
||
588 | // take a measure
|
||
589 | m.innerHTML = text; |
||
590 | |||
591 | if(m["getBoundingClientRect"]){ |
||
592 | var bcr = m.getBoundingClientRect();
|
||
593 | return {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)}; |
||
594 | }else{
|
||
595 | return dojo.marginBox(m);
|
||
596 | } |
||
597 | }; |
||
598 | |||
599 | // candidate for dojo.dom
|
||
600 | |||
601 | var uniqueId = 0; |
||
602 | b._getUniqueId = function(){ |
||
603 | // summary: returns a unique string for use with any DOM element
|
||
604 | var id;
|
||
605 | do{
|
||
606 | id = dojo._scopeName + "Unique" + (++uniqueId);
|
||
607 | }while(dojo.byId(id));
|
||
608 | return id;
|
||
609 | }; |
||
610 | })(); |
||
611 | |||
612 | dojo.mixin(dojox.gfx, { |
||
613 | // summary:
|
||
614 | // defines constants, prototypes, and utility functions
|
||
615 | |||
616 | // default shapes, which are used to fill in missing parameters
|
||
617 | defaultPath: {
|
||
618 | type: "path", path: "" |
||
619 | }, |
||
620 | defaultPolyline: {
|
||
621 | type: "polyline", points: [] |
||
622 | }, |
||
623 | defaultRect: {
|
||
624 | type: "rect", x: 0, y: 0, width: 100, height: 100, r: 0 |
||
625 | }, |
||
626 | defaultEllipse: {
|
||
627 | type: "ellipse", cx: 0, cy: 0, rx: 200, ry: 100 |
||
628 | }, |
||
629 | defaultCircle: {
|
||
630 | type: "circle", cx: 0, cy: 0, r: 100 |
||
631 | }, |
||
632 | defaultLine: {
|
||
633 | type: "line", x1: 0, y1: 0, x2: 100, y2: 100 |
||
634 | }, |
||
635 | defaultImage: {
|
||
636 | type: "image", x: 0, y: 0, width: 0, height: 0, src: "" |
||
637 | }, |
||
638 | defaultText: {
|
||
639 | type: "text", x: 0, y: 0, text: "", align: "start", |
||
640 | decoration: "none", rotated: false, kerning: true |
||
641 | }, |
||
642 | defaultTextPath: {
|
||
643 | type: "textpath", text: "", align: "start", |
||
644 | decoration: "none", rotated: false, kerning: true |
||
645 | }, |
||
646 | |||
647 | // default geometric attributes
|
||
648 | defaultStroke: {
|
||
649 | type: "stroke", color: "black", style: "solid", width: 1, |
||
650 | cap: "butt", join: 4 |
||
651 | }, |
||
652 | defaultLinearGradient: {
|
||
653 | type: "linear", x1: 0, y1: 0, x2: 100, y2: 100, |
||
654 | colors: [
|
||
655 | { offset: 0, color: "black" }, { offset: 1, color: "white" } |
||
656 | ] |
||
657 | }, |
||
658 | defaultRadialGradient: {
|
||
659 | type: "radial", cx: 0, cy: 0, r: 100, |
||
660 | colors: [
|
||
661 | { offset: 0, color: "black" }, { offset: 1, color: "white" } |
||
662 | ] |
||
663 | }, |
||
664 | defaultPattern: {
|
||
665 | type: "pattern", x: 0, y: 0, width: 0, height: 0, src: "" |
||
666 | }, |
||
667 | defaultFont: {
|
||
668 | type: "font", style: "normal", variant: "normal", |
||
669 | weight: "normal", size: "10pt", family: "serif" |
||
670 | }, |
||
671 | |||
672 | getDefault: (function(){ |
||
673 | var typeCtorCache = {};
|
||
674 | // a memoized delegate()
|
||
675 | return function(/*String*/ type){ |
||
676 | var t = typeCtorCache[type];
|
||
677 | if(t){
|
||
678 | return new t(); |
||
679 | } |
||
680 | t = typeCtorCache[type] = new Function;
|
||
681 | t.prototype = dojox.gfx[ "default" + type ];
|
||
682 | return new t(); |
||
683 | } |
||
684 | })(), |
||
685 | |||
686 | normalizeColor: function(/*Color*/ color){ |
||
687 | // summary:
|
||
688 | // converts any legal color representation to normalized
|
||
689 | // dojo.Color object
|
||
690 | return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color |
||
691 | }, |
||
692 | normalizeParameters: function(existed, update){ |
||
693 | // summary:
|
||
694 | // updates an existing object with properties from an "update"
|
||
695 | // object
|
||
696 | // existed: Object
|
||
697 | // the "target" object to be updated
|
||
698 | // update: Object
|
||
699 | // the "update" object, whose properties will be used to update
|
||
700 | // the existed object
|
||
701 | if(update){
|
||
702 | var empty = {};
|
||
703 | for(var x in existed){ |
||
704 | if(x in update && !(x in empty)){ |
||
705 | existed[x] = update[x]; |
||
706 | } |
||
707 | } |
||
708 | } |
||
709 | return existed; // Object |
||
710 | }, |
||
711 | makeParameters: function(defaults, update){ |
||
712 | // summary:
|
||
713 | // copies the original object, and all copied properties from the
|
||
714 | // "update" object
|
||
715 | // defaults: Object
|
||
716 | // the object to be cloned before updating
|
||
717 | // update: Object
|
||
718 | // the object, which properties are to be cloned during updating
|
||
719 | if(!update){
|
||
720 | // return dojo.clone(defaults);
|
||
721 | return dojo.delegate(defaults);
|
||
722 | } |
||
723 | var result = {};
|
||
724 | for(var i in defaults){ |
||
725 | if(!(i in result)){ |
||
726 | result[i] = dojo.clone((i in update) ? update[i] : defaults[i]);
|
||
727 | } |
||
728 | } |
||
729 | return result; // Object |
||
730 | }, |
||
731 | formatNumber: function(x, addSpace){ |
||
732 | // summary: converts a number to a string using a fixed notation
|
||
733 | // x: Number: number to be converted
|
||
734 | // addSpace: Boolean?: if it is true, add a space before a positive number
|
||
735 | var val = x.toString();
|
||
736 | if(val.indexOf("e") >= 0){ |
||
737 | val = x.toFixed(4);
|
||
738 | }else{
|
||
739 | var point = val.indexOf("."); |
||
740 | if(point >= 0 && val.length - point > 5){ |
||
741 | val = x.toFixed(4);
|
||
742 | } |
||
743 | } |
||
744 | if(x < 0){ |
||
745 | return val; // String |
||
746 | } |
||
747 | return addSpace ? " " + val : val; // String |
||
748 | }, |
||
749 | // font operations
|
||
750 | makeFontString: function(font){ |
||
751 | // summary: converts a font object to a CSS font string
|
||
752 | // font: Object: font object (see dojox.gfx.defaultFont)
|
||
753 | return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object |
||
754 | }, |
||
755 | splitFontString: function(str){ |
||
756 | // summary:
|
||
757 | // converts a CSS font string to a font object
|
||
758 | // description:
|
||
759 | // Converts a CSS font string to a gfx font object. The CSS font
|
||
760 | // string components should follow the W3C specified order
|
||
761 | // (see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand):
|
||
762 | // style, variant, weight, size, optional line height (will be
|
||
763 | // ignored), and family.
|
||
764 | // str: String
|
||
765 | // a CSS font string
|
||
766 | var font = dojox.gfx.getDefault("Font"); |
||
767 | var t = str.split(/\s+/); |
||
768 | do{
|
||
769 | if(t.length < 5){ break; } |
||
770 | font.style = t[0];
|
||
771 | font.variant = t[1];
|
||
772 | font.weight = t[2];
|
||
773 | var i = t[3].indexOf("/"); |
||
774 | font.size = i < 0 ? t[3] : t[3].substring(0, i); |
||
775 | var j = 4; |
||
776 | if(i < 0){ |
||
777 | if(t[4] == "/"){ |
||
778 | j = 6;
|
||
779 | }else if(t[4].charAt(0) == "/"){ |
||
780 | j = 5;
|
||
781 | } |
||
782 | } |
||
783 | if(j < t.length){
|
||
784 | font.family = t.slice(j).join(" ");
|
||
785 | } |
||
786 | }while(false); |
||
787 | return font; // Object |
||
788 | }, |
||
789 | // length operations
|
||
790 | cm_in_pt: 72 / 2.54, // Number: points per centimeter |
||
791 | mm_in_pt: 7.2 / 2.54, // Number: points per millimeter |
||
792 | px_in_pt: function(){ |
||
793 | // summary: returns a number of pixels per point
|
||
794 | return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12; // Number |
||
795 | }, |
||
796 | pt2px: function(len){ |
||
797 | // summary: converts points to pixels
|
||
798 | // len: Number: a value in points
|
||
799 | return len * dojox.gfx.px_in_pt(); // Number |
||
800 | }, |
||
801 | px2pt: function(len){ |
||
802 | // summary: converts pixels to points
|
||
803 | // len: Number: a value in pixels
|
||
804 | return len / dojox.gfx.px_in_pt(); // Number |
||
805 | }, |
||
806 | normalizedLength: function(len) { |
||
807 | // summary: converts any length value to pixels
|
||
808 | // len: String: a length, e.g., "12pc"
|
||
809 | if(len.length == 0) return 0; |
||
810 | if(len.length > 2){ |
||
811 | var px_in_pt = dojox.gfx.px_in_pt();
|
||
812 | var val = parseFloat(len);
|
||
813 | switch(len.slice(-2)){ |
||
814 | case "px": return val; |
||
815 | case "pt": return val * px_in_pt; |
||
816 | case "in": return val * 72 * px_in_pt; |
||
817 | case "pc": return val * 12 * px_in_pt; |
||
818 | case "mm": return val * dojox.gfx.mm_in_pt * px_in_pt; |
||
819 | case "cm": return val * dojox.gfx.cm_in_pt * px_in_pt; |
||
820 | } |
||
821 | } |
||
822 | return parseFloat(len); // Number |
||
823 | }, |
||
824 | |||
825 | // a constant used to split a SVG/VML path into primitive components
|
||
826 | pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, |
||
827 | pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, |
||
828 | |||
829 | equalSources: function(a, b){ |
||
830 | // summary: compares event sources, returns true if they are equal
|
||
831 | return a && b && a == b;
|
||
832 | } |
||
833 | }); |
||
834 | |||
835 | } |
||
836 | |||
837 | if(!dojo._hasResource["dojox.gfx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
||
838 | dojo._hasResource["dojox.gfx"] = true; |
||
839 | dojo.provide("dojox.gfx");
|
||
840 | |||
841 | |||
842 | |||
843 | |||
844 | dojo.loadInit(function(){
|
||
845 | //Since loaderInit can be fired before any dojo.provide/require calls,
|
||
846 | //make sure the dojox.gfx object exists and only run this logic if dojox.gfx.renderer
|
||
847 | //has not been defined yet.
|
||
848 | var gfx = dojo.getObject("dojox.gfx", true), sl, flag, match; |
||
849 | if(!gfx.renderer){
|
||
850 | //Have a way to force a GFX renderer, if so desired.
|
||
851 | //Useful for being able to serialize GFX data in a particular format.
|
||
852 | if(dojo.config.forceGfxRenderer){
|
||
853 | dojox.gfx.renderer = dojo.config.forceGfxRenderer; |
||
854 | return;
|
||
855 | } |
||
856 | var renderers = (typeof dojo.config.gfxRenderer == "string" ? |
||
857 | dojo.config.gfxRenderer : "svg,vml,silverlight,canvas").split(","); |
||
858 | |||
859 | // mobile platform detection
|
||
860 | // TODO: move to the base?
|
||
861 | |||
862 | var ua = navigator.userAgent, iPhoneOsBuild = 0, androidVersion = 0; |
||
863 | if(dojo.isSafari >= 3){ |
||
864 | // detect mobile version of WebKit starting with "version 3"
|
||
865 | |||
866 | // comprehensive iPhone test. Have to figure out whether it's SVG or Canvas based on the build.
|
||
867 | // iPhone OS build numbers from en.wikipedia.org.
|
||
868 | if(ua.indexOf("iPhone") >= 0 || ua.indexOf("iPod") >= 0){ |
||
869 | // grab the build out of this. Expression is a little nasty because we want
|
||
870 | // to be sure we have the whole version string.
|
||
871 | match = ua.match(/Version\/(\d(\.\d)?(\.\d)?)\sMobile\/([^\s]*)\s?/);
|
||
872 | if(match){
|
||
873 | // grab the build out of the match. Only use the first three because of specific builds.
|
||
874 | iPhoneOsBuild = parseInt(match[4].substr(0,3), 16); |
||
875 | } |
||
876 | } |
||
877 | } |
||
878 | if(dojo.isWebKit){
|
||
879 | // Android detection
|
||
880 | if(!iPhoneOsBuild){
|
||
881 | match = ua.match(/Android\s+(\d+\.\d+)/);
|
||
882 | if(match){
|
||
883 | androidVersion = parseFloat(match[1]);
|
||
884 | // Android 1.0-1.1 doesn't support SVG but supports Canvas
|
||
885 | } |
||
886 | } |
||
887 | } |
||
888 | |||
889 | for(var i = 0; i < renderers.length; ++i){ |
||
890 | switch(renderers[i]){
|
||
891 | case "svg": |
||
892 | // iPhone OS builds greater than 5F1 should have SVG.
|
||
893 | if(!dojo.isIE && (!iPhoneOsBuild || iPhoneOsBuild >= 0x5f1) && !androidVersion && !dojo.isAIR){ |
||
894 | dojox.gfx.renderer = "svg";
|
||
895 | } |
||
896 | break;
|
||
897 | case "vml": |
||
898 | if(dojo.isIE){
|
||
899 | dojox.gfx.renderer = "vml";
|
||
900 | } |
||
901 | break;
|
||
902 | case "silverlight": |
||
903 | try{
|
||
904 | if(dojo.isIE){
|
||
905 | sl = new ActiveXObject("AgControl.AgControl"); |
||
906 | if(sl && sl.IsVersionSupported("1.0")){ |
||
907 | flag = true;
|
||
908 | } |
||
909 | }else{
|
||
910 | if(navigator.plugins["Silverlight Plug-In"]){ |
||
911 | flag = true;
|
||
912 | } |
||
913 | } |
||
914 | }catch(e){
|
||
915 | flag = false;
|
||
916 | }finally{
|
||
917 | sl = null;
|
||
918 | } |
||
919 | if(flag){ dojox.gfx.renderer = "silverlight"; } |
||
920 | break;
|
||
921 | case "canvas": |
||
922 | //TODO: need more comprehensive test for Canvas
|
||
923 | if(!dojo.isIE){
|
||
924 | dojox.gfx.renderer = "canvas";
|
||
925 | } |
||
926 | break;
|
||
927 | } |
||
928 | if(dojox.gfx.renderer){ break; } |
||
929 | } |
||
930 | if(dojo.config.isDebug){
|
||
931 | console.log("gfx renderer = " + dojox.gfx.renderer);
|
||
932 | } |
||
933 | } |
||
934 | }); |
||
935 | |||
936 | // include a renderer conditionally
|
||
937 | dojo.requireIf(dojox.gfx.renderer == "svg", "dojox.gfx.svg"); |
||
938 | dojo.requireIf(dojox.gfx.renderer == "vml", "dojox.gfx.vml"); |
||
939 | dojo.requireIf(dojox.gfx.renderer == "silverlight", "dojox.gfx.silverlight"); |
||
940 | dojo.requireIf(dojox.gfx.renderer == "canvas", "dojox.gfx.canvas"); |
||
941 | |||
942 | } |