/*
Copyright (c) 2004-2011, 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
*/
/*
Copyright (c) 2004-2011, 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);
}
});
}