//>>built define("dojox/gfx/silverlight", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/Color", "dojo/_base/array", "dojo/dom-geometry", "dojo/dom", "dojo/_base/sniff", "./_base", "./shape", "./path"], function(kernel,lang,declare,color,arr,domGeom,dom,has,g,gs,pathLib){ /*===== dojox.gfx.silverlight = { // module: // dojox/gfx/silverlight // summary: // This the graphics rendering bridge for the Microsoft Silverlight plugin. // Silverlight is a faster implementation on IE6-8 than the default 2d graphics, VML }; g = dojox.gfx; pathLib.Path = dojox.gfx.path.Path; pathLib.TextPath = dojox.gfx.path.TextPath; sl.Shape = dojox.gfx.canvas.Shape; gs.Shape = dojox.gfx.shape.Shape; gs.Rect = dojox.gfx.shape.Rect; gs.Ellipse = dojox.gfx.shape.Ellipse; gs.Circle = dojox.gfx.shape.Circle; gs.Line = dojox.gfx.shape.Line; gs.PolyLine = dojox.gfx.shape.PolyLine; gs.Image = dojox.gfx.shape.Image; gs.Text = dojox.gfx.shape.Text; gs.Surface = dojox.gfx.shape.Surface; =====*/ var sl = g.silverlight = {}; kernel.experimental("dojox.gfx.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 } 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; arr.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; arr.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" || lang.isArray(stroke) || stroke instanceof 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 = lang.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; this.rawNode.tag = this.getUID(); }, // 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 } }); 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; this.rawNode.tag = this.getUID(); } }); sl.Group.nodeType = "Canvas"; 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"; 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"; 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"; 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"; 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"; 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; this.rawNode.tag = this.getUID(); } }); sl.Image.nodeType = "Image"; 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(lang.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; }, _getAdjustedMatrix: function(){ // summary: returns the adjusted ("real") transformation matrix var matrix = this.matrix, delta = this._delta, x; if(matrix){ x = delta ? [matrix, delta] : matrix; }else{ x = delta ? delta : {}; } return new g.Matrix2D(x); }, setStroke: function(){ // summary: ignore setting a stroke style return this; // self }, _setFillAttr: function(f){ this.rawNode.foreground = f; }, 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; this.rawNode.tag = this.getUID(); }, getTextWidth: function(){ // summary: get the text width in pixels return this.rawNode.actualWidth; } }); sl.Text.nodeType = "TextBlock"; declare("dojox.gfx.silverlight.Path", [sl.Shape, pathLib.Path], { // summary: a path shape (Silverlight) _updateWithSegment: function(segment){ // summary: updates the bounding box of path with new segment // segment: Object: a segment this.inherited(arguments); var p = this.shape.path; if(typeof(p) == "string"){ this.rawNode.data = p ? p : null; } }, setShape: function(newShape){ // summary: forms a path using a shape (Silverlight) // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath) this.inherited(arguments); var p = this.shape.path; this.rawNode.data = p ? p : null; return this; // self } }); sl.Path.nodeType = "Path"; declare("dojox.gfx.silverlight.TextPath", [sl.Shape, pathLib.TextPath], { // summary: a textpath shape (Silverlight) _updateWithSegment: function(segment){ // summary: updates the bounding box of path with new segment // segment: Object: a segment }, setShape: function(newShape){ // summary: forms a path using a shape (Silverlight) // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath) }, _setText: function(){ } }); sl.TextPath.nodeType = "text"; var surfaces = {}, nullFunc = new Function; declare("dojox.gfx.silverlight.Surface", gs.Surface, { // summary: a surface object to be used for drawings (Silverlight) constructor: function(){ gs.Container._init.call(this); }, destroy: function(){ window[this._onLoadName] = nullFunc; delete surfaces[this._nodeName]; this.inherited(arguments); }, 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 var p = this.rawNode && this.rawNode.getHost(); if(p){ p.width = width; p.height = height; } return this; // self }, getDimensions: function(){ // summary: returns an object with properties "width" and "height" var p = this.rawNode && this.rawNode.getHost(); var t = p ? {width: p.content.actualWidth, height: p.content.actualHeight} : null; if(t.width <= 0){ t.width = this.width; } if(t.height <= 0){ t.height = this.height; } return t; // Object } }); sl.createSurface = function(parentNode, width, height){ // summary: creates a surface (Silverlight) // parentNode: Node: a parent node // width: String: width of surface, e.g., "100px" // height: String: height of surface, e.g., "100px" if(!width && !height){ var pos = domGeom.position(parentNode); width = width || pos.w; height = height || pos.h; } if(typeof width == "number"){ width = width + "px"; } if(typeof height == "number"){ height = height + "px"; } var s = new sl.Surface(); parentNode = dom.byId(parentNode); s._parent = parentNode; s._nodeName = g._base._getUniqueId(); // create an empty canvas var t = parentNode.ownerDocument.createElement("script"); t.type = "text/xaml"; t.id = g._base._getUniqueId(); t.text = ""; parentNode.parentNode.insertBefore(t, parentNode); s._nodes.push(t); // build the object var obj, pluginName = g._base._getUniqueId(), onLoadName = "__" + g._base._getUniqueId() + "_onLoad"; s._onLoadName = onLoadName; window[onLoadName] = function(sender){ if(!s.rawNode){ s.rawNode = dom.byId(pluginName).content.root; // register the plugin with its parent node surfaces[s._nodeName] = parentNode; s.onLoad(s); } }; if(has("safari")){ obj = "