source: [view]
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");
dojo.require("dojox.gfx.gradient");
(function(){
var d = dojo, g = dojox.gfx, m = g.matrix, gs = g.shape, vml = g.vml;
// 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};
d.declare("dojox.gfx.vml.Shape", gs.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(), bbox = this.getBoundingBox(),
tbbox = this._getRealBBox ? this._getRealBBox() : this.getTransformedBoundingBox();
s = [];
if(this.fillStyle !== fill){
this.fillStyle = g.makeParameters(g.defaultLinearGradient, fill);
}
f = g.gradient.project(matrix, this.fillStyle,
{x: bbox.x, y: bbox.y},
{x: bbox.x + bbox.width, y: bbox.y + bbox.height},
tbbox[0], tbbox[2]);
a = f.colors;
if(a[0].offset.toFixed(5) != "0.00000"){
s.push("0 " + g.normalizeColor(a[0].color).toHex());
}
for(i = 0; i < a.length; ++i){
s.push(a[i].offset.toFixed(5) + " " + g.normalizeColor(a[i].color).toHex());
}
i = a.length - 1;
if(a[i].offset.toFixed(5) != "1.00000"){
s.push("1 " + g.normalizeColor(a[i].color).toHex());
}
fo = this.rawNode.fill;
fo.colors.value = s.join(";");
fo.method = "sigma";
fo.type = "gradient";
fo.angle = (270 - m._radToDeg(f.angle)) % 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
d.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 = d.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(5) + " " + 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(5) + " " + ((f.cy - t) / h).toFixed(5);
}
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;
var alphaFilter = this.rawNode.filters["DXImageTransform.Microsoft.Alpha"];
if(alphaFilter){
alphaFilter.opacity = Math.round(this.fillStyle.a * 100);
}
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" || d.isArray(stroke) || stroke instanceof d.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() {
var matrix = this._getRealMatrix();
if(matrix){
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) w = 1;
if(isNaN(h) || !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;
}
}
if(this.fillStyle && this.fillStyle.type == "linear"){
this.setFill(this.fillStyle);
}
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