source: [view]
dojo.provide("dojox.gfx.silverlight");
dojo.require("dojox.gfx._base");
dojo.require("dojox.gfx.shape");
dojo.require("dojox.gfx.path");
dojo.experimental("dojox.gfx.silverlight");
(function(){
var d = dojo, g = dojox.gfx, gs = g.shape, sl = g.silverlight;
var dasharray = {
solid: "none",
shortdash: [4, 1],
shortdot: [1, 1],
shortdashdot: [4, 1, 1, 1],
shortdashdotdot: [4, 1, 1, 1, 1, 1],
dot: [1, 3],
dash: [4, 3],
longdash: [8, 3],
dashdot: [4, 3, 1, 3],
longdashdot: [8, 3, 1, 3],
longdashdotdot: [8, 3, 1, 3, 1, 3]
},
fontweight = {
normal: 400,
bold: 700
},
caps = {butt: "Flat", round: "Round", square: "Square"},
joins = {bevel: "Bevel", round: "Round"},
fonts = {
serif: "Times New Roman",
times: "Times New Roman",
"sans-serif": "Arial",
helvetica: "Arial",
monotone: "Courier New",
courier: "Courier New"
};
function hexColor(/*String|Array|dojo.Color*/ color){
// summary: converts a color object to a Silverlight hex color string (#aarrggbb)
var c = g.normalizeColor(color),
t = c.toHex(), a = Math.round(c.a * 255);
a = (a < 0 ? 0 : a > 255 ? 255 : a).toString(16);
return "#" + (a.length < 2 ? "0" + a : a) + t.slice(1); // String
}
d.declare("dojox.gfx.silverlight.Shape", gs.Shape, {
// summary: Silverlight-specific implementation of dojox.gfx.Shape methods
setFill: function(fill){
// summary: sets a fill object (Silverlight)
// fill: Object: a fill object
// (see dojox.gfx.defaultLinearGradient,
// dojox.gfx.defaultRadialGradient,
// dojox.gfx.defaultPattern,
// or dojo.Color)
var p = this.rawNode.getHost().content, r = this.rawNode, f;
if(!fill){
// don't fill
this.fillStyle = null;
this._setFillAttr(null);
return this; // self
}
if(typeof(fill) == "object" && "type" in fill){
// gradient
switch(fill.type){
case "linear":
this.fillStyle = f = g.makeParameters(g.defaultLinearGradient, fill);
var lgb = p.createFromXaml("");
lgb.mappingMode = "Absolute";
lgb.startPoint = f.x1 + "," + f.y1;
lgb.endPoint = f.x2 + "," + f.y2;
d.forEach(f.colors, function(c){
var t = p.createFromXaml("");
t.offset = c.offset;
t.color = hexColor(c.color);
lgb.gradientStops.add(t);
});
this._setFillAttr(lgb);
break;
case "radial":
this.fillStyle = f = g.makeParameters(g.defaultRadialGradient, fill);
var rgb = p.createFromXaml(""),
c = g.matrix.multiplyPoint(g.matrix.invert(this._getAdjustedMatrix()), f.cx, f.cy),
pt = c.x + "," + c.y;
rgb.mappingMode = "Absolute";
rgb.gradientOrigin = pt;
rgb.center = pt;
rgb.radiusX = rgb.radiusY = f.r;
d.forEach(f.colors, function(c){
var t = p.createFromXaml("");
t.offset = c.offset;
t.color = hexColor(c.color);
rgb.gradientStops.add(t);
});
this._setFillAttr(rgb);
break;
case "pattern":
// don't fill: Silverlight doesn't define TileBrush for some reason
this.fillStyle = null;
this._setFillAttr(null);
break;
}
return this; // self
}
// color object
this.fillStyle = f = g.normalizeColor(fill);
var scb = p.createFromXaml("");
scb.color = f.toHex();
scb.opacity = f.a;
this._setFillAttr(scb);
return this; // self
},
_setFillAttr: function(f){
this.rawNode.fill = f;
},
setStroke: function(stroke){
// summary: sets a stroke object (Silverlight)
// stroke: Object: a stroke object
// (see dojox.gfx.defaultStroke)
var p = this.rawNode.getHost().content, r = this.rawNode;
if(!stroke){
// don't stroke
this.strokeStyle = null;
r.stroke = null;
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
if(s){
var scb = p.createFromXaml("");
scb.color = s.color.toHex();
scb.opacity = s.color.a;
r.stroke = scb;
r.strokeThickness = s.width;
r.strokeStartLineCap = r.strokeEndLineCap = r.strokeDashCap =
caps[s.cap];
if(typeof s.join == "number"){
r.strokeLineJoin = "Miter";
r.strokeMiterLimit = s.join;
}else{
r.strokeLineJoin = joins[s.join];
}
var da = s.style.toLowerCase();
if(da in dasharray){ da = dasharray[da]; }
if(da instanceof Array){
da = d.clone(da);
var i;
/*
for(var i = 0; i < da.length; ++i){
da[i] *= s.width;
}
*/
if(s.cap != "butt"){
for(i = 0; i < da.length; i += 2){
//da[i] -= s.width;
--da[i]
if(da[i] < 1){ da[i] = 1; }
}
for(i = 1; i < da.length; i += 2){
//da[i] += s.width;
++da[i];
}
}
r.strokeDashArray = da.join(",");
}else{
r.strokeDashArray = null;
}
}
return this; // self
},
_getParentSurface: function(){
var surface = this.parent;
for(; surface && !(surface instanceof g.Surface); surface = surface.parent);
return surface;
},
_applyTransform: function() {
var tm = this._getAdjustedMatrix(), r = this.rawNode;
if(tm){
var p = this.rawNode.getHost().content,
mt = p.createFromXaml(""),
mm = p.createFromXaml("");
mm.m11 = tm.xx;
mm.m21 = tm.xy;
mm.m12 = tm.yx;
mm.m22 = tm.yy;
mm.offsetX = tm.dx;
mm.offsetY = tm.dy;
mt.matrix = mm;
r.renderTransform = mt;
}else{
r.renderTransform = null;
}
return this;
},
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.fill = null;
rawNode.stroke = null;
this.rawNode = rawNode;
},
// move family
_moveToFront: function(){
// summary: moves a shape to front of its parent's list of shapes (Silverlight)
var c = this.parent.rawNode.children, r = this.rawNode;
c.remove(r);
c.add(r);
return this; // self
},
_moveToBack: function(){
// summary: moves a shape to back of its parent's list of shapes (Silverlight)
var c = this.parent.rawNode.children, r = this.rawNode;
c.remove(r);
c.insert(0, r);
return this; // self
},
_getAdjustedMatrix: function(){
// summary: returns the adjusted ("real") transformation matrix
return this.matrix; // dojox.gfx.Matrix2D
}
});
d.declare("dojox.gfx.silverlight.Group", sl.Shape, {
// summary: a group shape (Silverlight), which can be used
// to logically group shapes (e.g, to propagate matricies)
constructor: function(){
gs.Container._init.call(this);
},
setRawNode: function(rawNode){
// summary: sets a raw Silverlight node to be used by this shape
// rawNode: Node: an Silverlight node
this.rawNode = rawNode;
}
});
sl.Group.nodeType = "Canvas";
d.declare("dojox.gfx.silverlight.Rect", [sl.Shape, gs.Rect], {
// summary: a rectangle shape (Silverlight)
setShape: function(newShape){
// summary: sets a rectangle shape object (Silverlight)
// newShape: Object: a rectangle shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
var r = this.rawNode, n = this.shape;
r.width = n.width;
r.height = n.height;
r.radiusX = r.radiusY = n.r;
return this._applyTransform(); // self
},
_getAdjustedMatrix: function(){
// summary: returns the adjusted ("real") transformation matrix
var matrix = this.matrix, s = this.shape, delta = {dx: s.x, dy: s.y};
return new g.Matrix2D(matrix ? [matrix, delta] : delta); // dojox.gfx.Matrix2D
}
});
sl.Rect.nodeType = "Rectangle";
d.declare("dojox.gfx.silverlight.Ellipse", [sl.Shape, gs.Ellipse], {
// summary: an ellipse shape (Silverlight)
setShape: function(newShape){
// summary: sets an ellipse shape object (Silverlight)
// newShape: Object: an ellipse shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
var r = this.rawNode, n = this.shape;
r.width = 2 * n.rx;
r.height = 2 * n.ry;
return this._applyTransform(); // self
},
_getAdjustedMatrix: function(){
// summary: returns the adjusted ("real") transformation matrix
var matrix = this.matrix, s = this.shape, delta = {dx: s.cx - s.rx, dy: s.cy - s.ry};
return new g.Matrix2D(matrix ? [matrix, delta] : delta); // dojox.gfx.Matrix2D
}
});
sl.Ellipse.nodeType = "Ellipse";
d.declare("dojox.gfx.silverlight.Circle", [sl.Shape, gs.Circle], {
// summary: a circle shape (Silverlight)
setShape: function(newShape){
// summary: sets a circle shape object (Silverlight)
// newShape: Object: a circle shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
var r = this.rawNode, n = this.shape;
r.width = r.height = 2 * n.r;
return this._applyTransform(); // self
},
_getAdjustedMatrix: function(){
// summary: returns the adjusted ("real") transformation matrix
var matrix = this.matrix, s = this.shape, delta = {dx: s.cx - s.r, dy: s.cy - s.r};
return new g.Matrix2D(matrix ? [matrix, delta] : delta); // dojox.gfx.Matrix2D
}
});
sl.Circle.nodeType = "Ellipse";
d.declare("dojox.gfx.silverlight.Line", [sl.Shape, gs.Line], {
// summary: a line shape (Silverlight)
setShape: function(newShape){
// summary: sets a line shape object (Silverlight)
// newShape: Object: a line shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
var r = this.rawNode, n = this.shape;
r.x1 = n.x1; r.y1 = n.y1; r.x2 = n.x2; r.y2 = n.y2;
return this; // self
}
});
sl.Line.nodeType = "Line";
d.declare("dojox.gfx.silverlight.Polyline", [sl.Shape, gs.Polyline], {
// summary: a polyline/polygon shape (Silverlight)
setShape: function(points, closed){
// summary: sets a polyline/polygon shape object (Silverlight)
// points: Object: a polyline/polygon shape object
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;
this._normalizePoints();
var p = this.shape.points, rp = [];
for(var i = 0; i < p.length; ++i){
rp.push(p[i].x, p[i].y);
}
this.rawNode.points = rp.join(",");
return this; // self
}
});
sl.Polyline.nodeType = "Polyline";
d.declare("dojox.gfx.silverlight.Image", [sl.Shape, gs.Image], {
// summary: an image (Silverlight)
setShape: function(newShape){
// summary: sets an image shape object (Silverlight)
// newShape: Object: an image shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
var r = this.rawNode, n = this.shape;
r.width = n.width;
r.height = n.height;
r.source = n.src;
return this._applyTransform(); // self
},
_getAdjustedMatrix: function(){
// summary: returns the adjusted ("real") transformation matrix
var matrix = this.matrix, s = this.shape, delta = {dx: s.x, dy: s.y};
return new g.Matrix2D(matrix ? [matrix, delta] : delta); // dojox.gfx.Matrix2D
},
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)
this.rawNode = rawNode;
}
});
sl.Image.nodeType = "Image";
d.declare("dojox.gfx.silverlight.Text", [sl.Shape, gs.Text], {
// summary: an anchored text (Silverlight)
setShape: function(newShape){
// summary: sets a text shape object (Silverlight)
// newShape: Object: a text shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
var r = this.rawNode, s = this.shape;
r.text = s.text;
r.textDecorations = s.decoration === "underline" ? "Underline" : "None";
r["Canvas.Left"] = -10000;
r["Canvas.Top"] = -10000;
if(!this._delay){
this._delay = window.setTimeout(d.hitch(this, "_delayAlignment"), 10);
}
return this; // self
},
_delayAlignment: function(){
// handle alignment
var r = this.rawNode, s = this.shape, w, h;
try{
w = r.actualWidth;
h = r.actualHeight;
}catch(e){
// bail out if the node is hidden
return;
}
var x = s.x, y = s.y - h * 0.75;
switch(s.align){
case "middle":
x -= w / 2;
break;
case "end":
x -= w;
break;
}
this._delta = {dx: x, dy: y};
r["Canvas.Left"] = 0;
r["Canvas.Top"] = 0;
this._applyTransform();
delete this._delay;