1195 lines
37 KiB
JavaScript
1195 lines
37 KiB
JavaScript
|
dojo.provide("dojox.gfx.vml");
|
||
|
|
||
|
dojo.require("dojox.gfx._base");
|
||
|
dojo.require("dojox.gfx.shape");
|
||
|
dojo.require("dojox.gfx.path");
|
||
|
dojo.require("dojox.gfx.arc");
|
||
|
|
||
|
(function(){
|
||
|
var g = dojox.gfx, m = g.matrix, vml = g.vml, sh = g.shape;
|
||
|
|
||
|
// dojox.gfx.vml.xmlns: String: a VML's namespace
|
||
|
vml.xmlns = "urn:schemas-microsoft-com:vml";
|
||
|
|
||
|
// dojox.gfx.vml.text_alignment: Object: mapping from SVG alignment to VML alignment
|
||
|
vml.text_alignment = {start: "left", middle: "center", end: "right"};
|
||
|
|
||
|
vml._parseFloat = function(str) {
|
||
|
// summary: a helper function to parse VML-specific floating-point values
|
||
|
// str: String: a representation of a floating-point number
|
||
|
return str.match(/^\d+f$/i) ? parseInt(str) / 65536 : parseFloat(str); // Number
|
||
|
};
|
||
|
|
||
|
vml._bool = {"t": 1, "true": 1};
|
||
|
|
||
|
dojo.extend(g.Shape, {
|
||
|
// summary: VML-specific implementation of dojox.gfx.Shape methods
|
||
|
|
||
|
setFill: function(fill){
|
||
|
// summary: sets a fill object (VML)
|
||
|
// fill: Object: a fill object
|
||
|
// (see dojox.gfx.defaultLinearGradient,
|
||
|
// dojox.gfx.defaultRadialGradient,
|
||
|
// dojox.gfx.defaultPattern,
|
||
|
// or dojo.Color)
|
||
|
|
||
|
if(!fill){
|
||
|
// don't fill
|
||
|
this.fillStyle = null;
|
||
|
this.rawNode.filled = "f";
|
||
|
return this;
|
||
|
}
|
||
|
var i, f, fo, a, s;
|
||
|
if(typeof fill == "object" && "type" in fill){
|
||
|
// gradient
|
||
|
switch(fill.type){
|
||
|
case "linear":
|
||
|
var matrix = this._getRealMatrix();
|
||
|
s = [];
|
||
|
f = g.makeParameters(g.defaultLinearGradient, fill);
|
||
|
a = f.colors;
|
||
|
this.fillStyle = f;
|
||
|
dojo.forEach(a, function(v, i, a){
|
||
|
a[i].color = g.normalizeColor(v.color);
|
||
|
});
|
||
|
if(a[0].offset > 0){
|
||
|
s.push("0 " + a[0].color.toHex());
|
||
|
}
|
||
|
for(i = 0; i < a.length; ++i){
|
||
|
s.push(a[i].offset.toFixed(8) + " " + a[i].color.toHex());
|
||
|
}
|
||
|
i = a.length - 1;
|
||
|
if(a[i].offset < 1){
|
||
|
s.push("1 " + a[i].color.toHex());
|
||
|
}
|
||
|
fo = this.rawNode.fill;
|
||
|
fo.colors.value = s.join(";");
|
||
|
fo.method = "sigma";
|
||
|
fo.type = "gradient";
|
||
|
var fc1 = matrix ? m.multiplyPoint(matrix, f.x1, f.y1) : {x: f.x1, y: f.y1},
|
||
|
fc2 = matrix ? m.multiplyPoint(matrix, f.x2, f.y2) : {x: f.x2, y: f.y2};
|
||
|
fo.angle = (m._radToDeg(Math.atan2(fc2.x - fc1.x, fc2.y - fc1.y)) + 180) % 360;
|
||
|
fo.on = true;
|
||
|
break;
|
||
|
case "radial":
|
||
|
f = g.makeParameters(g.defaultRadialGradient, fill);
|
||
|
this.fillStyle = f;
|
||
|
var l = parseFloat(this.rawNode.style.left),
|
||
|
t = parseFloat(this.rawNode.style.top),
|
||
|
w = parseFloat(this.rawNode.style.width),
|
||
|
h = parseFloat(this.rawNode.style.height),
|
||
|
c = isNaN(w) ? 1 : 2 * f.r / w;
|
||
|
a = [];
|
||
|
// add a color at the offset 0 (1 in VML coordinates)
|
||
|
if(f.colors[0].offset > 0){
|
||
|
a.push({offset: 1, color: g.normalizeColor(f.colors[0].color)});
|
||
|
}
|
||
|
// massage colors
|
||
|
dojo.forEach(f.colors, function(v, i){
|
||
|
a.push({offset: 1 - v.offset * c, color: g.normalizeColor(v.color)});
|
||
|
});
|
||
|
i = a.length - 1;
|
||
|
while(i >= 0 && a[i].offset < 0){ --i; }
|
||
|
if(i < a.length - 1){
|
||
|
// correct excessive colors
|
||
|
var q = a[i], p = a[i + 1];
|
||
|
p.color = dojo.blendColors(q.color, p.color, q.offset / (q.offset - p.offset));
|
||
|
p.offset = 0;
|
||
|
while(a.length - i > 2) a.pop();
|
||
|
}
|
||
|
// set colors
|
||
|
i = a.length - 1, s = [];
|
||
|
if(a[i].offset > 0){
|
||
|
s.push("0 " + a[i].color.toHex());
|
||
|
}
|
||
|
for(; i >= 0; --i){
|
||
|
s.push(a[i].offset.toFixed(8) + " " + a[i].color.toHex());
|
||
|
}
|
||
|
fo = this.rawNode.fill;
|
||
|
fo.colors.value = s.join(";");
|
||
|
fo.method = "sigma";
|
||
|
fo.type = "gradientradial";
|
||
|
if(isNaN(w) || isNaN(h) || isNaN(l) || isNaN(t)){
|
||
|
fo.focusposition = "0.5 0.5";
|
||
|
}else{
|
||
|
fo.focusposition = ((f.cx - l) / w).toFixed(8) + " " + ((f.cy - t) / h).toFixed(8);
|
||
|
}
|
||
|
fo.focussize = "0 0";
|
||
|
fo.on = true;
|
||
|
break;
|
||
|
case "pattern":
|
||
|
f = g.makeParameters(g.defaultPattern, fill);
|
||
|
this.fillStyle = f;
|
||
|
fo = this.rawNode.fill;
|
||
|
fo.type = "tile";
|
||
|
fo.src = f.src;
|
||
|
if(f.width && f.height){
|
||
|
// in points
|
||
|
fo.size.x = g.px2pt(f.width);
|
||
|
fo.size.y = g.px2pt(f.height);
|
||
|
}
|
||
|
fo.alignShape = "f";
|
||
|
fo.position.x = 0;
|
||
|
fo.position.y = 0;
|
||
|
fo.origin.x = f.width ? f.x / f.width : 0;
|
||
|
fo.origin.y = f.height ? f.y / f.height : 0;
|
||
|
fo.on = true;
|
||
|
break;
|
||
|
}
|
||
|
this.rawNode.fill.opacity = 1;
|
||
|
return this;
|
||
|
}
|
||
|
// color object
|
||
|
this.fillStyle = g.normalizeColor(fill);
|
||
|
fo = this.rawNode.fill;
|
||
|
if(!fo){
|
||
|
fo = this.rawNode.ownerDocument.createElement("v:fill");
|
||
|
}
|
||
|
fo.method = "any";
|
||
|
fo.type = "solid";
|
||
|
fo.opacity = this.fillStyle.a;
|
||
|
this.rawNode.fillcolor = this.fillStyle.toHex();
|
||
|
this.rawNode.filled = true;
|
||
|
return this; // self
|
||
|
},
|
||
|
|
||
|
setStroke: function(stroke){
|
||
|
// summary: sets a stroke object (VML)
|
||
|
// stroke: Object: a stroke object
|
||
|
// (see dojox.gfx.defaultStroke)
|
||
|
|
||
|
if(!stroke){
|
||
|
// don't stroke
|
||
|
this.strokeStyle = null;
|
||
|
this.rawNode.stroked = "f";
|
||
|
return this;
|
||
|
}
|
||
|
// normalize the stroke
|
||
|
if(typeof stroke == "string" || dojo.isArray(stroke) || stroke instanceof dojo.Color){
|
||
|
stroke = {color: stroke};
|
||
|
}
|
||
|
var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
|
||
|
s.color = g.normalizeColor(s.color);
|
||
|
// generate attributes
|
||
|
var rn = this.rawNode;
|
||
|
rn.stroked = true;
|
||
|
rn.strokecolor = s.color.toCss();
|
||
|
rn.strokeweight = s.width + "px"; // TODO: should we assume that the width is always in pixels?
|
||
|
if(rn.stroke) {
|
||
|
rn.stroke.opacity = s.color.a;
|
||
|
rn.stroke.endcap = this._translate(this._capMap, s.cap);
|
||
|
if(typeof s.join == "number") {
|
||
|
rn.stroke.joinstyle = "miter";
|
||
|
rn.stroke.miterlimit = s.join;
|
||
|
}else{
|
||
|
rn.stroke.joinstyle = s.join;
|
||
|
// rn.stroke.miterlimit = s.width;
|
||
|
}
|
||
|
rn.stroke.dashstyle = s.style == "none" ? "Solid" : s.style;
|
||
|
}
|
||
|
return this; // self
|
||
|
},
|
||
|
|
||
|
_capMap: { butt: 'flat' },
|
||
|
_capMapReversed: { flat: 'butt' },
|
||
|
|
||
|
_translate: function(dict, value) {
|
||
|
return (value in dict) ? dict[value] : value;
|
||
|
},
|
||
|
|
||
|
_applyTransform: function() {
|
||
|
if(this.fillStyle && this.fillStyle.type == "linear"){
|
||
|
this.setFill(this.fillStyle);
|
||
|
}
|
||
|
var matrix = this._getRealMatrix();
|
||
|
if(!matrix) return this;
|
||
|
var skew = this.rawNode.skew;
|
||
|
if(typeof skew == "undefined"){
|
||
|
for(var i = 0; i < this.rawNode.childNodes.length; ++i){
|
||
|
if(this.rawNode.childNodes[i].tagName == "skew"){
|
||
|
skew = this.rawNode.childNodes[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(skew){
|
||
|
skew.on = "f";
|
||
|
var mt = matrix.xx.toFixed(8) + " " + matrix.xy.toFixed(8) + " " +
|
||
|
matrix.yx.toFixed(8) + " " + matrix.yy.toFixed(8) + " 0 0",
|
||
|
offset = Math.floor(matrix.dx).toFixed() + "px " + Math.floor(matrix.dy).toFixed() + "px",
|
||
|
s = this.rawNode.style,
|
||
|
l = parseFloat(s.left),
|
||
|
t = parseFloat(s.top),
|
||
|
w = parseFloat(s.width),
|
||
|
h = parseFloat(s.height);
|
||
|
if(isNaN(l)) l = 0;
|
||
|
if(isNaN(t)) t = 0;
|
||
|
if(isNaN(w)) w = 1;
|
||
|
if(isNaN(h)) h = 1;
|
||
|
var origin = (-l / w - 0.5).toFixed(8) + " " + (-t / h - 0.5).toFixed(8);
|
||
|
skew.matrix = mt;
|
||
|
skew.origin = origin;
|
||
|
skew.offset = offset;
|
||
|
skew.on = true;
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
_setDimensions: function(width, height){
|
||
|
// summary: sets the width and height of the rawNode,
|
||
|
// if the surface sixe has been changed
|
||
|
// width: String: width in pixels
|
||
|
// height: String: height in pixels
|
||
|
|
||
|
// default implementation does nothing
|
||
|
return this; // self
|
||
|
},
|
||
|
|
||
|
setRawNode: function(rawNode){
|
||
|
// summary:
|
||
|
// assigns and clears the underlying node that will represent this
|
||
|
// shape. Once set, transforms, gradients, etc, can be applied.
|
||
|
// (no fill & stroke by default)
|
||
|
rawNode.stroked = "f";
|
||
|
rawNode.filled = "f";
|
||
|
this.rawNode = rawNode;
|
||
|
},
|
||
|
|
||
|
// move family
|
||
|
|
||
|
_moveToFront: function(){
|
||
|
// summary: moves a shape to front of its parent's list of shapes (VML)
|
||
|
this.rawNode.parentNode.appendChild(this.rawNode);
|
||
|
return this;
|
||
|
},
|
||
|
_moveToBack: function(){
|
||
|
// summary: moves a shape to back of its parent's list of shapes (VML)
|
||
|
var r = this.rawNode, p = r.parentNode, n = p.firstChild;
|
||
|
p.insertBefore(r, n);
|
||
|
if(n.tagName == "rect"){
|
||
|
// surface has a background rectangle, which position should be preserved
|
||
|
n.swapNode(r);
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
_getRealMatrix: function(){
|
||
|
// summary: returns the cumulative ("real") transformation matrix
|
||
|
// by combining the shape's matrix with its parent's matrix
|
||
|
return this.parentMatrix ? new g.Matrix2D([this.parentMatrix, this.matrix]) : this.matrix; // dojox.gfx.Matrix2D
|
||
|
}
|
||
|
});
|
||
|
|
||
|
dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, {
|
||
|
// summary: a group shape (VML), which can be used
|
||
|
// to logically group shapes (e.g, to propagate matricies)
|
||
|
constructor: function(){
|
||
|
vml.Container._init.call(this);
|
||
|
},
|
||
|
// apply transformation
|
||
|
_applyTransform: function(){
|
||
|
// summary: applies a transformation matrix to a group
|
||
|
var matrix = this._getRealMatrix();
|
||
|
for(var i = 0; i < this.children.length; ++i){
|
||
|
this.children[i]._updateParentMatrix(matrix);
|
||
|
}
|
||
|
return this; // self
|
||
|
},
|
||
|
_setDimensions: function(width, height){
|
||
|
// summary: sets the width and height of the rawNode,
|
||
|
// if the surface sixe has been changed
|
||
|
// width: String: width in pixels
|
||
|
// height: String: height in pixels
|
||
|
var r = this.rawNode, rs = r.style,
|
||
|
bs = this.bgNode.style;
|
||
|
rs.width = width;
|
||
|
rs.height = height;
|
||
|
r.coordsize = width + " " + height;
|
||
|
bs.width = width;
|
||
|
bs.height = height;
|
||
|
for(var i = 0; i < this.children.length; ++i){
|
||
|
this.children[i]._setDimensions(width, height);
|
||
|
}
|
||
|
return this; // self
|
||
|
}
|
||
|
});
|
||
|
g.Group.nodeType = "group";
|
||
|
|
||
|
dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, {
|
||
|
// summary: a rectangle shape (VML)
|
||
|
setShape: function(newShape){
|
||
|
// summary: sets a rectangle shape object (VML)
|
||
|
// newShape: Object: a rectangle shape object
|
||
|
var shape = this.shape = g.makeParameters(this.shape, newShape);
|
||
|
this.bbox = null;
|
||
|
var r = Math.min(1, (shape.r / Math.min(parseFloat(shape.width), parseFloat(shape.height)))).toFixed(8);
|
||
|
// a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node
|
||
|
var parent = this.rawNode.parentNode, before = null;
|
||
|
if(parent){
|
||
|
if(parent.lastChild !== this.rawNode){
|
||
|
for(var i = 0; i < parent.childNodes.length; ++i){
|
||
|
if(parent.childNodes[i] === this.rawNode){
|
||
|
before = parent.childNodes[i + 1];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
parent.removeChild(this.rawNode);
|
||
|
}
|
||
|
if(dojo.isIE > 7){
|
||
|
var node = this.rawNode.ownerDocument.createElement("v:roundrect");
|
||
|
node.arcsize = r;
|
||
|
node.style.display = "inline-block";
|
||
|
this.rawNode = node;
|
||
|
}else{
|
||
|
this.rawNode.arcsize = r;
|
||
|
}
|
||
|
if(parent){
|
||
|
if(before){
|
||
|
parent.insertBefore(this.rawNode, before);
|
||
|
}else{
|
||
|
parent.appendChild(this.rawNode);
|
||
|
}
|
||
|
}
|
||
|
var style = this.rawNode.style;
|
||
|
style.left = shape.x.toFixed();
|
||
|
style.top = shape.y.toFixed();
|
||
|
style.width = (typeof shape.width == "string" && shape.width.indexOf("%") >= 0) ? shape.width : shape.width.toFixed();
|
||
|
style.height = (typeof shape.width == "string" && shape.height.indexOf("%") >= 0) ? shape.height : shape.height.toFixed();
|
||
|
// set all necessary styles, which are lost by VML (yes, it's a VML's bug)
|
||
|
return this.setTransform(this.matrix).setFill(this.fillStyle).setStroke(this.strokeStyle); // self
|
||
|
}
|
||
|
});
|
||
|
g.Rect.nodeType = "roundrect"; // use a roundrect so the stroke join type is respected
|
||
|
|
||
|
|
||
|
dojo.declare("dojox.gfx.Ellipse", dojox.gfx.shape.Ellipse, {
|
||
|
// summary: an ellipse shape (VML)
|
||
|
setShape: function(newShape){
|
||
|
// summary: sets an ellipse shape object (VML)
|
||
|
// newShape: Object: an ellipse shape object
|
||
|
var shape = this.shape = g.makeParameters(this.shape, newShape);
|
||
|
this.bbox = null;
|
||
|
var style = this.rawNode.style;
|
||
|
style.left = (shape.cx - shape.rx).toFixed();
|
||
|
style.top = (shape.cy - shape.ry).toFixed();
|
||
|
style.width = (shape.rx * 2).toFixed();
|
||
|
style.height = (shape.ry * 2).toFixed();
|
||
|
return this.setTransform(this.matrix); // self
|
||
|
}
|
||
|
});
|
||
|
g.Ellipse.nodeType = "oval";
|
||
|
|
||
|
dojo.declare("dojox.gfx.Circle", dojox.gfx.shape.Circle, {
|
||
|
// summary: a circle shape (VML)
|
||
|
setShape: function(newShape){
|
||
|
// summary: sets a circle shape object (VML)
|
||
|
// newShape: Object: a circle shape object
|
||
|
var shape = this.shape = g.makeParameters(this.shape, newShape);
|
||
|
this.bbox = null;
|
||
|
var style = this.rawNode.style;
|
||
|
style.left = (shape.cx - shape.r).toFixed();
|
||
|
style.top = (shape.cy - shape.r).toFixed();
|
||
|
style.width = (shape.r * 2).toFixed();
|
||
|
style.height = (shape.r * 2).toFixed();
|
||
|
return this; // self
|
||
|
}
|
||
|
});
|
||
|
g.Circle.nodeType = "oval";
|
||
|
|
||
|
dojo.declare("dojox.gfx.Line", dojox.gfx.shape.Line, {
|
||
|
// summary: a line shape (VML)
|
||
|
constructor: function(rawNode){
|
||
|
if(rawNode) rawNode.setAttribute("dojoGfxType", "line");
|
||
|
},
|
||
|
setShape: function(newShape){
|
||
|
// summary: sets a line shape object (VML)
|
||
|
// newShape: Object: a line shape object
|
||
|
var shape = this.shape = g.makeParameters(this.shape, newShape);
|
||
|
this.bbox = null;
|
||
|
this.rawNode.path.v = "m" + shape.x1.toFixed() + " " + shape.y1.toFixed() +
|
||
|
"l" + shape.x2.toFixed() + " " + shape.y2.toFixed() + "e";
|
||
|
return this.setTransform(this.matrix); // self
|
||
|
}
|
||
|
});
|
||
|
g.Line.nodeType = "shape";
|
||
|
|
||
|
dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline, {
|
||
|
// summary: a polyline/polygon shape (VML)
|
||
|
constructor: function(rawNode){
|
||
|
if(rawNode) rawNode.setAttribute("dojoGfxType", "polyline");
|
||
|
},
|
||
|
setShape: function(points, closed){
|
||
|
// summary: sets a polyline/polygon shape object (VML)
|
||
|
// points: Object: a polyline/polygon shape object
|
||
|
// closed: Boolean?: if true, close the polyline explicitely
|
||
|
if(points && points instanceof Array){
|
||
|
// branch
|
||
|
// points: Array: an array of points
|
||
|
this.shape = g.makeParameters(this.shape, { points: points });
|
||
|
if(closed && this.shape.points.length) this.shape.points.push(this.shape.points[0]);
|
||
|
}else{
|
||
|
this.shape = g.makeParameters(this.shape, points);
|
||
|
}
|
||
|
this.bbox = null;
|
||
|
var attr = [], p = this.shape.points;
|
||
|
if(p.length > 0){
|
||
|
attr.push("m");
|
||
|
var k = 1;
|
||
|
if(typeof p[0] == "number"){
|
||
|
attr.push(p[0].toFixed());
|
||
|
attr.push(p[1].toFixed());
|
||
|
k = 2;
|
||
|
}else{
|
||
|
attr.push(p[0].x.toFixed());
|
||
|
attr.push(p[0].y.toFixed());
|
||
|
}
|
||
|
if(p.length > k){
|
||
|
attr.push("l");
|
||
|
for(var i = k; i < p.length; ++i){
|
||
|
if(typeof p[i] == "number"){
|
||
|
attr.push(p[i].toFixed());
|
||
|
}else{
|
||
|
attr.push(p[i].x.toFixed());
|
||
|
attr.push(p[i].y.toFixed());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
attr.push("e");
|
||
|
this.rawNode.path.v = attr.join(" ");
|
||
|
return this.setTransform(this.matrix); // self
|
||
|
}
|
||
|
});
|
||
|
g.Polyline.nodeType = "shape";
|
||
|
|
||
|
dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, {
|
||
|
// summary: an image (VML)
|
||
|
setShape: function(newShape){
|
||
|
// summary: sets an image shape object (VML)
|
||
|
// newShape: Object: an image shape object
|
||
|
var shape = this.shape = g.makeParameters(this.shape, newShape);
|
||
|
this.bbox = null;
|
||
|
this.rawNode.firstChild.src = shape.src;
|
||
|
return this.setTransform(this.matrix); // self
|
||
|
},
|
||
|
_applyTransform: function() {
|
||
|
var matrix = this._getRealMatrix(),
|
||
|
rawNode = this.rawNode,
|
||
|
s = rawNode.style,
|
||
|
shape = this.shape;
|
||
|
if(matrix){
|
||
|
matrix = m.multiply(matrix, {dx: shape.x, dy: shape.y});
|
||
|
}else{
|
||
|
matrix = m.normalize({dx: shape.x, dy: shape.y});
|
||
|
}
|
||
|
if(matrix.xy == 0 && matrix.yx == 0 && matrix.xx > 0 && matrix.yy > 0){
|
||
|
// special case to avoid filters
|
||
|
s.filter = "";
|
||
|
s.width = Math.floor(matrix.xx * shape.width);
|
||
|
s.height = Math.floor(matrix.yy * shape.height);
|
||
|
s.left = Math.floor(matrix.dx);
|
||
|
s.top = Math.floor(matrix.dy);
|
||
|
}else{
|
||
|
var ps = rawNode.parentNode.style;
|
||
|
s.left = "0px";
|
||
|
s.top = "0px";
|
||
|
s.width = ps.width;
|
||
|
s.height = ps.height;
|
||
|
matrix = m.multiply(matrix,
|
||
|
{xx: shape.width / parseInt(s.width), yy: shape.height / parseInt(s.height)});
|
||
|
var f = rawNode.filters["DXImageTransform.Microsoft.Matrix"];
|
||
|
if(f){
|
||
|
f.M11 = matrix.xx;
|
||
|
f.M12 = matrix.xy;
|
||
|
f.M21 = matrix.yx;
|
||
|
f.M22 = matrix.yy;
|
||
|
f.Dx = matrix.dx;
|
||
|
f.Dy = matrix.dy;
|
||
|
}else{
|
||
|
s.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + matrix.xx +
|
||
|
", M12=" + matrix.xy + ", M21=" + matrix.yx + ", M22=" + matrix.yy +
|
||
|
", Dx=" + matrix.dx + ", Dy=" + matrix.dy + ")";
|
||
|
}
|
||
|
}
|
||
|
return this; // self
|
||
|
},
|
||
|
_setDimensions: function(width, height){
|
||
|
// summary: sets the width and height of the rawNode,
|
||
|
// if the surface sixe has been changed
|
||
|
// width: String: width in pixels
|
||
|
// height: String: height in pixels
|
||
|
|
||
|
var r = this.rawNode, f = r.filters["DXImageTransform.Microsoft.Matrix"];
|
||
|
if(f){
|
||
|
var s = r.style;
|
||
|
s.width = width;
|
||
|
s.height = height;
|
||
|
return this._applyTransform(); // self
|
||
|
}
|
||
|
return this; // self
|
||
|
}
|
||
|
});
|
||
|
g.Image.nodeType = "rect";
|
||
|
|
||
|
dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, {
|
||
|
// summary: an anchored text (VML)
|
||
|
constructor: function(rawNode){
|
||
|
if(rawNode){rawNode.setAttribute("dojoGfxType", "text");}
|
||
|
this.fontStyle = null;
|
||
|
},
|
||
|
_alignment: {start: "left", middle: "center", end: "right"},
|
||
|
setShape: function(newShape){
|
||
|
// summary: sets a text shape object (VML)
|
||
|
// newShape: Object: a text shape object
|
||
|
this.shape = g.makeParameters(this.shape, newShape);
|
||
|
this.bbox = null;
|
||
|
var r = this.rawNode, s = this.shape, x = s.x, y = s.y.toFixed(), path;
|
||
|
switch(s.align){
|
||
|
case "middle":
|
||
|
x -= 5;
|
||
|
break;
|
||
|
case "end":
|
||
|
x -= 10;
|
||
|
break;
|
||
|
}
|
||
|
path = "m" + x.toFixed() + "," + y + "l" + (x + 10).toFixed() + "," + y + "e";
|
||
|
// find path and text path
|
||
|
var p = null, t = null, c = r.childNodes;
|
||
|
for(var i = 0; i < c.length; ++i){
|
||
|
var tag = c[i].tagName;
|
||
|
if(tag == "path"){
|
||
|
p = c[i];
|
||
|
if(t) break;
|
||
|
}else if(tag == "textpath"){
|
||
|
t = c[i];
|
||
|
if(p) break;
|
||
|
}
|
||
|
}
|
||
|
if(!p){
|
||
|
p = r.ownerDocument.createElement("v:path");
|
||
|
r.appendChild(p);
|
||
|
}
|
||
|
if(!t){
|
||
|
t = r.ownerDocument.createElement("v:textpath");
|
||
|
r.appendChild(t);
|
||
|
}
|
||
|
p.v = path;
|
||
|
p.textPathOk = true;
|
||
|
t.on = true;
|
||
|
var a = vml.text_alignment[s.align];
|
||
|
t.style["v-text-align"] = a ? a : "left";
|
||
|
t.style["text-decoration"] = s.decoration;
|
||
|
t.style["v-rotate-letters"] = s.rotated;
|
||
|
t.style["v-text-kern"] = s.kerning;
|
||
|
t.string = s.text;
|
||
|
return this.setTransform(this.matrix); // self
|
||
|
},
|
||
|
_setFont: function(){
|
||
|
// summary: sets a font object (VML)
|
||
|
var f = this.fontStyle, c = this.rawNode.childNodes;
|
||
|
for(var i = 0; i < c.length; ++i){
|
||
|
if(c[i].tagName == "textpath"){
|
||
|
c[i].style.font = g.makeFontString(f);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
this.setTransform(this.matrix);
|
||
|
},
|
||
|
_getRealMatrix: function(){
|
||
|
// summary: returns the cumulative ("real") transformation matrix
|
||
|
// by combining the shape's matrix with its parent's matrix;
|
||
|
// it makes a correction for a font size
|
||
|
var matrix = g.Shape.prototype._getRealMatrix.call(this);
|
||
|
// It appears that text is always aligned vertically at a middle of x-height (???).
|
||
|
// It is impossible to obtain these metrics from VML => I try to approximate it with
|
||
|
// more-or-less util value of 0.7 * FontSize, which is typical for European fonts.
|
||
|
if(matrix){
|
||
|
matrix = m.multiply(matrix,
|
||
|
{dy: -g.normalizedLength(this.fontStyle ? this.fontStyle.size : "10pt") * 0.35});
|
||
|
}
|
||
|
return matrix; // dojox.gfx.Matrix2D
|
||
|
},
|
||
|
getTextWidth: function(){
|
||
|
// summary: get the text width, in px
|
||
|
var rawNode = this.rawNode, _display = rawNode.style.display;
|
||
|
rawNode.style.display = "inline";
|
||
|
var _width = g.pt2px(parseFloat(rawNode.currentStyle.width));
|
||
|
rawNode.style.display = _display;
|
||
|
return _width;
|
||
|
}
|
||
|
});
|
||
|
g.Text.nodeType = "shape";
|
||
|
|
||
|
g.path._calcArc = function(alpha){
|
||
|
// return a start point, 1st and 2nd control points, and an end point
|
||
|
var cosa = Math.cos(alpha), sina = Math.sin(alpha),
|
||
|
p2 = {x: cosa + (4 / 3) * (1 - cosa), y: sina - (4 / 3) * cosa * (1 - cosa) / sina};
|
||
|
return {
|
||
|
s: {x: cosa, y: -sina},
|
||
|
c1: {x: p2.x, y: -p2.y},
|
||
|
c2: p2,
|
||
|
e: {x: cosa, y: sina}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, {
|
||
|
// summary: a path shape (VML)
|
||
|
constructor: function(rawNode){
|
||
|
if(rawNode && !rawNode.getAttribute("dojoGfxType")){
|
||
|
rawNode.setAttribute("dojoGfxType", "path");
|
||
|
}
|
||
|
this.vmlPath = "";
|
||
|
this.lastControl = {};
|
||
|
},
|
||
|
_updateWithSegment: function(segment){
|
||
|
// summary: updates the bounding box of path with new segment
|
||
|
// segment: Object: a segment
|
||
|
var last = dojo.clone(this.last);
|
||
|
g.Path.superclass._updateWithSegment.apply(this, arguments);
|
||
|
// add a VML path segment
|
||
|
var path = this[this.renderers[segment.action]](segment, last);
|
||
|
if(typeof this.vmlPath == "string"){
|
||
|
this.vmlPath += path.join("");
|
||
|
this.rawNode.path.v = this.vmlPath + " r0,0 e";
|
||
|
}else{
|
||
|
Array.prototype.push.apply(this.vmlPath, path);
|
||
|
}
|
||
|
},
|
||
|
setShape: function(newShape){
|
||
|
// summary: forms a path using a shape (VML)
|
||
|
// newShape: Object: an VML path string or a path object (see dojox.gfx.defaultPath)
|
||
|
this.vmlPath = [];
|
||
|
this.lastControl.type = ""; // no prior control point
|
||
|
g.Path.superclass.setShape.apply(this, arguments);
|
||
|
this.vmlPath = this.vmlPath.join("");
|
||
|
this.rawNode.path.v = this.vmlPath + " r0,0 e";
|
||
|
return this;
|
||
|
},
|
||
|
_pathVmlToSvgMap: {m: "M", l: "L", t: "m", r: "l", c: "C", v: "c", qb: "Q", x: "z", e: ""},
|
||
|
// VML-specific segment renderers
|
||
|
renderers: {
|
||
|
M: "_moveToA", m: "_moveToR",
|
||
|
L: "_lineToA", l: "_lineToR",
|
||
|
H: "_hLineToA", h: "_hLineToR",
|
||
|
V: "_vLineToA", v: "_vLineToR",
|
||
|
C: "_curveToA", c: "_curveToR",
|
||
|
S: "_smoothCurveToA", s: "_smoothCurveToR",
|
||
|
Q: "_qCurveToA", q: "_qCurveToR",
|
||
|
T: "_qSmoothCurveToA", t: "_qSmoothCurveToR",
|
||
|
A: "_arcTo", a: "_arcTo",
|
||
|
Z: "_closePath", z: "_closePath"
|
||
|
},
|
||
|
_addArgs: function(path, segment, from, upto){
|
||
|
var n = segment instanceof Array ? segment : segment.args;
|
||
|
for(var i = from; i < upto; ++i){
|
||
|
path.push(" ", n[i].toFixed());
|
||
|
}
|
||
|
},
|
||
|
_adjustRelCrd: function(last, segment, step){
|
||
|
var n = segment instanceof Array ? segment : segment.args, l = n.length,
|
||
|
result = new Array(l), i = 0, x = last.x, y = last.y;
|
||
|
if(typeof x != "number"){
|
||
|
// there is no last coordinate =>
|
||
|
// treat the first pair as an absolute coordinate
|
||
|
result[0] = x = n[0];
|
||
|
result[1] = y = n[1];
|
||
|
i = 2;
|
||
|
}
|
||
|
if(typeof step == "number" && step != 2){
|
||
|
var j = step;
|
||
|
while(j <= l){
|
||
|
for(; i < j; i += 2){
|
||
|
result[i] = x + n[i];
|
||
|
result[i + 1] = y + n[i + 1];
|
||
|
}
|
||
|
x = result[j - 2];
|
||
|
y = result[j - 1];
|
||
|
j += step;
|
||
|
}
|
||
|
}else{
|
||
|
for(; i < l; i += 2){
|
||
|
result[i] = (x += n[i]);
|
||
|
result[i + 1] = (y += n[i + 1]);
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
},
|
||
|
_adjustRelPos: function(last, segment){
|
||
|
var n = segment instanceof Array ? segment : segment.args, l = n.length,
|
||
|
result = new Array(l);
|
||
|
for(var i = 0; i < l; ++i){
|
||
|
result[i] = (last += n[i]);
|
||
|
}
|
||
|
return result;
|
||
|
},
|
||
|
_moveToA: function(segment){
|
||
|
var p = [" m"], n = segment instanceof Array ? segment : segment.args, l = n.length;
|
||
|
this._addArgs(p, n, 0, 2);
|
||
|
if(l > 2){
|
||
|
p.push(" l");
|
||
|
this._addArgs(p, n, 2, l);
|
||
|
}
|
||
|
this.lastControl.type = ""; // no control point after this primitive
|
||
|
return p;
|
||
|
},
|
||
|
_moveToR: function(segment, last){
|
||
|
return this._moveToA(this._adjustRelCrd(last, segment));
|
||
|
},
|
||
|
_lineToA: function(segment){
|
||
|
var p = [" l"], n = segment instanceof Array ? segment : segment.args;
|
||
|
this._addArgs(p, n, 0, n.length);
|
||
|
this.lastControl.type = ""; // no control point after this primitive
|
||
|
return p;
|
||
|
},
|
||
|
_lineToR: function(segment, last){
|
||
|
return this._lineToA(this._adjustRelCrd(last, segment));
|
||
|
},
|
||
|
_hLineToA: function(segment, last){
|
||
|
var p = [" l"], y = " " + last.y.toFixed(),
|
||
|
n = segment instanceof Array ? segment : segment.args, l = n.length;
|
||
|
for(var i = 0; i < l; ++i){
|
||
|
p.push(" ", n[i].toFixed(), y);
|
||
|
}
|
||
|
this.lastControl.type = ""; // no control point after this primitive
|
||
|
return p;
|
||
|
},
|
||
|
_hLineToR: function(segment, last){
|
||
|
return this._hLineToA(this._adjustRelPos(last.x, segment), last);
|
||
|
},
|
||
|
_vLineToA: function(segment, last){
|
||
|
var p = [" l"], x = " " + last.x.toFixed(),
|
||
|
n = segment instanceof Array ? segment : segment.args, l = n.length;
|
||
|
for(var i = 0; i < l; ++i){
|
||
|
p.push(x, " ", n[i].toFixed());
|
||
|
}
|
||
|
this.lastControl.type = ""; // no control point after this primitive
|
||
|
return p;
|
||
|
},
|
||
|
_vLineToR: function(segment, last){
|
||
|
return this._vLineToA(this._adjustRelPos(last.y, segment), last);
|
||
|
},
|
||
|
_curveToA: function(segment){
|
||
|
var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
|
||
|
lc = this.lastControl;
|
||
|
for(var i = 0; i < l; i += 6){
|
||
|
p.push(" c");
|
||
|
this._addArgs(p, n, i, i + 6);
|
||
|
}
|
||
|
lc.x = n[l - 4];
|
||
|
lc.y = n[l - 3];
|
||
|
lc.type = "C";
|
||
|
return p;
|
||
|
},
|
||
|
_curveToR: function(segment, last){
|
||
|
return this._curveToA(this._adjustRelCrd(last, segment, 6));
|
||
|
},
|
||
|
_smoothCurveToA: function(segment, last){
|
||
|
var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
|
||
|
lc = this.lastControl, i = 0;
|
||
|
if(lc.type != "C"){
|
||
|
p.push(" c");
|
||
|
this._addArgs(p, [last.x, last.y], 0, 2);
|
||
|
this._addArgs(p, n, 0, 4);
|
||
|
lc.x = n[0];
|
||
|
lc.y = n[1];
|
||
|
lc.type = "C";
|
||
|
i = 4;
|
||
|
}
|
||
|
for(; i < l; i += 4){
|
||
|
p.push(" c");
|
||
|
this._addArgs(p, [
|
||
|
2 * last.x - lc.x,
|
||
|
2 * last.y - lc.y
|
||
|
], 0, 2);
|
||
|
this._addArgs(p, n, i, i + 4);
|
||
|
lc.x = n[i];
|
||
|
lc.y = n[i + 1];
|
||
|
}
|
||
|
return p;
|
||
|
},
|
||
|
_smoothCurveToR: function(segment, last){
|
||
|
return this._smoothCurveToA(this._adjustRelCrd(last, segment, 4), last);
|
||
|
},
|
||
|
_qCurveToA: function(segment){
|
||
|
var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
|
||
|
lc = this.lastControl;
|
||
|
for(var i = 0; i < l; i += 4){
|
||
|
p.push(" qb");
|
||
|
this._addArgs(p, n, i, i + 4);
|
||
|
}
|
||
|
lc.x = n[l - 4];
|
||
|
lc.y = n[l - 3];
|
||
|
lc.type = "Q";
|
||
|
return p;
|
||
|
},
|
||
|
_qCurveToR: function(segment, last){
|
||
|
return this._qCurveToA(this._adjustRelCrd(last, segment, 4));
|
||
|
},
|
||
|
_qSmoothCurveToA: function(segment, last){
|
||
|
var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
|
||
|
lc = this.lastControl, i = 0;
|
||
|
if(lc.type != "Q"){
|
||
|
p.push(" qb");
|
||
|
this._addArgs(p, [
|
||
|
lc.x = last.x,
|
||
|
lc.y = last.y
|
||
|
], 0, 2);
|
||
|
lc.type = "Q";
|
||
|
this._addArgs(p, n, 0, 2);
|
||
|
i = 2;
|
||
|
}
|
||
|
for(; i < l; i += 2){
|
||
|
p.push(" qb");
|
||
|
this._addArgs(p, [
|
||
|
lc.x = 2 * last.x - lc.x,
|
||
|
lc.y = 2 * last.y - lc.y
|
||
|
], 0, 2);
|
||
|
this._addArgs(p, n, i, i + 2);
|
||
|
}
|
||
|
return p;
|
||
|
},
|
||
|
_qSmoothCurveToR: function(segment, last){
|
||
|
return this._qSmoothCurveToA(this._adjustRelCrd(last, segment, 2), last);
|
||
|
},
|
||
|
_arcTo: function(segment, last){
|
||
|
var p = [], n = segment.args, l = n.length, relative = segment.action == "a";
|
||
|
for(var i = 0; i < l; i += 7){
|
||
|
var x1 = n[i + 5], y1 = n[i + 6];
|
||
|
if(relative){
|
||
|
x1 += last.x;
|
||
|
y1 += last.y;
|
||
|
}
|
||
|
var result = g.arc.arcAsBezier(
|
||
|
last, n[i], n[i + 1], n[i + 2],
|
||
|
n[i + 3] ? 1 : 0, n[i + 4] ? 1 : 0,
|
||
|
x1, y1
|
||
|
);
|
||
|
for(var j = 0; j < result.length; ++j){
|
||
|
p.push(" c");
|
||
|
var t = result[j];
|
||
|
this._addArgs(p, t, 0, t.length);
|
||
|
}
|
||
|
last.x = x1;
|
||
|
last.y = y1;
|
||
|
}
|
||
|
this.lastControl.type = ""; // no control point after this primitive
|
||
|
return p;
|
||
|
},
|
||
|
_closePath: function(){
|
||
|
this.lastControl.type = ""; // no control point after this primitive
|
||
|
return ["x"];
|
||
|
}
|
||
|
});
|
||
|
g.Path.nodeType = "shape";
|
||
|
|
||
|
dojo.declare("dojox.gfx.TextPath", dojox.gfx.Path, {
|
||
|
// summary: a textpath shape (VML)
|
||
|
constructor: function(rawNode){
|
||
|
if(rawNode){rawNode.setAttribute("dojoGfxType", "textpath");}
|
||
|
this.fontStyle = null;
|
||
|
if(!("text" in this)){
|
||
|
this.text = dojo.clone(g.defaultTextPath);
|
||
|
}
|
||
|
if(!("fontStyle" in this)){
|
||
|
this.fontStyle = dojo.clone(g.defaultFont);
|
||
|
}
|
||
|
},
|
||
|
setText: function(newText){
|
||
|
// summary: sets a text to be drawn along the path
|
||
|
this.text = g.makeParameters(this.text,
|
||
|
typeof newText == "string" ? {text: newText} : newText);
|
||
|
this._setText();
|
||
|
return this; // self
|
||
|
},
|
||
|
setFont: function(newFont){
|
||
|
// summary: sets a font for text
|
||
|
this.fontStyle = typeof newFont == "string" ?
|
||
|
g.splitFontString(newFont) :
|
||
|
g.makeParameters(g.defaultFont, newFont);
|
||
|
this._setFont();
|
||
|
return this; // self
|
||
|
},
|
||
|
|
||
|
_setText: function(){
|
||
|
// summary: sets a text shape object (VML)
|
||
|
this.bbox = null;
|
||
|
var r = this.rawNode, s = this.text,
|
||
|
// find path and text path
|
||
|
p = null, t = null, c = r.childNodes;
|
||
|
for(var i = 0; i < c.length; ++i){
|
||
|
var tag = c[i].tagName;
|
||
|
if(tag == "path"){
|
||
|
p = c[i];
|
||
|
if(t) break;
|
||
|
}else if(tag == "textpath"){
|
||
|
t = c[i];
|
||
|
if(p) break;
|
||
|
}
|
||
|
}
|
||
|
if(!p){
|
||
|
p = this.rawNode.ownerDocument.createElement("v:path");
|
||
|
r.appendChild(p);
|
||
|
}
|
||
|
if(!t){
|
||
|
t = this.rawNode.ownerDocument.createElement("v:textpath");
|
||
|
r.appendChild(t);
|
||
|
}
|
||
|
p.textPathOk = true;
|
||
|
t.on = true;
|
||
|
var a = vml.text_alignment[s.align];
|
||
|
t.style["v-text-align"] = a ? a : "left";
|
||
|
t.style["text-decoration"] = s.decoration;
|
||
|
t.style["v-rotate-letters"] = s.rotated;
|
||
|
t.style["v-text-kern"] = s.kerning;
|
||
|
t.string = s.text;
|
||
|
},
|
||
|
_setFont: function(){
|
||
|
// summary: sets a font object (VML)
|
||
|
var f = this.fontStyle, c = this.rawNode.childNodes;
|
||
|
for(var i = 0; i < c.length; ++i){
|
||
|
if(c[i].tagName == "textpath"){
|
||
|
c[i].style.font = g.makeFontString(f);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
g.TextPath.nodeType = "shape";
|
||
|
|
||
|
dojo.declare("dojox.gfx.Surface", dojox.gfx.shape.Surface, {
|
||
|
// summary: a surface object to be used for drawings (VML)
|
||
|
constructor: function(){
|
||
|
vml.Container._init.call(this);
|
||
|
},
|
||
|
setDimensions: function(width, height){
|
||
|
// summary: sets the width and height of the rawNode
|
||
|
// width: String: width of surface, e.g., "100px"
|
||
|
// height: String: height of surface, e.g., "100px"
|
||
|
this.width = g.normalizedLength(width); // in pixels
|
||
|
this.height = g.normalizedLength(height); // in pixels
|
||
|
if(!this.rawNode) return this;
|
||
|
var cs = this.clipNode.style,
|
||
|
r = this.rawNode, rs = r.style,
|
||
|
bs = this.bgNode.style,
|
||
|
ps = this._parent.style, i;
|
||
|
ps.width = width;
|
||
|
ps.height = height;
|
||
|
cs.width = width;
|
||
|
cs.height = height;
|
||
|
cs.clip = "rect(0px " + width + "px " + height + "px 0px)";
|
||
|
rs.width = width;
|
||
|
rs.height = height;
|
||
|
r.coordsize = width + " " + height;
|
||
|
bs.width = width;
|
||
|
bs.height = height;
|
||
|
for(i = 0; i < this.children.length; ++i){
|
||
|
this.children[i]._setDimensions(width, height);
|
||
|
}
|
||
|
return this; // self
|
||
|
},
|
||
|
getDimensions: function(){
|
||
|
// summary: returns an object with properties "width" and "height"
|
||
|
var t = this.rawNode ? {
|
||
|
width: g.normalizedLength(this.rawNode.style.width),
|
||
|
height: g.normalizedLength(this.rawNode.style.height)} : null;
|
||
|
if(t.width <= 0){ t.width = this.width; }
|
||
|
if(t.height <= 0){ t.height = this.height; }
|
||
|
return t; // Object
|
||
|
}
|
||
|
});
|
||
|
|
||
|
dojox.gfx.createSurface = function(parentNode, width, height){
|
||
|
// summary: creates a surface (VML)
|
||
|
// parentNode: Node: a parent node
|
||
|
// width: String: width of surface, e.g., "100px"
|
||
|
// height: String: height of surface, e.g., "100px"
|
||
|
|
||
|
if(!width){ width = "100%"; }
|
||
|
if(!height){ height = "100%"; }
|
||
|
var s = new g.Surface(), p = dojo.byId(parentNode),
|
||
|
c = s.clipNode = p.ownerDocument.createElement("div"),
|
||
|
r = s.rawNode = p.ownerDocument.createElement("v:group"),
|
||
|
cs = c.style, rs = r.style;
|
||
|
|
||
|
if(dojo.isIE > 7){
|
||
|
rs.display = "inline-block";
|
||
|
}
|
||
|
|
||
|
s._parent = p;
|
||
|
s._nodes.push(c); // other elements will be deleted as parts of "c"
|
||
|
|
||
|
p.style.width = width;
|
||
|
p.style.height = height;
|
||
|
|
||
|
cs.position = "absolute";
|
||
|
cs.width = width;
|
||
|
cs.height = height;
|
||
|
cs.clip = "rect(0px " + width + "px " + height + "px 0px)";
|
||
|
rs.position = "absolute";
|
||
|
rs.width = width;
|
||
|
rs.height = height;
|
||
|
r.coordsize = (width == "100%" ? width : parseFloat(width)) + " " +
|
||
|
(height == "100%" ? height : parseFloat(height));
|
||
|
r.coordorigin = "0 0";
|
||
|
|
||
|
// create a background rectangle, which is required to show all other shapes
|
||
|
var b = s.bgNode = r.ownerDocument.createElement("v:rect"), bs = b.style;
|
||
|
bs.left = bs.top = 0;
|
||
|
bs.width = rs.width;
|
||
|
bs.height = rs.height;
|
||
|
b.filled = b.stroked = "f";
|
||
|
|
||
|
r.appendChild(b);
|
||
|
c.appendChild(r);
|
||
|
p.appendChild(c);
|
||
|
|
||
|
s.width = g.normalizedLength(width); // in pixels
|
||
|
s.height = g.normalizedLength(height); // in pixels
|
||
|
|
||
|
|
||
|
return s; // dojox.gfx.Surface
|
||
|
};
|
||
|
|
||
|
// Extenders
|
||
|
|
||
|
|
||
|
vml.Container = {
|
||
|
_init: function(){
|
||
|
sh.Container._init.call(this);
|
||
|
},
|
||
|
add: function(shape){
|
||
|
// summary: adds a shape to a group/surface
|
||
|
// shape: dojox.gfx.Shape: an VML shape object
|
||
|
if(this != shape.getParent()){
|
||
|
this.rawNode.appendChild(shape.rawNode);
|
||
|
if(!shape.getParent()){
|
||
|
// reapply visual attributes
|
||
|
shape.setFill(shape.getFill());
|
||
|
shape.setStroke(shape.getStroke());
|
||
|
}
|
||
|
//dojox.gfx.Group.superclass.add.apply(this, arguments);
|
||
|
//this.inherited(arguments);
|
||
|
sh.Container.add.apply(this, arguments);
|
||
|
}
|
||
|
return this; // self
|
||
|
},
|
||
|
remove: function(shape, silently){
|
||
|
// summary: remove a shape from a group/surface
|
||
|
// shape: dojox.gfx.Shape: an VML shape object
|
||
|
// silently: Boolean?: if true, regenerate a picture
|
||
|
if(this == shape.getParent()){
|
||
|
if(this.rawNode == shape.rawNode.parentNode){
|
||
|
this.rawNode.removeChild(shape.rawNode);
|
||
|
}
|
||
|
//dojox.gfx.Group.superclass.remove.apply(this, arguments);
|
||
|
//this.inherited(arguments);
|
||
|
sh.Container.remove.apply(this, arguments);
|
||
|
}
|
||
|
return this; // self
|
||
|
},
|
||
|
clear: function(){
|
||
|
// summary: removes all shapes from a group/surface
|
||
|
var r = this.rawNode;
|
||
|
while(r.firstChild != r.lastChild){
|
||
|
if(r.firstChild != this.bgNode){
|
||
|
r.removeChild(r.firstChild);
|
||
|
}
|
||
|
if(r.lastChild != this.bgNode){
|
||
|
r.removeChild(r.lastChild);
|
||
|
}
|
||
|
}
|
||
|
//return this.inherited(arguments); // self
|
||
|
return sh.Container.clear.apply(this, arguments);
|
||
|
},
|
||
|
_moveChildToFront: sh.Container._moveChildToFront,
|
||
|
_moveChildToBack: sh.Container._moveChildToBack
|
||
|
};
|
||
|
|
||
|
dojo.mixin(sh.Creator, {
|
||
|
// summary: VML shape creators
|
||
|
createGroup: function(){
|
||
|
// summary: creates a VML group shape
|
||
|
var node = this.createObject(g.Group, null); // dojox.gfx.Group
|
||
|
// create a background rectangle, which is required to show all other shapes
|
||
|
var r = node.rawNode.ownerDocument.createElement("v:rect");
|
||
|
r.style.left = r.style.top = 0;
|
||
|
r.style.width = node.rawNode.style.width;
|
||
|
r.style.height = node.rawNode.style.height;
|
||
|
r.filled = r.stroked = "f";
|
||
|
node.rawNode.appendChild(r);
|
||
|
node.bgNode = r;
|
||
|
return node; // dojox.gfx.Group
|
||
|
},
|
||
|
createImage: function(image){
|
||
|
// summary: creates a VML image shape
|
||
|
// image: Object: an image object (see dojox.gfx.defaultImage)
|
||
|
if(!this.rawNode) return null;
|
||
|
var shape = new g.Image(),
|
||
|
doc = this.rawNode.ownerDocument,
|
||
|
node = doc.createElement('v:rect');
|
||
|
node.stroked = "f";
|
||
|
node.style.width = this.rawNode.style.width;
|
||
|
node.style.height = this.rawNode.style.height;
|
||
|
var img = doc.createElement('v:imagedata');
|
||
|
node.appendChild(img);
|
||
|
shape.setRawNode(node);
|
||
|
this.rawNode.appendChild(node);
|
||
|
shape.setShape(image);
|
||
|
this.add(shape);
|
||
|
return shape; // dojox.gfx.Image
|
||
|
},
|
||
|
createRect: function(rect){
|
||
|
// summary: creates a rectangle shape
|
||
|
// rect: Object: a path object (see dojox.gfx.defaultRect)
|
||
|
if(!this.rawNode) return null;
|
||
|
var shape = new g.Rect,
|
||
|
node = this.rawNode.ownerDocument.createElement("v:roundrect");
|
||
|
if(dojo.isIE > 7){
|
||
|
node.style.display = "inline-block";
|
||
|
}
|
||
|
shape.setRawNode(node);
|
||
|
this.rawNode.appendChild(node);
|
||
|
shape.setShape(rect);
|
||
|
this.add(shape);
|
||
|
return shape; // dojox.gfx.Rect
|
||
|
},
|
||
|
createObject: function(shapeType, rawShape) {
|
||
|
// summary: creates an instance of the passed shapeType class
|
||
|
// shapeType: Function: a class constructor to create an instance of
|
||
|
// rawShape: Object: properties to be passed in to the classes "setShape" method
|
||
|
// overrideSize: Boolean: set the size explicitly, if true
|
||
|
if(!this.rawNode) return null;
|
||
|
var shape = new shapeType(),
|
||
|
node = this.rawNode.ownerDocument.createElement('v:' + shapeType.nodeType);
|
||
|
shape.setRawNode(node);
|
||
|
this.rawNode.appendChild(node);
|
||
|
switch(shapeType){
|
||
|
case g.Group:
|
||
|
case g.Line:
|
||
|
case g.Polyline:
|
||
|
case g.Image:
|
||
|
case g.Text:
|
||
|
case g.Path:
|
||
|
case g.TextPath:
|
||
|
this._overrideSize(node);
|
||
|
}
|
||
|
shape.setShape(rawShape);
|
||
|
this.add(shape);
|
||
|
return shape; // dojox.gfx.Shape
|
||
|
},
|
||
|
_overrideSize: function(node){
|
||
|
var s = this.rawNode.style, w = s.width, h = s.height;
|
||
|
node.style.width = w;
|
||
|
node.style.height = h;
|
||
|
node.coordsize = parseInt(w) + " " + parseInt(h);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
dojo.extend(g.Group, vml.Container);
|
||
|
dojo.extend(g.Group, sh.Creator);
|
||
|
|
||
|
dojo.extend(g.Surface, vml.Container);
|
||
|
dojo.extend(g.Surface, sh.Creator);
|
||
|
|
||
|
})();
|