/* Copyright (c) 2004-2012, 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 an optimized version of Dojo, built for deployment and not for development. To get sources and documentation, please visit: http://dojotoolkit.org */ 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.create("div", {style: { position: "absolute", left: "0", top: "-100px", width: "30px", height: "1000em", borderWidth: "0", margin: "0", padding: "0", outline: "none", lineHeight: "1", overflow: "hidden" }}, dojo.body()); // 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); 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){ measuringNode = dojo.create("div", {style: { position: "absolute", top: "-10000px", left: "0" }}, dojo.body()); } m = measuringNode; // reset styles m.className = ""; s = m.style; s.borderWidth = "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; }, switchTo: function(renderer){ var ns = dojox.gfx[renderer]; if(ns){ dojo.forEach(["Group", "Rect", "Ellipse", "Circle", "Line", "Polyline", "Image", "Text", "Path", "TextPath", "Surface", "createSurface"], function(name){ dojox.gfx[name] = ns[name]; }); } } }); } 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; while(!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; break; } var renderers = (typeof dojo.config.gfxRenderer == "string" ? dojo.config.gfxRenderer : "svg,vml,canvas,silverlight").split(","); for(var i = 0; i < renderers.length; ++i){ switch(renderers[i]){ case "svg": // the next test is from https://github.com/phiggins42/has.js if("SVGAngle" in dojo.global){ 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": if(dojo.global.CanvasRenderingContext2D){ dojox.gfx.renderer = "canvas"; } break; } if(gfx.renderer){ break; } } break; } if(dojo.config.isDebug){ console.log("gfx renderer = " + gfx.renderer); } // load & initialize renderer if(gfx[gfx.renderer]){ // already loaded gfx.switchTo(gfx.renderer); }else{ // load gfx.loadAndSwitch = gfx.renderer; dojo["require"]("dojox.gfx." + gfx.renderer); } }); }