silverlight.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.gfx.silverlight"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.gfx.silverlight"] = true;
  8. dojo.provide("dojox.gfx.silverlight");
  9. dojo.require("dojox.gfx._base");
  10. dojo.require("dojox.gfx.shape");
  11. dojo.require("dojox.gfx.path");
  12. dojo.experimental("dojox.gfx.silverlight");
  13. (function(){
  14. var d = dojo, g = dojox.gfx, gs = g.shape, sl = g.silverlight;
  15. var dasharray = {
  16. solid: "none",
  17. shortdash: [4, 1],
  18. shortdot: [1, 1],
  19. shortdashdot: [4, 1, 1, 1],
  20. shortdashdotdot: [4, 1, 1, 1, 1, 1],
  21. dot: [1, 3],
  22. dash: [4, 3],
  23. longdash: [8, 3],
  24. dashdot: [4, 3, 1, 3],
  25. longdashdot: [8, 3, 1, 3],
  26. longdashdotdot: [8, 3, 1, 3, 1, 3]
  27. },
  28. fontweight = {
  29. normal: 400,
  30. bold: 700
  31. },
  32. caps = {butt: "Flat", round: "Round", square: "Square"},
  33. joins = {bevel: "Bevel", round: "Round"},
  34. fonts = {
  35. serif: "Times New Roman",
  36. times: "Times New Roman",
  37. "sans-serif": "Arial",
  38. helvetica: "Arial",
  39. monotone: "Courier New",
  40. courier: "Courier New"
  41. };
  42. function hexColor(/*String|Array|dojo.Color*/ color){
  43. // summary: converts a color object to a Silverlight hex color string (#aarrggbb)
  44. var c = g.normalizeColor(color),
  45. t = c.toHex(), a = Math.round(c.a * 255);
  46. a = (a < 0 ? 0 : a > 255 ? 255 : a).toString(16);
  47. return "#" + (a.length < 2 ? "0" + a : a) + t.slice(1); // String
  48. }
  49. d.declare("dojox.gfx.silverlight.Shape", gs.Shape, {
  50. // summary: Silverlight-specific implementation of dojox.gfx.Shape methods
  51. setFill: function(fill){
  52. // summary: sets a fill object (Silverlight)
  53. // fill: Object: a fill object
  54. // (see dojox.gfx.defaultLinearGradient,
  55. // dojox.gfx.defaultRadialGradient,
  56. // dojox.gfx.defaultPattern,
  57. // or dojo.Color)
  58. var p = this.rawNode.getHost().content, r = this.rawNode, f;
  59. if(!fill){
  60. // don't fill
  61. this.fillStyle = null;
  62. this._setFillAttr(null);
  63. return this; // self
  64. }
  65. if(typeof(fill) == "object" && "type" in fill){
  66. // gradient
  67. switch(fill.type){
  68. case "linear":
  69. this.fillStyle = f = g.makeParameters(g.defaultLinearGradient, fill);
  70. var lgb = p.createFromXaml("<LinearGradientBrush/>");
  71. lgb.mappingMode = "Absolute";
  72. lgb.startPoint = f.x1 + "," + f.y1;
  73. lgb.endPoint = f.x2 + "," + f.y2;
  74. d.forEach(f.colors, function(c){
  75. var t = p.createFromXaml("<GradientStop/>");
  76. t.offset = c.offset;
  77. t.color = hexColor(c.color);
  78. lgb.gradientStops.add(t);
  79. });
  80. this._setFillAttr(lgb);
  81. break;
  82. case "radial":
  83. this.fillStyle = f = g.makeParameters(g.defaultRadialGradient, fill);
  84. var rgb = p.createFromXaml("<RadialGradientBrush/>"),
  85. c = g.matrix.multiplyPoint(g.matrix.invert(this._getAdjustedMatrix()), f.cx, f.cy),
  86. pt = c.x + "," + c.y;
  87. rgb.mappingMode = "Absolute";
  88. rgb.gradientOrigin = pt;
  89. rgb.center = pt;
  90. rgb.radiusX = rgb.radiusY = f.r;
  91. d.forEach(f.colors, function(c){
  92. var t = p.createFromXaml("<GradientStop/>");
  93. t.offset = c.offset;
  94. t.color = hexColor(c.color);
  95. rgb.gradientStops.add(t);
  96. });
  97. this._setFillAttr(rgb);
  98. break;
  99. case "pattern":
  100. // don't fill: Silverlight doesn't define TileBrush for some reason
  101. this.fillStyle = null;
  102. this._setFillAttr(null);
  103. break;
  104. }
  105. return this; // self
  106. }
  107. // color object
  108. this.fillStyle = f = g.normalizeColor(fill);
  109. var scb = p.createFromXaml("<SolidColorBrush/>");
  110. scb.color = f.toHex();
  111. scb.opacity = f.a;
  112. this._setFillAttr(scb);
  113. return this; // self
  114. },
  115. _setFillAttr: function(f){
  116. this.rawNode.fill = f;
  117. },
  118. setStroke: function(stroke){
  119. // summary: sets a stroke object (Silverlight)
  120. // stroke: Object: a stroke object
  121. // (see dojox.gfx.defaultStroke)
  122. var p = this.rawNode.getHost().content, r = this.rawNode;
  123. if(!stroke){
  124. // don't stroke
  125. this.strokeStyle = null;
  126. r.stroke = null;
  127. return this;
  128. }
  129. // normalize the stroke
  130. if(typeof stroke == "string" || d.isArray(stroke) || stroke instanceof d.Color){
  131. stroke = {color: stroke};
  132. }
  133. var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
  134. s.color = g.normalizeColor(s.color);
  135. // generate attributes
  136. if(s){
  137. var scb = p.createFromXaml("<SolidColorBrush/>");
  138. scb.color = s.color.toHex();
  139. scb.opacity = s.color.a;
  140. r.stroke = scb;
  141. r.strokeThickness = s.width;
  142. r.strokeStartLineCap = r.strokeEndLineCap = r.strokeDashCap =
  143. caps[s.cap];
  144. if(typeof s.join == "number"){
  145. r.strokeLineJoin = "Miter";
  146. r.strokeMiterLimit = s.join;
  147. }else{
  148. r.strokeLineJoin = joins[s.join];
  149. }
  150. var da = s.style.toLowerCase();
  151. if(da in dasharray){ da = dasharray[da]; }
  152. if(da instanceof Array){
  153. da = d.clone(da);
  154. var i;
  155. /*
  156. for(var i = 0; i < da.length; ++i){
  157. da[i] *= s.width;
  158. }
  159. */
  160. if(s.cap != "butt"){
  161. for(i = 0; i < da.length; i += 2){
  162. //da[i] -= s.width;
  163. --da[i]
  164. if(da[i] < 1){ da[i] = 1; }
  165. }
  166. for(i = 1; i < da.length; i += 2){
  167. //da[i] += s.width;
  168. ++da[i];
  169. }
  170. }
  171. r.strokeDashArray = da.join(",");
  172. }else{
  173. r.strokeDashArray = null;
  174. }
  175. }
  176. return this; // self
  177. },
  178. _getParentSurface: function(){
  179. var surface = this.parent;
  180. for(; surface && !(surface instanceof g.Surface); surface = surface.parent);
  181. return surface;
  182. },
  183. _applyTransform: function() {
  184. var tm = this._getAdjustedMatrix(), r = this.rawNode;
  185. if(tm){
  186. var p = this.rawNode.getHost().content,
  187. mt = p.createFromXaml("<MatrixTransform/>"),
  188. mm = p.createFromXaml("<Matrix/>");
  189. mm.m11 = tm.xx;
  190. mm.m21 = tm.xy;
  191. mm.m12 = tm.yx;
  192. mm.m22 = tm.yy;
  193. mm.offsetX = tm.dx;
  194. mm.offsetY = tm.dy;
  195. mt.matrix = mm;
  196. r.renderTransform = mt;
  197. }else{
  198. r.renderTransform = null;
  199. }
  200. return this;
  201. },
  202. setRawNode: function(rawNode){
  203. // summary:
  204. // assigns and clears the underlying node that will represent this
  205. // shape. Once set, transforms, gradients, etc, can be applied.
  206. // (no fill & stroke by default)
  207. rawNode.fill = null;
  208. rawNode.stroke = null;
  209. this.rawNode = rawNode;
  210. },
  211. // move family
  212. _moveToFront: function(){
  213. // summary: moves a shape to front of its parent's list of shapes (Silverlight)
  214. var c = this.parent.rawNode.children, r = this.rawNode;
  215. c.remove(r);
  216. c.add(r);
  217. return this; // self
  218. },
  219. _moveToBack: function(){
  220. // summary: moves a shape to back of its parent's list of shapes (Silverlight)
  221. var c = this.parent.rawNode.children, r = this.rawNode;
  222. c.remove(r);
  223. c.insert(0, r);
  224. return this; // self
  225. },
  226. _getAdjustedMatrix: function(){
  227. // summary: returns the adjusted ("real") transformation matrix
  228. return this.matrix; // dojox.gfx.Matrix2D
  229. }
  230. });
  231. d.declare("dojox.gfx.silverlight.Group", sl.Shape, {
  232. // summary: a group shape (Silverlight), which can be used
  233. // to logically group shapes (e.g, to propagate matricies)
  234. constructor: function(){
  235. gs.Container._init.call(this);
  236. },
  237. setRawNode: function(rawNode){
  238. // summary: sets a raw Silverlight node to be used by this shape
  239. // rawNode: Node: an Silverlight node
  240. this.rawNode = rawNode;
  241. }
  242. });
  243. sl.Group.nodeType = "Canvas";
  244. d.declare("dojox.gfx.silverlight.Rect", [sl.Shape, gs.Rect], {
  245. // summary: a rectangle shape (Silverlight)
  246. setShape: function(newShape){
  247. // summary: sets a rectangle shape object (Silverlight)
  248. // newShape: Object: a rectangle shape object
  249. this.shape = g.makeParameters(this.shape, newShape);
  250. this.bbox = null;
  251. var r = this.rawNode, n = this.shape;
  252. r.width = n.width;
  253. r.height = n.height;
  254. r.radiusX = r.radiusY = n.r;
  255. return this._applyTransform(); // self
  256. },
  257. _getAdjustedMatrix: function(){
  258. // summary: returns the adjusted ("real") transformation matrix
  259. var matrix = this.matrix, s = this.shape, delta = {dx: s.x, dy: s.y};
  260. return new g.Matrix2D(matrix ? [matrix, delta] : delta); // dojox.gfx.Matrix2D
  261. }
  262. });
  263. sl.Rect.nodeType = "Rectangle";
  264. d.declare("dojox.gfx.silverlight.Ellipse", [sl.Shape, gs.Ellipse], {
  265. // summary: an ellipse shape (Silverlight)
  266. setShape: function(newShape){
  267. // summary: sets an ellipse shape object (Silverlight)
  268. // newShape: Object: an ellipse shape object
  269. this.shape = g.makeParameters(this.shape, newShape);
  270. this.bbox = null;
  271. var r = this.rawNode, n = this.shape;
  272. r.width = 2 * n.rx;
  273. r.height = 2 * n.ry;
  274. return this._applyTransform(); // self
  275. },
  276. _getAdjustedMatrix: function(){
  277. // summary: returns the adjusted ("real") transformation matrix
  278. var matrix = this.matrix, s = this.shape, delta = {dx: s.cx - s.rx, dy: s.cy - s.ry};
  279. return new g.Matrix2D(matrix ? [matrix, delta] : delta); // dojox.gfx.Matrix2D
  280. }
  281. });
  282. sl.Ellipse.nodeType = "Ellipse";
  283. d.declare("dojox.gfx.silverlight.Circle", [sl.Shape, gs.Circle], {
  284. // summary: a circle shape (Silverlight)
  285. setShape: function(newShape){
  286. // summary: sets a circle shape object (Silverlight)
  287. // newShape: Object: a circle shape object
  288. this.shape = g.makeParameters(this.shape, newShape);
  289. this.bbox = null;
  290. var r = this.rawNode, n = this.shape;
  291. r.width = r.height = 2 * n.r;
  292. return this._applyTransform(); // self
  293. },
  294. _getAdjustedMatrix: function(){
  295. // summary: returns the adjusted ("real") transformation matrix
  296. var matrix = this.matrix, s = this.shape, delta = {dx: s.cx - s.r, dy: s.cy - s.r};
  297. return new g.Matrix2D(matrix ? [matrix, delta] : delta); // dojox.gfx.Matrix2D
  298. }
  299. });
  300. sl.Circle.nodeType = "Ellipse";
  301. d.declare("dojox.gfx.silverlight.Line", [sl.Shape, gs.Line], {
  302. // summary: a line shape (Silverlight)
  303. setShape: function(newShape){
  304. // summary: sets a line shape object (Silverlight)
  305. // newShape: Object: a line shape object
  306. this.shape = g.makeParameters(this.shape, newShape);
  307. this.bbox = null;
  308. var r = this.rawNode, n = this.shape;
  309. r.x1 = n.x1; r.y1 = n.y1; r.x2 = n.x2; r.y2 = n.y2;
  310. return this; // self
  311. }
  312. });
  313. sl.Line.nodeType = "Line";
  314. d.declare("dojox.gfx.silverlight.Polyline", [sl.Shape, gs.Polyline], {
  315. // summary: a polyline/polygon shape (Silverlight)
  316. setShape: function(points, closed){
  317. // summary: sets a polyline/polygon shape object (Silverlight)
  318. // points: Object: a polyline/polygon shape object
  319. if(points && points instanceof Array){
  320. // branch
  321. // points: Array: an array of points
  322. this.shape = g.makeParameters(this.shape, {points: points});
  323. if(closed && this.shape.points.length){
  324. this.shape.points.push(this.shape.points[0]);
  325. }
  326. }else{
  327. this.shape = g.makeParameters(this.shape, points);
  328. }
  329. this.bbox = null;
  330. this._normalizePoints();
  331. var p = this.shape.points, rp = [];
  332. for(var i = 0; i < p.length; ++i){
  333. rp.push(p[i].x, p[i].y);
  334. }
  335. this.rawNode.points = rp.join(",");
  336. return this; // self
  337. }
  338. });
  339. sl.Polyline.nodeType = "Polyline";
  340. d.declare("dojox.gfx.silverlight.Image", [sl.Shape, gs.Image], {
  341. // summary: an image (Silverlight)
  342. setShape: function(newShape){
  343. // summary: sets an image shape object (Silverlight)
  344. // newShape: Object: an image shape object
  345. this.shape = g.makeParameters(this.shape, newShape);
  346. this.bbox = null;
  347. var r = this.rawNode, n = this.shape;
  348. r.width = n.width;
  349. r.height = n.height;
  350. r.source = n.src;
  351. return this._applyTransform(); // self
  352. },
  353. _getAdjustedMatrix: function(){
  354. // summary: returns the adjusted ("real") transformation matrix
  355. var matrix = this.matrix, s = this.shape, delta = {dx: s.x, dy: s.y};
  356. return new g.Matrix2D(matrix ? [matrix, delta] : delta); // dojox.gfx.Matrix2D
  357. },
  358. setRawNode: function(rawNode){
  359. // summary:
  360. // assigns and clears the underlying node that will represent this
  361. // shape. Once set, transforms, gradients, etc, can be applied.
  362. // (no fill & stroke by default)
  363. this.rawNode = rawNode;
  364. }
  365. });
  366. sl.Image.nodeType = "Image";
  367. d.declare("dojox.gfx.silverlight.Text", [sl.Shape, gs.Text], {
  368. // summary: an anchored text (Silverlight)
  369. setShape: function(newShape){
  370. // summary: sets a text shape object (Silverlight)
  371. // newShape: Object: a text shape object
  372. this.shape = g.makeParameters(this.shape, newShape);
  373. this.bbox = null;
  374. var r = this.rawNode, s = this.shape;
  375. r.text = s.text;
  376. r.textDecorations = s.decoration === "underline" ? "Underline" : "None";
  377. r["Canvas.Left"] = -10000;
  378. r["Canvas.Top"] = -10000;
  379. if(!this._delay){
  380. this._delay = window.setTimeout(d.hitch(this, "_delayAlignment"), 10);
  381. }
  382. return this; // self
  383. },
  384. _delayAlignment: function(){
  385. // handle alignment
  386. var r = this.rawNode, s = this.shape, w, h;
  387. try{
  388. w = r.actualWidth;
  389. h = r.actualHeight;
  390. }catch(e){
  391. // bail out if the node is hidden
  392. return;
  393. }
  394. var x = s.x, y = s.y - h * 0.75;
  395. switch(s.align){
  396. case "middle":
  397. x -= w / 2;
  398. break;
  399. case "end":
  400. x -= w;
  401. break;
  402. }
  403. this._delta = {dx: x, dy: y};
  404. r["Canvas.Left"] = 0;
  405. r["Canvas.Top"] = 0;
  406. this._applyTransform();
  407. delete this._delay;
  408. },
  409. _getAdjustedMatrix: function(){
  410. // summary: returns the adjusted ("real") transformation matrix
  411. var matrix = this.matrix, delta = this._delta, x;
  412. if(matrix){
  413. x = delta ? [matrix, delta] : matrix;
  414. }else{
  415. x = delta ? delta : {};
  416. }
  417. return new g.Matrix2D(x);
  418. },
  419. setStroke: function(){
  420. // summary: ignore setting a stroke style
  421. return this; // self
  422. },
  423. _setFillAttr: function(f){
  424. this.rawNode.foreground = f;
  425. },
  426. setRawNode: function(rawNode){
  427. // summary:
  428. // assigns and clears the underlying node that will represent this
  429. // shape. Once set, transforms, gradients, etc, can be applied.
  430. // (no fill & stroke by default)
  431. this.rawNode = rawNode;
  432. },
  433. getTextWidth: function(){
  434. // summary: get the text width in pixels
  435. return this.rawNode.actualWidth;
  436. }
  437. });
  438. sl.Text.nodeType = "TextBlock";
  439. d.declare("dojox.gfx.silverlight.Path", [sl.Shape, g.path.Path], {
  440. // summary: a path shape (Silverlight)
  441. _updateWithSegment: function(segment){
  442. // summary: updates the bounding box of path with new segment
  443. // segment: Object: a segment
  444. this.inherited(arguments);
  445. var p = this.shape.path;
  446. if(typeof(p) == "string"){
  447. this.rawNode.data = p ? p : null;
  448. }
  449. },
  450. setShape: function(newShape){
  451. // summary: forms a path using a shape (Silverlight)
  452. // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath)
  453. this.inherited(arguments);
  454. var p = this.shape.path;
  455. this.rawNode.data = p ? p : null;
  456. return this; // self
  457. }
  458. });
  459. sl.Path.nodeType = "Path";
  460. d.declare("dojox.gfx.silverlight.TextPath", [sl.Shape, g.path.TextPath], {
  461. // summary: a textpath shape (Silverlight)
  462. _updateWithSegment: function(segment){
  463. // summary: updates the bounding box of path with new segment
  464. // segment: Object: a segment
  465. },
  466. setShape: function(newShape){
  467. // summary: forms a path using a shape (Silverlight)
  468. // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath)
  469. },
  470. _setText: function(){
  471. }
  472. });
  473. sl.TextPath.nodeType = "text";
  474. var surfaces = {}, nullFunc = new Function;
  475. d.declare("dojox.gfx.silverlight.Surface", gs.Surface, {
  476. // summary: a surface object to be used for drawings (Silverlight)
  477. constructor: function(){
  478. gs.Container._init.call(this);
  479. },
  480. destroy: function(){
  481. window[this._onLoadName] = nullFunc;
  482. delete surfaces[this._nodeName];
  483. this.inherited(arguments);
  484. },
  485. setDimensions: function(width, height){
  486. // summary: sets the width and height of the rawNode
  487. // width: String: width of surface, e.g., "100px"
  488. // height: String: height of surface, e.g., "100px"
  489. this.width = g.normalizedLength(width); // in pixels
  490. this.height = g.normalizedLength(height); // in pixels
  491. var p = this.rawNode && this.rawNode.getHost();
  492. if(p){
  493. p.width = width;
  494. p.height = height;
  495. }
  496. return this; // self
  497. },
  498. getDimensions: function(){
  499. // summary: returns an object with properties "width" and "height"
  500. var p = this.rawNode && this.rawNode.getHost();
  501. var t = p ? {width: p.content.actualWidth, height: p.content.actualHeight} : null;
  502. if(t.width <= 0){ t.width = this.width; }
  503. if(t.height <= 0){ t.height = this.height; }
  504. return t; // Object
  505. }
  506. });
  507. sl.createSurface = function(parentNode, width, height){
  508. // summary: creates a surface (Silverlight)
  509. // parentNode: Node: a parent node
  510. // width: String: width of surface, e.g., "100px"
  511. // height: String: height of surface, e.g., "100px"
  512. if(!width && !height){
  513. var pos = d.position(parentNode);
  514. width = width || pos.w;
  515. height = height || pos.h;
  516. }
  517. if(typeof width == "number"){
  518. width = width + "px";
  519. }
  520. if(typeof height == "number"){
  521. height = height + "px";
  522. }
  523. var s = new sl.Surface();
  524. parentNode = d.byId(parentNode);
  525. s._parent = parentNode;
  526. s._nodeName = g._base._getUniqueId();
  527. // create an empty canvas
  528. var t = parentNode.ownerDocument.createElement("script");
  529. t.type = "text/xaml";
  530. t.id = g._base._getUniqueId();
  531. t.text = "<?xml version='1.0'?><Canvas xmlns='http://schemas.microsoft.com/client/2007' Name='" +
  532. s._nodeName + "'/>";
  533. parentNode.parentNode.insertBefore(t, parentNode);
  534. s._nodes.push(t);
  535. // build the object
  536. var obj, pluginName = g._base._getUniqueId(),
  537. onLoadName = "__" + g._base._getUniqueId() + "_onLoad";
  538. s._onLoadName = onLoadName;
  539. window[onLoadName] = function(sender){
  540. if(!s.rawNode){
  541. s.rawNode = d.byId(pluginName).content.root;
  542. // register the plugin with its parent node
  543. surfaces[s._nodeName] = parentNode;
  544. s.onLoad(s);
  545. }
  546. };
  547. if(d.isSafari){
  548. obj = "<embed type='application/x-silverlight' id='" +
  549. pluginName + "' width='" + width + "' height='" + height +
  550. " background='transparent'" +
  551. " source='#" + t.id + "'" +
  552. " windowless='true'" +
  553. " maxFramerate='60'" +
  554. " onLoad='" + onLoadName + "'" +
  555. " onError='__dojoSilverlightError'" +
  556. " /><iframe style='visibility:hidden;height:0;width:0'/>";
  557. }else{
  558. obj = "<object type='application/x-silverlight' data='data:application/x-silverlight,' id='" +
  559. pluginName + "' width='" + width + "' height='" + height + "'>" +
  560. "<param name='background' value='transparent' />" +
  561. "<param name='source' value='#" + t.id + "' />" +
  562. "<param name='windowless' value='true' />" +
  563. "<param name='maxFramerate' value='60' />" +
  564. "<param name='onLoad' value='" + onLoadName + "' />" +
  565. "<param name='onError' value='__dojoSilverlightError' />" +
  566. "</object>";
  567. }
  568. parentNode.innerHTML = obj;
  569. var pluginNode = d.byId(pluginName);
  570. if(pluginNode.content && pluginNode.content.root){
  571. // the plugin was created synchronously
  572. s.rawNode = pluginNode.content.root;
  573. // register the plugin with its parent node
  574. surfaces[s._nodeName] = parentNode;
  575. }else{
  576. // the plugin is being created asynchronously
  577. s.rawNode = null;
  578. s.isLoaded = false;
  579. }
  580. s._nodes.push(pluginNode);
  581. s.width = g.normalizedLength(width); // in pixels
  582. s.height = g.normalizedLength(height); // in pixels
  583. return s; // dojox.gfx.Surface
  584. };
  585. // the function below is meant to be global, it is called from
  586. // the Silverlight's error handler
  587. __dojoSilverlightError = function(sender, err){
  588. var t = "Silverlight Error:\n" +
  589. "Code: " + err.ErrorCode + "\n" +
  590. "Type: " + err.ErrorType + "\n" +
  591. "Message: " + err.ErrorMessage + "\n";
  592. switch(err.ErrorType){
  593. case "ParserError":
  594. t += "XamlFile: " + err.xamlFile + "\n" +
  595. "Line: " + err.lineNumber + "\n" +
  596. "Position: " + err.charPosition + "\n";
  597. break;
  598. case "RuntimeError":
  599. t += "MethodName: " + err.methodName + "\n";
  600. if(err.lineNumber != 0){
  601. t +=
  602. "Line: " + err.lineNumber + "\n" +
  603. "Position: " + err.charPosition + "\n";
  604. }
  605. break;
  606. }
  607. };
  608. // Extenders
  609. var Font = {
  610. _setFont: function(){
  611. // summary: sets a font object (Silverlight)
  612. var f = this.fontStyle, r = this.rawNode, t = f.family.toLowerCase();
  613. r.fontStyle = f.style == "italic" ? "Italic" : "Normal";
  614. r.fontWeight = f.weight in fontweight ? fontweight[f.weight] : f.weight;
  615. r.fontSize = g.normalizedLength(f.size);
  616. r.fontFamily = t in fonts ? fonts[t] : f.family;
  617. // update the transform
  618. if(!this._delay){
  619. this._delay = window.setTimeout(d.hitch(this, "_delayAlignment"), 10);
  620. }
  621. }
  622. };
  623. var C = gs.Container, Container = {
  624. add: function(shape){
  625. // summary: adds a shape to a group/surface
  626. // shape: dojox.gfx.Shape: a Silverlight shape object
  627. if(this != shape.getParent()){
  628. C.add.apply(this, arguments);
  629. this.rawNode.children.add(shape.rawNode);
  630. }
  631. return this; // self
  632. },
  633. remove: function(shape, silently){
  634. // summary: remove a shape from a group/surface
  635. // shape: dojox.gfx.Shape: a Silverlight shape object
  636. // silently: Boolean?: if true, regenerate a picture
  637. if(this == shape.getParent()){
  638. var parent = shape.rawNode.getParent();
  639. if(parent){
  640. parent.children.remove(shape.rawNode);
  641. }
  642. C.remove.apply(this, arguments);
  643. }
  644. return this; // self
  645. },
  646. clear: function(){
  647. // summary: removes all shapes from a group/surface
  648. this.rawNode.children.clear();
  649. return C.clear.apply(this, arguments);
  650. },
  651. _moveChildToFront: C._moveChildToFront,
  652. _moveChildToBack: C._moveChildToBack
  653. };
  654. var Creator = {
  655. createObject: function(shapeType, rawShape){
  656. // summary: creates an instance of the passed shapeType class
  657. // shapeType: Function: a class constructor to create an instance of
  658. // rawShape: Object: properties to be passed in to the classes "setShape" method
  659. if(!this.rawNode){ return null; }
  660. var shape = new shapeType();
  661. var node = this.rawNode.getHost().content.createFromXaml("<" + shapeType.nodeType + "/>");
  662. shape.setRawNode(node);
  663. shape.setShape(rawShape);
  664. this.add(shape);
  665. return shape; // dojox.gfx.Shape
  666. }
  667. };
  668. d.extend(sl.Text, Font);
  669. //d.extend(sl.TextPath, Font);
  670. d.extend(sl.Group, Container);
  671. d.extend(sl.Group, gs.Creator);
  672. d.extend(sl.Group, Creator);
  673. d.extend(sl.Surface, Container);
  674. d.extend(sl.Surface, gs.Creator);
  675. d.extend(sl.Surface, Creator);
  676. function mouseFix(s, a){
  677. var ev = {target: s, currentTarget: s, preventDefault: function(){}, stopPropagation: function(){}};
  678. try{
  679. if(a.source){
  680. // support silverlight 2.0
  681. ev.target = a.source;
  682. }
  683. }catch(e){
  684. // a.source does not exist in 1.0
  685. }
  686. if(a){
  687. try{
  688. ev.ctrlKey = a.ctrl;
  689. ev.shiftKey = a.shift;
  690. var p = a.getPosition(null);
  691. ev.x = ev.offsetX = ev.layerX = p.x;
  692. ev.y = ev.offsetY = ev.layerY = p.y;
  693. // calculate clientX and clientY
  694. var parent = surfaces[s.getHost().content.root.name];
  695. var t = d.position(parent);
  696. ev.clientX = t.x + p.x;
  697. ev.clientY = t.y + p.y;
  698. }catch(e){
  699. // squelch bugs in MouseLeave's implementation
  700. }
  701. }
  702. return ev;
  703. }
  704. function keyFix(s, a){
  705. var ev = {
  706. keyCode: a.platformKeyCode,
  707. ctrlKey: a.ctrl,
  708. shiftKey: a.shift
  709. };
  710. try{
  711. if(a.source){
  712. // source is defined from Silverlight 2+
  713. ev.target = a.source;
  714. }
  715. }catch(e){
  716. // a.source does not exist in 1.0
  717. }
  718. return ev;
  719. }
  720. var eventNames = {
  721. onclick: {name: "MouseLeftButtonUp", fix: mouseFix},
  722. onmouseenter: {name: "MouseEnter", fix: mouseFix},
  723. onmouseleave: {name: "MouseLeave", fix: mouseFix},
  724. onmouseover: {name: "MouseEnter", fix: mouseFix},
  725. onmouseout: {name: "MouseLeave", fix: mouseFix},
  726. onmousedown: {name: "MouseLeftButtonDown", fix: mouseFix},
  727. onmouseup: {name: "MouseLeftButtonUp", fix: mouseFix},
  728. onmousemove: {name: "MouseMove", fix: mouseFix},
  729. onkeydown: {name: "KeyDown", fix: keyFix},
  730. onkeyup: {name: "KeyUp", fix: keyFix}
  731. };
  732. var eventsProcessing = {
  733. connect: function(name, object, method){
  734. var token, n = name in eventNames ? eventNames[name] :
  735. {name: name, fix: function(){ return {}; }};
  736. if(arguments.length > 2){
  737. token = this.getEventSource().addEventListener(n.name,
  738. function(s, a){ d.hitch(object, method)(n.fix(s, a)); });
  739. }else{
  740. token = this.getEventSource().addEventListener(n.name,
  741. function(s, a){ object(n.fix(s, a)); });
  742. }
  743. return {name: n.name, token: token};
  744. },
  745. disconnect: function(token){
  746. try{
  747. this.getEventSource().removeEventListener(token.name, token.token);
  748. }catch(e){
  749. // bail out if the node is hidden
  750. }
  751. }
  752. };
  753. d.extend(sl.Shape, eventsProcessing);
  754. d.extend(sl.Surface, eventsProcessing);
  755. // patch dojox.gfx
  756. g.equalSources = function(a, b){
  757. // summary: compares event sources, returns true if they are equal
  758. return a && b && a.equals(b);
  759. };
  760. // see if we are required to initilize
  761. if(g.loadAndSwitch === "silverlight"){
  762. g.switchTo("silverlight");
  763. delete g.loadAndSwitch;
  764. }
  765. })();
  766. }