| /* |
| Copyright (c) 2004-2009, The Dojo Foundation All Rights Reserved. |
| Available via Academic Free License >= 2.1 OR the modified BSD license. |
| see: http://dojotoolkit.org/license for details |
| */ |
| |
| /* |
| This is a compiled version of Dojo, built for deployment and not for |
| development. To get an editable version, please visit: |
| |
| http://dojotoolkit.org |
| |
| for documentation and information on getting the source. |
| */ |
| |
| if(!dojo._hasResource["dojox.gfx.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.gfx.matrix"] = true; |
| dojo.provide("dojox.gfx.matrix"); |
| |
| (function(){ |
| var m = dojox.gfx.matrix; |
| |
| // candidates for dojox.math: |
| var _degToRadCache = {}; |
| m._degToRad = function(degree){ |
| return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180)); |
| }; |
| m._radToDeg = function(radian){ return radian / Math.PI * 180; }; |
| |
| m.Matrix2D = function(arg){ |
| // summary: a 2D matrix object |
| // description: Normalizes a 2D matrix-like object. If arrays is passed, |
| // all objects of the array are normalized and multiplied sequentially. |
| // arg: Object |
| // a 2D matrix-like object, a number, or an array of such objects |
| if(arg){ |
| if(typeof arg == "number"){ |
| this.xx = this.yy = arg; |
| }else if(arg instanceof Array){ |
| if(arg.length > 0){ |
| var matrix = m.normalize(arg[0]); |
| // combine matrices |
| for(var i = 1; i < arg.length; ++i){ |
| var l = matrix, r = dojox.gfx.matrix.normalize(arg[i]); |
| matrix = new m.Matrix2D(); |
| matrix.xx = l.xx * r.xx + l.xy * r.yx; |
| matrix.xy = l.xx * r.xy + l.xy * r.yy; |
| matrix.yx = l.yx * r.xx + l.yy * r.yx; |
| matrix.yy = l.yx * r.xy + l.yy * r.yy; |
| matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx; |
| matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy; |
| } |
| dojo.mixin(this, matrix); |
| } |
| }else{ |
| dojo.mixin(this, arg); |
| } |
| } |
| }; |
| |
| // the default (identity) matrix, which is used to fill in missing values |
| dojo.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0}); |
| |
| dojo.mixin(m, { |
| // summary: class constants, and methods of dojox.gfx.matrix |
| |
| // matrix constants |
| |
| // identity: dojox.gfx.matrix.Matrix2D |
| // an identity matrix constant: identity * (x, y) == (x, y) |
| identity: new m.Matrix2D(), |
| |
| // flipX: dojox.gfx.matrix.Matrix2D |
| // a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y) |
| flipX: new m.Matrix2D({xx: -1}), |
| |
| // flipY: dojox.gfx.matrix.Matrix2D |
| // a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y) |
| flipY: new m.Matrix2D({yy: -1}), |
| |
| // flipXY: dojox.gfx.matrix.Matrix2D |
| // a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y) |
| flipXY: new m.Matrix2D({xx: -1, yy: -1}), |
| |
| // matrix creators |
| |
| translate: function(a, b){ |
| // summary: forms a translation matrix |
| // description: The resulting matrix is used to translate (move) points by specified offsets. |
| // a: Number: an x coordinate value |
| // b: Number: a y coordinate value |
| if(arguments.length > 1){ |
| return new m.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D |
| } |
| // branch |
| // a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions |
| // b: null |
| return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D |
| }, |
| scale: function(a, b){ |
| // summary: forms a scaling matrix |
| // description: The resulting matrix is used to scale (magnify) points by specified offsets. |
| // a: Number: a scaling factor used for the x coordinate |
| // b: Number: a scaling factor used for the y coordinate |
| if(arguments.length > 1){ |
| return new m.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D |
| } |
| if(typeof a == "number"){ |
| // branch |
| // a: Number: a uniform scaling factor used for the both coordinates |
| // b: null |
| return new m.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D |
| } |
| // branch |
| // a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions |
| // b: null |
| return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D |
| }, |
| rotate: function(angle){ |
| // summary: forms a rotating matrix |
| // description: The resulting matrix is used to rotate points |
| // around the origin of coordinates (0, 0) by specified angle. |
| // angle: Number: an angle of rotation in radians (>0 for CW) |
| var c = Math.cos(angle); |
| var s = Math.sin(angle); |
| return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx.matrix.Matrix2D |
| }, |
| rotateg: function(degree){ |
| // summary: forms a rotating matrix |
| // description: The resulting matrix is used to rotate points |
| // around the origin of coordinates (0, 0) by specified degree. |
| // See dojox.gfx.matrix.rotate() for comparison. |
| // degree: Number: an angle of rotation in degrees (>0 for CW) |
| return m.rotate(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewX: function(angle) { |
| // summary: forms an x skewing matrix |
| // description: The resulting matrix is used to skew points in the x dimension |
| // around the origin of coordinates (0, 0) by specified angle. |
| // angle: Number: an skewing angle in radians |
| return new m.Matrix2D({xy: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewXg: function(degree){ |
| // summary: forms an x skewing matrix |
| // description: The resulting matrix is used to skew points in the x dimension |
| // around the origin of coordinates (0, 0) by specified degree. |
| // See dojox.gfx.matrix.skewX() for comparison. |
| // degree: Number: an skewing angle in degrees |
| return m.skewX(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewY: function(angle){ |
| // summary: forms a y skewing matrix |
| // description: The resulting matrix is used to skew points in the y dimension |
| // around the origin of coordinates (0, 0) by specified angle. |
| // angle: Number: an skewing angle in radians |
| return new m.Matrix2D({yx: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewYg: function(degree){ |
| // summary: forms a y skewing matrix |
| // description: The resulting matrix is used to skew points in the y dimension |
| // around the origin of coordinates (0, 0) by specified degree. |
| // See dojox.gfx.matrix.skewY() for comparison. |
| // degree: Number: an skewing angle in degrees |
| return m.skewY(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
| }, |
| reflect: function(a, b){ |
| // summary: forms a reflection matrix |
| // description: The resulting matrix is used to reflect points around a vector, |
| // which goes through the origin. |
| // a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection |
| // b: null |
| if(arguments.length == 1){ |
| b = a.y; |
| a = a.x; |
| } |
| // branch |
| // a: Number: an x coordinate value |
| // b: Number: a y coordinate value |
| |
| // make a unit vector |
| var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2; |
| return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox.gfx.matrix.Matrix2D |
| }, |
| project: function(a, b){ |
| // summary: forms an orthogonal projection matrix |
| // description: The resulting matrix is used to project points orthogonally on a vector, |
| // which goes through the origin. |
| // a: dojox.gfx.Point: a point-like object, which specifies a vector of projection |
| // b: null |
| if(arguments.length == 1){ |
| b = a.y; |
| a = a.x; |
| } |
| // branch |
| // a: Number: an x coordinate value |
| // b: Number: a y coordinate value |
| |
| // make a unit vector |
| var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2; |
| return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox.gfx.matrix.Matrix2D |
| }, |
| |
| // ensure matrix 2D conformance |
| normalize: function(matrix){ |
| // summary: converts an object to a matrix, if necessary |
| // description: Converts any 2D matrix-like object or an array of |
| // such objects to a valid dojox.gfx.matrix.Matrix2D object. |
| // matrix: Object: an object, which is converted to a matrix, if necessary |
| return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D |
| }, |
| |
| // common operations |
| |
| clone: function(matrix){ |
| // summary: creates a copy of a 2D matrix |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned |
| var obj = new m.Matrix2D(); |
| for(var i in matrix){ |
| if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i]; |
| } |
| return obj; // dojox.gfx.matrix.Matrix2D |
| }, |
| invert: function(matrix){ |
| // summary: inverts a 2D matrix |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted |
| var M = m.normalize(matrix), |
| D = M.xx * M.yy - M.xy * M.yx, |
| M = new m.Matrix2D({ |
| xx: M.yy/D, xy: -M.xy/D, |
| yx: -M.yx/D, yy: M.xx/D, |
| dx: (M.xy * M.dy - M.yy * M.dx) / D, |
| dy: (M.yx * M.dx - M.xx * M.dy) / D |
| }); |
| return M; // dojox.gfx.matrix.Matrix2D |
| }, |
| _multiplyPoint: function(matrix, x, y){ |
| // summary: applies a matrix to a point |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied |
| // x: Number: an x coordinate of a point |
| // y: Number: a y coordinate of a point |
| return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox.gfx.Point |
| }, |
| multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b){ |
| // summary: applies a matrix to a point |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied |
| // a: Number: an x coordinate of a point |
| // b: Number: a y coordinate of a point |
| var M = m.normalize(matrix); |
| if(typeof a == "number" && typeof b == "number"){ |
| return m._multiplyPoint(M, a, b); // dojox.gfx.Point |
| } |
| // branch |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied |
| // a: dojox.gfx.Point: a point |
| // b: null |
| return m._multiplyPoint(M, a.x, a.y); // dojox.gfx.Point |
| }, |
| multiply: function(matrix){ |
| // summary: combines matrices by multiplying them sequentially in the given order |
| // matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object, |
| // all subsequent arguments are matrix-like objects too |
| var M = m.normalize(matrix); |
| // combine matrices |
| for(var i = 1; i < arguments.length; ++i){ |
| var l = M, r = m.normalize(arguments[i]); |
| M = new m.Matrix2D(); |
| M.xx = l.xx * r.xx + l.xy * r.yx; |
| M.xy = l.xx * r.xy + l.xy * r.yy; |
| M.yx = l.yx * r.xx + l.yy * r.yx; |
| M.yy = l.yx * r.xy + l.yy * r.yy; |
| M.dx = l.xx * r.dx + l.xy * r.dy + l.dx; |
| M.dy = l.yx * r.dx + l.yy * r.dy + l.dy; |
| } |
| return M; // dojox.gfx.matrix.Matrix2D |
| }, |
| |
| // high level operations |
| |
| _sandwich: function(matrix, x, y){ |
| // summary: applies a matrix at a centrtal point |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point |
| // x: Number: an x component of the central point |
| // y: Number: a y component of the central point |
| return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D |
| }, |
| scaleAt: function(a, b, c, d){ |
| // summary: scales a picture using a specified point as a center of scaling |
| // description: Compare with dojox.gfx.matrix.scale(). |
| // a: Number: a scaling factor used for the x coordinate |
| // b: Number: a scaling factor used for the y coordinate |
| // c: Number: an x component of a central point |
| // d: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) uniform scale factor, Point |
| // 2) uniform scale factor, x, y |
| // 3) x scale, y scale, Point |
| // 4) x scale, y scale, x, y |
| |
| switch(arguments.length){ |
| case 4: |
| // a and b are scale factor components, c and d are components of a point |
| return m._sandwich(m.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D |
| case 3: |
| if(typeof c == "number"){ |
| // branch |
| // a: Number: a uniform scaling factor used for both coordinates |
| // b: Number: an x component of a central point |
| // c: Number: a y component of a central point |
| // d: null |
| return m._sandwich(m.scale(a), b, c); // dojox.gfx.matrix.Matrix2D |
| } |
| // branch |
| // a: Number: a scaling factor used for the x coordinate |
| // b: Number: a scaling factor used for the y coordinate |
| // c: dojox.gfx.Point: a central point |
| // d: null |
| return m._sandwich(m.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D |
| } |
| // branch |
| // a: Number: a uniform scaling factor used for both coordinates |
| // b: dojox.gfx.Point: a central point |
| // c: null |
| // d: null |
| return m._sandwich(m.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| rotateAt: function(angle, a, b){ |
| // summary: rotates a picture using a specified point as a center of rotation |
| // description: Compare with dojox.gfx.matrix.rotate(). |
| // angle: Number: an angle of rotation in radians (>0 for CW) |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) rotation angle in radians, Point |
| // 2) rotation angle in radians, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // angle: Number: an angle of rotation in radians (>0 for CCW) |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| rotategAt: function(degree, a, b){ |
| // summary: rotates a picture using a specified point as a center of rotation |
| // description: Compare with dojox.gfx.matrix.rotateg(). |
| // degree: Number: an angle of rotation in degrees (>0 for CW) |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) rotation angle in degrees, Point |
| // 2) rotation angle in degrees, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // degree: Number: an angle of rotation in degrees (>0 for CCW) |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewXAt: function(angle, a, b){ |
| // summary: skews a picture along the x axis using a specified point as a center of skewing |
| // description: Compare with dojox.gfx.matrix.skewX(). |
| // angle: Number: an skewing angle in radians |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) skew angle in radians, Point |
| // 2) skew angle in radians, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // angle: Number: an skewing angle in radians |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewXgAt: function(degree, a, b){ |
| // summary: skews a picture along the x axis using a specified point as a center of skewing |
| // description: Compare with dojox.gfx.matrix.skewXg(). |
| // degree: Number: an skewing angle in degrees |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) skew angle in degrees, Point |
| // 2) skew angle in degrees, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // degree: Number: an skewing angle in degrees |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewYAt: function(angle, a, b){ |
| // summary: skews a picture along the y axis using a specified point as a center of skewing |
| // description: Compare with dojox.gfx.matrix.skewY(). |
| // angle: Number: an skewing angle in radians |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) skew angle in radians, Point |
| // 2) skew angle in radians, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // angle: Number: an skewing angle in radians |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){ |
| // summary: skews a picture along the y axis using a specified point as a center of skewing |
| // description: Compare with dojox.gfx.matrix.skewYg(). |
| // degree: Number: an skewing angle in degrees |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) skew angle in degrees, Point |
| // 2) skew angle in degrees, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // degree: Number: an skewing angle in degrees |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| //TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions) |
| |
| }); |
| })(); |
| |
| // propagate Matrix2D up |
| dojox.gfx.Matrix2D = dojox.gfx.matrix.Matrix2D; |
| |
| } |
| |
| if(!dojo._hasResource["dojox.gfx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.gfx._base"] = true; |
| dojo.provide("dojox.gfx._base"); |
| |
| (function(){ |
| var g = dojox.gfx, b = g._base; |
| |
| // candidates for dojox.style (work on VML and SVG nodes) |
| g._hasClass = function(/*DomNode*/node, /*String*/classStr){ |
| // summary: |
| // Returns whether or not the specified classes are a portion of the |
| // class list currently applied to the node. |
| // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean |
| var cls = node.getAttribute("className"); |
| return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0; // Boolean |
| } |
| g._addClass = function(/*DomNode*/node, /*String*/classStr){ |
| // summary: |
| // Adds the specified classes to the end of the class list on the |
| // passed node. |
| var cls = node.getAttribute("className") || ""; |
| if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){ |
| node.setAttribute("className", cls + (cls ? " " : "") + classStr); |
| } |
| } |
| g._removeClass = function(/*DomNode*/node, /*String*/classStr){ |
| // summary: Removes classes from node. |
| var cls = node.getAttribute("className"); |
| if(cls){ |
| node.setAttribute( |
| "className", |
| cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2") |
| ); |
| } |
| } |
| |
| // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here) |
| |
| // derived from Morris John's emResized measurer |
| b._getFontMeasurements = function(){ |
| // summary: |
| // Returns an object that has pixel equivilents of standard font |
| // size values. |
| var heights = { |
| '1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0, |
| 'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0, |
| 'xx-large': 0 |
| }; |
| |
| if(dojo.isIE){ |
| // we do a font-size fix if and only if one isn't applied already. |
| // NOTE: If someone set the fontSize on the HTML Element, this will kill it. |
| dojo.doc.documentElement.style.fontSize="100%"; |
| } |
| |
| // set up the measuring node. |
| var div = dojo.doc.createElement("div"); |
| var s = div.style; |
| s.position = "absolute"; |
| s.left = "-100px"; |
| s.top = "0px"; |
| s.width = "30px"; |
| s.height = "1000em"; |
| s.border = "0px"; |
| s.margin = "0px"; |
| s.padding = "0px"; |
| s.outline = "none"; |
| s.lineHeight = "1"; |
| s.overflow = "hidden"; |
| dojo.body().appendChild(div); |
| |
| // do the measurements. |
| for(var p in heights){ |
| div.style.fontSize = p; |
| heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000; |
| } |
| |
| dojo.body().removeChild(div); |
| div = null; |
| return heights; // object |
| }; |
| |
| var fontMeasurements = null; |
| |
| b._getCachedFontMeasurements = function(recalculate){ |
| if(recalculate || !fontMeasurements){ |
| fontMeasurements = b._getFontMeasurements(); |
| } |
| return fontMeasurements; |
| }; |
| |
| // candidate for dojox.html.metrics |
| |
| var measuringNode = null, empty = {}; |
| b._getTextBox = function( /*String*/ text, |
| /*Object*/ style, |
| /*String?*/ className){ |
| var m, s, al = arguments.length; |
| if(!measuringNode){ |
| m = measuringNode = dojo.doc.createElement("div"); |
| s = m.style; |
| s.position = "absolute"; |
| s.left = "-10000px"; |
| s.top = "0"; |
| dojo.body().appendChild(m); |
| }else{ |
| m = measuringNode; |
| s = m.style; |
| } |
| // reset styles |
| m.className = ""; |
| s.border = "0"; |
| s.margin = "0"; |
| s.padding = "0"; |
| s.outline = "0"; |
| // set new style |
| if(al > 1 && style){ |
| for(var i in style){ |
| if(i in empty){ continue; } |
| s[i] = style[i]; |
| } |
| } |
| // set classes |
| if(al > 2 && className){ |
| m.className = className; |
| } |
| // take a measure |
| m.innerHTML = text; |
| |
| if(m["getBoundingClientRect"]){ |
| var bcr = m.getBoundingClientRect(); |
| return {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)}; |
| }else{ |
| return dojo.marginBox(m); |
| } |
| }; |
| |
| // candidate for dojo.dom |
| |
| var uniqueId = 0; |
| b._getUniqueId = function(){ |
| // summary: returns a unique string for use with any DOM element |
| var id; |
| do{ |
| id = dojo._scopeName + "Unique" + (++uniqueId); |
| }while(dojo.byId(id)); |
| return id; |
| }; |
| })(); |
| |
| dojo.mixin(dojox.gfx, { |
| // summary: |
| // defines constants, prototypes, and utility functions |
| |
| // default shapes, which are used to fill in missing parameters |
| defaultPath: { |
| type: "path", path: "" |
| }, |
| defaultPolyline: { |
| type: "polyline", points: [] |
| }, |
| defaultRect: { |
| type: "rect", x: 0, y: 0, width: 100, height: 100, r: 0 |
| }, |
| defaultEllipse: { |
| type: "ellipse", cx: 0, cy: 0, rx: 200, ry: 100 |
| }, |
| defaultCircle: { |
| type: "circle", cx: 0, cy: 0, r: 100 |
| }, |
| defaultLine: { |
| type: "line", x1: 0, y1: 0, x2: 100, y2: 100 |
| }, |
| defaultImage: { |
| type: "image", x: 0, y: 0, width: 0, height: 0, src: "" |
| }, |
| defaultText: { |
| type: "text", x: 0, y: 0, text: "", align: "start", |
| decoration: "none", rotated: false, kerning: true |
| }, |
| defaultTextPath: { |
| type: "textpath", text: "", align: "start", |
| decoration: "none", rotated: false, kerning: true |
| }, |
| |
| // default geometric attributes |
| defaultStroke: { |
| type: "stroke", color: "black", style: "solid", width: 1, |
| cap: "butt", join: 4 |
| }, |
| defaultLinearGradient: { |
| type: "linear", x1: 0, y1: 0, x2: 100, y2: 100, |
| colors: [ |
| { offset: 0, color: "black" }, { offset: 1, color: "white" } |
| ] |
| }, |
| defaultRadialGradient: { |
| type: "radial", cx: 0, cy: 0, r: 100, |
| colors: [ |
| { offset: 0, color: "black" }, { offset: 1, color: "white" } |
| ] |
| }, |
| defaultPattern: { |
| type: "pattern", x: 0, y: 0, width: 0, height: 0, src: "" |
| }, |
| defaultFont: { |
| type: "font", style: "normal", variant: "normal", |
| weight: "normal", size: "10pt", family: "serif" |
| }, |
| |
| getDefault: (function(){ |
| var typeCtorCache = {}; |
| // a memoized delegate() |
| return function(/*String*/ type){ |
| var t = typeCtorCache[type]; |
| if(t){ |
| return new t(); |
| } |
| t = typeCtorCache[type] = new Function; |
| t.prototype = dojox.gfx[ "default" + type ]; |
| return new t(); |
| } |
| })(), |
| |
| normalizeColor: function(/*Color*/ color){ |
| // summary: |
| // converts any legal color representation to normalized |
| // dojo.Color object |
| return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color |
| }, |
| normalizeParameters: function(existed, update){ |
| // summary: |
| // updates an existing object with properties from an "update" |
| // object |
| // existed: Object |
| // the "target" object to be updated |
| // update: Object |
| // the "update" object, whose properties will be used to update |
| // the existed object |
| if(update){ |
| var empty = {}; |
| for(var x in existed){ |
| if(x in update && !(x in empty)){ |
| existed[x] = update[x]; |
| } |
| } |
| } |
| return existed; // Object |
| }, |
| makeParameters: function(defaults, update){ |
| // summary: |
| // copies the original object, and all copied properties from the |
| // "update" object |
| // defaults: Object |
| // the object to be cloned before updating |
| // update: Object |
| // the object, which properties are to be cloned during updating |
| if(!update){ |
| // return dojo.clone(defaults); |
| return dojo.delegate(defaults); |
| } |
| var result = {}; |
| for(var i in defaults){ |
| if(!(i in result)){ |
| result[i] = dojo.clone((i in update) ? update[i] : defaults[i]); |
| } |
| } |
| return result; // Object |
| }, |
| formatNumber: function(x, addSpace){ |
| // summary: converts a number to a string using a fixed notation |
| // x: Number: number to be converted |
| // addSpace: Boolean?: if it is true, add a space before a positive number |
| var val = x.toString(); |
| if(val.indexOf("e") >= 0){ |
| val = x.toFixed(4); |
| }else{ |
| var point = val.indexOf("."); |
| if(point >= 0 && val.length - point > 5){ |
| val = x.toFixed(4); |
| } |
| } |
| if(x < 0){ |
| return val; // String |
| } |
| return addSpace ? " " + val : val; // String |
| }, |
| // font operations |
| makeFontString: function(font){ |
| // summary: converts a font object to a CSS font string |
| // font: Object: font object (see dojox.gfx.defaultFont) |
| return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object |
| }, |
| splitFontString: function(str){ |
| // summary: |
| // converts a CSS font string to a font object |
| // description: |
| // Converts a CSS font string to a gfx font object. The CSS font |
| // string components should follow the W3C specified order |
| // (see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand): |
| // style, variant, weight, size, optional line height (will be |
| // ignored), and family. |
| // str: String |
| // a CSS font string |
| var font = dojox.gfx.getDefault("Font"); |
| var t = str.split(/\s+/); |
| do{ |
| if(t.length < 5){ break; } |
| font.style = t[0]; |
| font.variant = t[1]; |
| font.weight = t[2]; |
| var i = t[3].indexOf("/"); |
| font.size = i < 0 ? t[3] : t[3].substring(0, i); |
| var j = 4; |
| if(i < 0){ |
| if(t[4] == "/"){ |
| j = 6; |
| }else if(t[4].charAt(0) == "/"){ |
| j = 5; |
| } |
| } |
| if(j < t.length){ |
| font.family = t.slice(j).join(" "); |
| } |
| }while(false); |
| return font; // Object |
| }, |
| // length operations |
| cm_in_pt: 72 / 2.54, // Number: points per centimeter |
| mm_in_pt: 7.2 / 2.54, // Number: points per millimeter |
| px_in_pt: function(){ |
| // summary: returns a number of pixels per point |
| return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12; // Number |
| }, |
| pt2px: function(len){ |
| // summary: converts points to pixels |
| // len: Number: a value in points |
| return len * dojox.gfx.px_in_pt(); // Number |
| }, |
| px2pt: function(len){ |
| // summary: converts pixels to points |
| // len: Number: a value in pixels |
| return len / dojox.gfx.px_in_pt(); // Number |
| }, |
| normalizedLength: function(len) { |
| // summary: converts any length value to pixels |
| // len: String: a length, e.g., "12pc" |
| if(len.length == 0) return 0; |
| if(len.length > 2){ |
| var px_in_pt = dojox.gfx.px_in_pt(); |
| var val = parseFloat(len); |
| switch(len.slice(-2)){ |
| case "px": return val; |
| case "pt": return val * px_in_pt; |
| case "in": return val * 72 * px_in_pt; |
| case "pc": return val * 12 * px_in_pt; |
| case "mm": return val * dojox.gfx.mm_in_pt * px_in_pt; |
| case "cm": return val * dojox.gfx.cm_in_pt * px_in_pt; |
| } |
| } |
| return parseFloat(len); // Number |
| }, |
| |
| // a constant used to split a SVG/VML path into primitive components |
| pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, |
| pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, |
| |
| equalSources: function(a, b){ |
| // summary: compares event sources, returns true if they are equal |
| return a && b && a == b; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.gfx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.gfx"] = true; |
| dojo.provide("dojox.gfx"); |
| |
| |
| |
| |
| dojo.loadInit(function(){ |
| //Since loaderInit can be fired before any dojo.provide/require calls, |
| //make sure the dojox.gfx object exists and only run this logic if dojox.gfx.renderer |
| //has not been defined yet. |
| var gfx = dojo.getObject("dojox.gfx", true), sl, flag, match; |
| if(!gfx.renderer){ |
| //Have a way to force a GFX renderer, if so desired. |
| //Useful for being able to serialize GFX data in a particular format. |
| if(dojo.config.forceGfxRenderer){ |
| dojox.gfx.renderer = dojo.config.forceGfxRenderer; |
| return; |
| } |
| var renderers = (typeof dojo.config.gfxRenderer == "string" ? |
| dojo.config.gfxRenderer : "svg,vml,silverlight,canvas").split(","); |
| |
| // mobile platform detection |
| // TODO: move to the base? |
| |
| var ua = navigator.userAgent, iPhoneOsBuild = 0, androidVersion = 0; |
| if(dojo.isSafari >= 3){ |
| // detect mobile version of WebKit starting with "version 3" |
| |
| // comprehensive iPhone test. Have to figure out whether it's SVG or Canvas based on the build. |
| // iPhone OS build numbers from en.wikipedia.org. |
| if(ua.indexOf("iPhone") >= 0 || ua.indexOf("iPod") >= 0){ |
| // grab the build out of this. Expression is a little nasty because we want |
| // to be sure we have the whole version string. |
| match = ua.match(/Version\/(\d(\.\d)?(\.\d)?)\sMobile\/([^\s]*)\s?/); |
| if(match){ |
| // grab the build out of the match. Only use the first three because of specific builds. |
| iPhoneOsBuild = parseInt(match[4].substr(0,3), 16); |
| } |
| } |
| } |
| if(dojo.isWebKit){ |
| // Android detection |
| if(!iPhoneOsBuild){ |
| match = ua.match(/Android\s+(\d+\.\d+)/); |
| if(match){ |
| androidVersion = parseFloat(match[1]); |
| // Android 1.0-1.1 doesn't support SVG but supports Canvas |
| } |
| } |
| } |
| |
| for(var i = 0; i < renderers.length; ++i){ |
| switch(renderers[i]){ |
| case "svg": |
| // iPhone OS builds greater than 5F1 should have SVG. |
| if(!dojo.isIE && (!iPhoneOsBuild || iPhoneOsBuild >= 0x5f1) && !androidVersion && !dojo.isAIR){ |
| dojox.gfx.renderer = "svg"; |
| } |
| break; |
| case "vml": |
| if(dojo.isIE){ |
| dojox.gfx.renderer = "vml"; |
| } |
| break; |
| case "silverlight": |
| try{ |
| if(dojo.isIE){ |
| sl = new ActiveXObject("AgControl.AgControl"); |
| if(sl && sl.IsVersionSupported("1.0")){ |
| flag = true; |
| } |
| }else{ |
| if(navigator.plugins["Silverlight Plug-In"]){ |
| flag = true; |
| } |
| } |
| }catch(e){ |
| flag = false; |
| }finally{ |
| sl = null; |
| } |
| if(flag){ dojox.gfx.renderer = "silverlight"; } |
| break; |
| case "canvas": |
| //TODO: need more comprehensive test for Canvas |
| if(!dojo.isIE){ |
| dojox.gfx.renderer = "canvas"; |
| } |
| break; |
| } |
| if(dojox.gfx.renderer){ break; } |
| } |
| if(dojo.config.isDebug){ |
| console.log("gfx renderer = " + dojox.gfx.renderer); |
| } |
| } |
| }); |
| |
| // include a renderer conditionally |
| dojo.requireIf(dojox.gfx.renderer == "svg", "dojox.gfx.svg"); |
| dojo.requireIf(dojox.gfx.renderer == "vml", "dojox.gfx.vml"); |
| dojo.requireIf(dojox.gfx.renderer == "silverlight", "dojox.gfx.silverlight"); |
| dojo.requireIf(dojox.gfx.renderer == "canvas", "dojox.gfx.canvas"); |
| |
| } |
| |