Project

General

Profile

Statistics
| Revision:

root / trunk / web / dojo / dojox / gfx.js.uncompressed.js @ 12

History | View | Annotate | Download (30.8 KB)

1
/*
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
}
943