if (!dojo._hasResource["dojox.gfx.silverlight"]) { // _hasResource checks added // by build. Do not use // _hasResource directly in // your code. dojo._hasResource["dojox.gfx.silverlight"] = true; 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"); dojox.gfx.silverlight.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] }; dojox.gfx.silverlight.fontweight = { normal : 400, bold : 700 }; dojox.gfx.silverlight.caps = { butt : "Flat", round : "Round", square : "Square" }; dojox.gfx.silverlight.joins = { bevel : "Bevel", round : "Round" }; dojox.gfx.silverlight.fonts = { serif : "Times New Roman", times : "Times New Roman", "sans-serif" : "Arial", helvetica : "Arial", monotone : "Courier New", courier : "Courier New" }; dojox.gfx.silverlight.hexColor = function(/* String|Array|dojo.Color */color) { // summary: converts a color object to a Silverlight hex color string // (#aarrggbb) var c = dojox.gfx.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 }; dojo.extend(dojox.gfx.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 = dojox.gfx.makeParameters( dojox.gfx.defaultLinearGradient, fill); var lgb = p.createFromXaml(""); lgb.mappingMode = "Absolute"; lgb.startPoint = f.x1 + "," + f.y1; lgb.endPoint = f.x2 + "," + f.y2; dojo.forEach(f.colors, function(c) { var t = p.createFromXaml(""); t.offset = c.offset; t.color = dojox.gfx.silverlight .hexColor(c.color); lgb.gradientStops.add(t); }); this._setFillAttr(lgb); break; case "radial" : this.fillStyle = f = dojox.gfx.makeParameters( dojox.gfx.defaultRadialGradient, fill); var rgb = p.createFromXaml(""), w = r.width, h = r.height, l = this.rawNode["Canvas.Left"], t = this.rawNode["Canvas.Top"]; rgb.center = (f.cx - l) / w + "," + (f.cy - t) / h; rgb.radiusX = f.r / w; rgb.radiusY = f.r / h; dojo.forEach(f.colors, function(c) { var t = p.createFromXaml(""); t.offset = c.offset; t.color = dojox.gfx.silverlight .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 = dojox.gfx.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") { stroke = { color : stroke }; } var s = this.strokeStyle = dojox.gfx.makeParameters( dojox.gfx.defaultStroke, stroke); s.color = dojox.gfx.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 = dojox.gfx.silverlight.caps[s.cap]; if (typeof s.join == "number") { r.strokeLineJoin = "Miter"; r.strokeMiterLimit = s.join; } else { r.strokeLineJoin = dojox.gfx.silverlight.joins[s.join]; } var da = s.style.toLowerCase(); if (da in dojox.gfx.silverlight.dasharray) { da = dojox.gfx.silverlight.dasharray[da]; } if (da instanceof Array) { da = dojo.clone(da); /* * for(var i = 0; i < da.length; ++i){ da[i] *= s.width; } */ if (s.cap != "butt") { for (var i = 0; i < da.length; i += 2) { // da[i] -= s.width; --da[i] if (da[i] < 1) { da[i] = 1; } } for (var 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 dojox.gfx.Surface); surface = surface.parent); return surface; }, _applyTransform : function() { var tm = this.matrix, r = this.rawNode; if (tm) { var p = this.rawNode.getHost().content, m = 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; m.matrix = mm; r.renderTransform = m; } 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 } }); dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, { // summary: a group shape (Silverlight), which can be used // to logically group shapes (e.g, to propagate matricies) constructor : function() { dojox.gfx.silverlight.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; } }); dojox.gfx.Group.nodeType = "Canvas"; dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, { // summary: a rectangle shape (Silverlight) setShape : function(newShape) { // summary: sets a rectangle shape object (Silverlight) // newShape: Object: a rectangle shape object this.shape = dojox.gfx.makeParameters(this.shape, newShape); this.bbox = null; var r = this.rawNode, n = this.shape; r["Canvas.Left"] = n.x; r["Canvas.Top"] = n.y; r.width = n.width; r.height = n.height; r.radiusX = r.radiusY = n.r; return this; // self } }); dojox.gfx.Rect.nodeType = "Rectangle"; dojo.declare("dojox.gfx.Ellipse", dojox.gfx.shape.Ellipse, { // summary: an ellipse shape (Silverlight) setShape : function(newShape) { // summary: sets an ellipse shape object (Silverlight) // newShape: Object: an ellipse shape object this.shape = dojox.gfx.makeParameters(this.shape, newShape); this.bbox = null; var r = this.rawNode, n = this.shape; r["Canvas.Left"] = n.cx - n.rx; r["Canvas.Top"] = n.cy - n.ry; r.width = 2 * n.rx; r.height = 2 * n.ry; return this; // self } }); dojox.gfx.Ellipse.nodeType = "Ellipse"; dojo.declare("dojox.gfx.Circle", dojox.gfx.shape.Circle, { // summary: a circle shape (Silverlight) setShape : function(newShape) { // summary: sets a circle shape object (Silverlight) // newShape: Object: a circle shape object this.shape = dojox.gfx.makeParameters(this.shape, newShape); this.bbox = null; var r = this.rawNode, n = this.shape; r["Canvas.Left"] = n.cx - n.r; r["Canvas.Top"] = n.cy - n.r; r.width = r.height = 2 * n.r; return this; // self } }); dojox.gfx.Circle.nodeType = "Ellipse"; dojo.declare("dojox.gfx.Line", dojox.gfx.shape.Line, { // summary: a line shape (Silverlight) setShape : function(newShape) { // summary: sets a line shape object (Silverlight) // newShape: Object: a line shape object this.shape = dojox.gfx.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 } }); dojox.gfx.Line.nodeType = "Line"; dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.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 = dojox.gfx.makeParameters(this.shape, { points : points }); if (closed && this.shape.points.length) { this.shape.points.push(this.shape.points[0]); } } else { this.shape = dojox.gfx.makeParameters(this.shape, points); } this.box = null; var p = this.shape.points, rp = []; for (var i = 0; i < p.length; ++i) { if (typeof p[i] == "number") { rp.push(p[i], p[++i]); } else { rp.push(p[i].x, p[i].y); } } this.rawNode.points = rp.join(","); return this; // self } }); dojox.gfx.Polyline.nodeType = "Polyline"; dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, { // summary: an image (Silverlight) setShape : function(newShape) { // summary: sets an image shape object (Silverlight) // newShape: Object: an image shape object this.shape = dojox.gfx.makeParameters(this.shape, newShape); this.bbox = null; var r = this.rawNode, n = this.shape; r["Canvas.Left"] = n.x; r["Canvas.Top"] = n.y; r.width = n.width; r.height = n.height; r.source = n.src; 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) this.rawNode = rawNode; } }); dojox.gfx.Image.nodeType = "Image"; dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, { // summary: an anchored text (Silverlight) setShape : function(newShape) { // summary: sets a text shape object (Silverlight) // newShape: Object: a text shape object this.shape = dojox.gfx.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; window.setTimeout(dojo.hitch(this, "_delayAlignment"), 0); return this; // self }, _delayAlignment : function() { // handle alignment var r = this.rawNode, s = this.shape, w = r.actualWidth, h = r.actualHeight, x = s.x, y = s.y - h * 0.75; switch (s.align) { case "middle" : x -= w / 2; break; case "end" : x -= w; break; } var a = this.matrix ? dojox.gfx.matrix.multiplyPoint(this.matrix, x, y) : { x : x, y : y }; r["Canvas.Left"] = a.x; r["Canvas.Top"] = a.y; }, 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; }, _applyTransform : function() { var tm = this.matrix, r = this.rawNode; if (tm) { // the next line is pure magic :-( tm = dojox.gfx.matrix.normalize([1 / 100, tm, 100]); var p = this.rawNode.getHost().content, m = 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; m.matrix = mm; r.renderTransform = m; } else { r.renderTransform = null; } return this; }, getTextWidth : function() { // summary: get the text width in pixels return this.rawNode.actualWidth; } }); dojox.gfx.Text.nodeType = "TextBlock"; dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, { // summary: a path shape (Silverlight) _updateWithSegment : function(segment) { // summary: updates the bounding box of path with new segment // segment: Object: a segment dojox.gfx.Path.superclass._updateWithSegment.apply(this, 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) dojox.gfx.Path.superclass.setShape.apply(this, arguments); var p = this.shape.path; this.rawNode.data = p ? p : null; return this; // self } }); dojox.gfx.Path.nodeType = "Path"; dojo.declare("dojox.gfx.TextPath", dojox.gfx.path.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() { } }); dojox.gfx.TextPath.nodeType = "text"; dojo.declare("dojox.gfx.Surface", dojox.gfx.shape.Surface, { // summary: a surface object to be used for drawings // (Silverlight) constructor : function() { dojox.gfx.silverlight.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 = dojox.gfx.normalizedLength(width); // in pixels this.height = dojox.gfx.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 } }); dojox.gfx.silverlight.surfaces = {}; dojox.gfx.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" var s = new dojox.gfx.Surface(); parentNode = dojo.byId(parentNode); // create an empty canvas var t = parentNode.ownerDocument.createElement("script"); t.type = "text/xaml"; t.id = dojox.gfx._base._getUniqueId(); t.text = ""; document.body.appendChild(t); // create a plugin var pluginName = dojox.gfx._base._getUniqueId(); Silverlight.createObject("#" + t.id, // none parentNode, pluginName, { // Plugin properties. width : String(width), // Width of rectangular region of // plugin in pixels. height : String(height), // Height of rectangular region // of plugin in pixels. inplaceInstallPrompt : "false", // Determines whether to // display in-place install // prompt if invalid version // detected. // background: "white", // Background color of plugin. // isWindowless: "false", // Determines whether to display // plugin in Windowless mode. background : "transparent", // Background color of plugin. isWindowless : "true", // Determines whether to display // plugin in Windowless mode. framerate : "24", // MaxFrameRate property value. version : "1.0" // Silverlight version. }, {}, null, null); s.rawNode = dojo.byId(pluginName).content.root; // register the plugin with its parent node dojox.gfx.silverlight.surfaces[s.rawNode.name] = parentNode; s.width = dojox.gfx.normalizedLength(width); // in pixels s.height = dojox.gfx.normalizedLength(height); // in pixels return s; // dojox.gfx.Surface }; // Extenders dojox.gfx.silverlight.Font = { _setFont : function() { // summary: sets a font object (Silverlight) var f = this.fontStyle, r = this.rawNode, fw = dojox.gfx.silverlight.fontweight, fo = dojox.gfx.silverlight.fonts, t = f.family .toLowerCase(); r.fontStyle = f.style == "italic" ? "Italic" : "Normal"; r.fontWeight = f.weight in fw ? fw[f.weight] : f.weight; r.fontSize = dojox.gfx.normalizedLength(f.size); r.fontFamily = t in fo ? fo[t] : f.family; } }; dojox.gfx.silverlight.Container = { _init : function() { dojox.gfx.shape.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()) { // dojox.gfx.Group.superclass.add.apply(this, arguments); // this.inherited(arguments); dojox.gfx.shape.Container.add.apply(this, arguments); this.rawNode.children.add(shape.rawNode); } 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()) { var parent = shape.rawNode.getParent(); if (parent) { parent.children.remove(shape.rawNode); } // dojox.gfx.Group.superclass.remove.apply(this, arguments); // this.inherited(arguments); dojox.gfx.shape.Container.remove.apply(this, arguments); } return this; // self }, clear : function() { // summary: removes all shapes from a group/surface this.rawNode.children.clear(); // return this.inherited(arguments); // self return dojox.gfx.shape.Container.clear.apply(this, arguments); }, _moveChildToFront : dojox.gfx.shape.Container._moveChildToFront, _moveChildToBack : dojox.gfx.shape.Container._moveChildToBack }; dojo.mixin(dojox.gfx.shape.Creator, { 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 if (!this.rawNode) { return null; } var shape = new shapeType(); var node = this.rawNode.getHost().content .createFromXaml("<" + shapeType.nodeType + "/>"); shape.setRawNode(node); shape.setShape(rawShape); this.add(shape); return shape; // dojox.gfx.Shape } }); dojo.extend(dojox.gfx.Text, dojox.gfx.silverlight.Font); // dojo.extend(dojox.gfx.TextPath, dojox.gfx.silverlight.Font); dojo.extend(dojox.gfx.Group, dojox.gfx.silverlight.Container); dojo.extend(dojox.gfx.Group, dojox.gfx.shape.Creator); dojo.extend(dojox.gfx.Surface, dojox.gfx.silverlight.Container); dojo.extend(dojox.gfx.Surface, dojox.gfx.shape.Creator); (function() { var surfaces = dojox.gfx.silverlight.surfaces; var mouseFix = function(s, a) { var ev = { target : s, currentTarget : s, preventDefault : function() { }, stopPropagation : function() { } }; if (a) { ev.ctrlKey = a.ctrl; ev.shiftKey = a.shift; var p = a.getPosition(null); ev.x = ev.offsetX = ev.layerX = p.x; ev.y = ev.offsetY = ev.layerY = p.y; // calculate clientX and clientY var parent = surfaces[s.getHost().content.root.name]; var t = dojo._abs(parent); ev.clientX = t.x + p.x; ev.clientY = t.y + p.y; } return ev; }; var keyFix = function(s, a) { var ev = { keyCode : a.platformKeyCode, ctrlKey : a.ctrl, shiftKey : a.shift }; return ev; }; var eventNames = { onclick : { name : "MouseLeftButtonUp", fix : mouseFix }, onmouseenter : { name : "MouseEnter", fix : mouseFix }, onmouseleave : { name : "MouseLeave", fix : mouseFix }, onmousedown : { name : "MouseLeftButtonDown", fix : mouseFix }, onmouseup : { name : "MouseLeftButtonUp", fix : mouseFix }, onmousemove : { name : "MouseMove", fix : mouseFix }, onkeydown : { name : "KeyDown", fix : keyFix }, onkeyup : { name : "KeyUp", fix : keyFix } }; var eventsProcessing = { connect : function(name, object, method) { var token, n = name in eventNames ? eventNames[name] : { name : name, fix : function() { return {}; } }; if (arguments.length > 2) { token = this.getEventSource().addEventListener(n.name, function(s, a) { dojo.hitch(object, method)(n.fix(s, a)); }); } else { token = this.getEventSource().addEventListener(n.name, function(s, a) { object(n.fix(s, a)); }); } return { name : n.name, token : token }; }, disconnect : function(token) { this.getEventSource().removeEventListener(token.name, token.token); } }; dojo.extend(dojox.gfx.Shape, eventsProcessing); dojo.extend(dojox.gfx.Surface, eventsProcessing); dojox.gfx.equalSources = function(a, b) { return a && b && a.equals(b); } })(); }