vml.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234
  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.vml"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.gfx.vml"] = true;
  8. dojo.provide("dojox.gfx.vml");
  9. dojo.require("dojox.gfx._base");
  10. dojo.require("dojox.gfx.shape");
  11. dojo.require("dojox.gfx.path");
  12. dojo.require("dojox.gfx.arc");
  13. dojo.require("dojox.gfx.gradient");
  14. (function(){
  15. var d = dojo, g = dojox.gfx, m = g.matrix, gs = g.shape, vml = g.vml;
  16. // dojox.gfx.vml.xmlns: String: a VML's namespace
  17. vml.xmlns = "urn:schemas-microsoft-com:vml";
  18. // dojox.gfx.vml.text_alignment: Object: mapping from SVG alignment to VML alignment
  19. vml.text_alignment = {start: "left", middle: "center", end: "right"};
  20. vml._parseFloat = function(str) {
  21. // summary: a helper function to parse VML-specific floating-point values
  22. // str: String: a representation of a floating-point number
  23. return str.match(/^\d+f$/i) ? parseInt(str) / 65536 : parseFloat(str); // Number
  24. };
  25. vml._bool = {"t": 1, "true": 1};
  26. d.declare("dojox.gfx.vml.Shape", gs.Shape, {
  27. // summary: VML-specific implementation of dojox.gfx.Shape methods
  28. setFill: function(fill){
  29. // summary: sets a fill object (VML)
  30. // fill: Object: a fill object
  31. // (see dojox.gfx.defaultLinearGradient,
  32. // dojox.gfx.defaultRadialGradient,
  33. // dojox.gfx.defaultPattern,
  34. // or dojo.Color)
  35. if(!fill){
  36. // don't fill
  37. this.fillStyle = null;
  38. this.rawNode.filled = "f";
  39. return this;
  40. }
  41. var i, f, fo, a, s;
  42. if(typeof fill == "object" && "type" in fill){
  43. // gradient
  44. switch(fill.type){
  45. case "linear":
  46. var matrix = this._getRealMatrix(), bbox = this.getBoundingBox(),
  47. tbbox = this._getRealBBox ? this._getRealBBox() : this.getTransformedBoundingBox();
  48. s = [];
  49. if(this.fillStyle !== fill){
  50. this.fillStyle = g.makeParameters(g.defaultLinearGradient, fill);
  51. }
  52. f = g.gradient.project(matrix, this.fillStyle,
  53. {x: bbox.x, y: bbox.y},
  54. {x: bbox.x + bbox.width, y: bbox.y + bbox.height},
  55. tbbox[0], tbbox[2]);
  56. a = f.colors;
  57. if(a[0].offset.toFixed(5) != "0.00000"){
  58. s.push("0 " + g.normalizeColor(a[0].color).toHex());
  59. }
  60. for(i = 0; i < a.length; ++i){
  61. s.push(a[i].offset.toFixed(5) + " " + g.normalizeColor(a[i].color).toHex());
  62. }
  63. i = a.length - 1;
  64. if(a[i].offset.toFixed(5) != "1.00000"){
  65. s.push("1 " + g.normalizeColor(a[i].color).toHex());
  66. }
  67. fo = this.rawNode.fill;
  68. fo.colors.value = s.join(";");
  69. fo.method = "sigma";
  70. fo.type = "gradient";
  71. fo.angle = (270 - m._radToDeg(f.angle)) % 360;
  72. fo.on = true;
  73. break;
  74. case "radial":
  75. f = g.makeParameters(g.defaultRadialGradient, fill);
  76. this.fillStyle = f;
  77. var l = parseFloat(this.rawNode.style.left),
  78. t = parseFloat(this.rawNode.style.top),
  79. w = parseFloat(this.rawNode.style.width),
  80. h = parseFloat(this.rawNode.style.height),
  81. c = isNaN(w) ? 1 : 2 * f.r / w;
  82. a = [];
  83. // add a color at the offset 0 (1 in VML coordinates)
  84. if(f.colors[0].offset > 0){
  85. a.push({offset: 1, color: g.normalizeColor(f.colors[0].color)});
  86. }
  87. // massage colors
  88. d.forEach(f.colors, function(v, i){
  89. a.push({offset: 1 - v.offset * c, color: g.normalizeColor(v.color)});
  90. });
  91. i = a.length - 1;
  92. while(i >= 0 && a[i].offset < 0){ --i; }
  93. if(i < a.length - 1){
  94. // correct excessive colors
  95. var q = a[i], p = a[i + 1];
  96. p.color = d.blendColors(q.color, p.color, q.offset / (q.offset - p.offset));
  97. p.offset = 0;
  98. while(a.length - i > 2) a.pop();
  99. }
  100. // set colors
  101. i = a.length - 1, s = [];
  102. if(a[i].offset > 0){
  103. s.push("0 " + a[i].color.toHex());
  104. }
  105. for(; i >= 0; --i){
  106. s.push(a[i].offset.toFixed(5) + " " + a[i].color.toHex());
  107. }
  108. fo = this.rawNode.fill;
  109. fo.colors.value = s.join(";");
  110. fo.method = "sigma";
  111. fo.type = "gradientradial";
  112. if(isNaN(w) || isNaN(h) || isNaN(l) || isNaN(t)){
  113. fo.focusposition = "0.5 0.5";
  114. }else{
  115. fo.focusposition = ((f.cx - l) / w).toFixed(5) + " " + ((f.cy - t) / h).toFixed(5);
  116. }
  117. fo.focussize = "0 0";
  118. fo.on = true;
  119. break;
  120. case "pattern":
  121. f = g.makeParameters(g.defaultPattern, fill);
  122. this.fillStyle = f;
  123. fo = this.rawNode.fill;
  124. fo.type = "tile";
  125. fo.src = f.src;
  126. if(f.width && f.height){
  127. // in points
  128. fo.size.x = g.px2pt(f.width);
  129. fo.size.y = g.px2pt(f.height);
  130. }
  131. fo.alignShape = "f";
  132. fo.position.x = 0;
  133. fo.position.y = 0;
  134. fo.origin.x = f.width ? f.x / f.width : 0;
  135. fo.origin.y = f.height ? f.y / f.height : 0;
  136. fo.on = true;
  137. break;
  138. }
  139. this.rawNode.fill.opacity = 1;
  140. return this;
  141. }
  142. // color object
  143. this.fillStyle = g.normalizeColor(fill);
  144. fo = this.rawNode.fill;
  145. if(!fo){
  146. fo = this.rawNode.ownerDocument.createElement("v:fill");
  147. }
  148. fo.method = "any";
  149. fo.type = "solid";
  150. fo.opacity = this.fillStyle.a;
  151. var alphaFilter = this.rawNode.filters["DXImageTransform.Microsoft.Alpha"];
  152. if(alphaFilter){
  153. alphaFilter.opacity = Math.round(this.fillStyle.a * 100);
  154. }
  155. this.rawNode.fillcolor = this.fillStyle.toHex();
  156. this.rawNode.filled = true;
  157. return this; // self
  158. },
  159. setStroke: function(stroke){
  160. // summary: sets a stroke object (VML)
  161. // stroke: Object: a stroke object
  162. // (see dojox.gfx.defaultStroke)
  163. if(!stroke){
  164. // don't stroke
  165. this.strokeStyle = null;
  166. this.rawNode.stroked = "f";
  167. return this;
  168. }
  169. // normalize the stroke
  170. if(typeof stroke == "string" || d.isArray(stroke) || stroke instanceof d.Color){
  171. stroke = {color: stroke};
  172. }
  173. var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
  174. s.color = g.normalizeColor(s.color);
  175. // generate attributes
  176. var rn = this.rawNode;
  177. rn.stroked = true;
  178. rn.strokecolor = s.color.toCss();
  179. rn.strokeweight = s.width + "px"; // TODO: should we assume that the width is always in pixels?
  180. if(rn.stroke) {
  181. rn.stroke.opacity = s.color.a;
  182. rn.stroke.endcap = this._translate(this._capMap, s.cap);
  183. if(typeof s.join == "number") {
  184. rn.stroke.joinstyle = "miter";
  185. rn.stroke.miterlimit = s.join;
  186. }else{
  187. rn.stroke.joinstyle = s.join;
  188. // rn.stroke.miterlimit = s.width;
  189. }
  190. rn.stroke.dashstyle = s.style == "none" ? "Solid" : s.style;
  191. }
  192. return this; // self
  193. },
  194. _capMap: { butt: 'flat' },
  195. _capMapReversed: { flat: 'butt' },
  196. _translate: function(dict, value) {
  197. return (value in dict) ? dict[value] : value;
  198. },
  199. _applyTransform: function() {
  200. var matrix = this._getRealMatrix();
  201. if(matrix){
  202. var skew = this.rawNode.skew;
  203. if(typeof skew == "undefined"){
  204. for(var i = 0; i < this.rawNode.childNodes.length; ++i){
  205. if(this.rawNode.childNodes[i].tagName == "skew"){
  206. skew = this.rawNode.childNodes[i];
  207. break;
  208. }
  209. }
  210. }
  211. if(skew){
  212. skew.on = "f";
  213. var mt = matrix.xx.toFixed(8) + " " + matrix.xy.toFixed(8) + " " +
  214. matrix.yx.toFixed(8) + " " + matrix.yy.toFixed(8) + " 0 0",
  215. offset = Math.floor(matrix.dx).toFixed() + "px " + Math.floor(matrix.dy).toFixed() + "px",
  216. s = this.rawNode.style,
  217. l = parseFloat(s.left),
  218. t = parseFloat(s.top),
  219. w = parseFloat(s.width),
  220. h = parseFloat(s.height);
  221. if(isNaN(l)) l = 0;
  222. if(isNaN(t)) t = 0;
  223. if(isNaN(w) || !w) w = 1;
  224. if(isNaN(h) || !h) h = 1;
  225. var origin = (-l / w - 0.5).toFixed(8) + " " + (-t / h - 0.5).toFixed(8);
  226. skew.matrix = mt;
  227. skew.origin = origin;
  228. skew.offset = offset;
  229. skew.on = true;
  230. }
  231. }
  232. if(this.fillStyle && this.fillStyle.type == "linear"){
  233. this.setFill(this.fillStyle);
  234. }
  235. return this;
  236. },
  237. _setDimensions: function(width, height){
  238. // summary: sets the width and height of the rawNode,
  239. // if the surface sixe has been changed
  240. // width: String: width in pixels
  241. // height: String: height in pixels
  242. // default implementation does nothing
  243. return this; // self
  244. },
  245. setRawNode: function(rawNode){
  246. // summary:
  247. // assigns and clears the underlying node that will represent this
  248. // shape. Once set, transforms, gradients, etc, can be applied.
  249. // (no fill & stroke by default)
  250. rawNode.stroked = "f";
  251. rawNode.filled = "f";
  252. this.rawNode = rawNode;
  253. },
  254. // move family
  255. _moveToFront: function(){
  256. // summary: moves a shape to front of its parent's list of shapes (VML)
  257. this.rawNode.parentNode.appendChild(this.rawNode);
  258. return this;
  259. },
  260. _moveToBack: function(){
  261. // summary: moves a shape to back of its parent's list of shapes (VML)
  262. var r = this.rawNode, p = r.parentNode, n = p.firstChild;
  263. p.insertBefore(r, n);
  264. if(n.tagName == "rect"){
  265. // surface has a background rectangle, which position should be preserved
  266. n.swapNode(r);
  267. }
  268. return this;
  269. },
  270. _getRealMatrix: function(){
  271. // summary: returns the cumulative ("real") transformation matrix
  272. // by combining the shape's matrix with its parent's matrix
  273. return this.parentMatrix ? new g.Matrix2D([this.parentMatrix, this.matrix]) : this.matrix; // dojox.gfx.Matrix2D
  274. }
  275. });
  276. dojo.declare("dojox.gfx.vml.Group", vml.Shape, {
  277. // summary: a group shape (VML), which can be used
  278. // to logically group shapes (e.g, to propagate matricies)
  279. constructor: function(){
  280. gs.Container._init.call(this);
  281. },
  282. // apply transformation
  283. _applyTransform: function(){
  284. // summary: applies a transformation matrix to a group
  285. var matrix = this._getRealMatrix();
  286. for(var i = 0; i < this.children.length; ++i){
  287. this.children[i]._updateParentMatrix(matrix);
  288. }
  289. return this; // self
  290. },
  291. _setDimensions: function(width, height){
  292. // summary: sets the width and height of the rawNode,
  293. // if the surface sixe has been changed
  294. // width: String: width in pixels
  295. // height: String: height in pixels
  296. var r = this.rawNode, rs = r.style,
  297. bs = this.bgNode.style;
  298. rs.width = width;
  299. rs.height = height;
  300. r.coordsize = width + " " + height;
  301. bs.width = width;
  302. bs.height = height;
  303. for(var i = 0; i < this.children.length; ++i){
  304. this.children[i]._setDimensions(width, height);
  305. }
  306. return this; // self
  307. }
  308. });
  309. vml.Group.nodeType = "group";
  310. dojo.declare("dojox.gfx.vml.Rect", [vml.Shape, gs.Rect], {
  311. // summary: a rectangle shape (VML)
  312. setShape: function(newShape){
  313. // summary: sets a rectangle shape object (VML)
  314. // newShape: Object: a rectangle shape object
  315. var shape = this.shape = g.makeParameters(this.shape, newShape);
  316. this.bbox = null;
  317. var r = Math.min(1, (shape.r / Math.min(parseFloat(shape.width), parseFloat(shape.height)))).toFixed(8);
  318. // a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node
  319. var parent = this.rawNode.parentNode, before = null;
  320. if(parent){
  321. if(parent.lastChild !== this.rawNode){
  322. for(var i = 0; i < parent.childNodes.length; ++i){
  323. if(parent.childNodes[i] === this.rawNode){
  324. before = parent.childNodes[i + 1];
  325. break;
  326. }
  327. }
  328. }
  329. parent.removeChild(this.rawNode);
  330. }
  331. if(d.isIE > 7){
  332. var node = this.rawNode.ownerDocument.createElement("v:roundrect");
  333. node.arcsize = r;
  334. node.style.display = "inline-block";
  335. this.rawNode = node;
  336. }else{
  337. this.rawNode.arcsize = r;
  338. }
  339. if(parent){
  340. if(before){
  341. parent.insertBefore(this.rawNode, before);
  342. }else{
  343. parent.appendChild(this.rawNode);
  344. }
  345. }
  346. var style = this.rawNode.style;
  347. style.left = shape.x.toFixed();
  348. style.top = shape.y.toFixed();
  349. style.width = (typeof shape.width == "string" && shape.width.indexOf("%") >= 0) ? shape.width : shape.width.toFixed();
  350. style.height = (typeof shape.width == "string" && shape.height.indexOf("%") >= 0) ? shape.height : shape.height.toFixed();
  351. // set all necessary styles, which are lost by VML (yes, it's a VML's bug)
  352. return this.setTransform(this.matrix).setFill(this.fillStyle).setStroke(this.strokeStyle); // self
  353. }
  354. });
  355. vml.Rect.nodeType = "roundrect"; // use a roundrect so the stroke join type is respected
  356. dojo.declare("dojox.gfx.vml.Ellipse", [vml.Shape, gs.Ellipse], {
  357. // summary: an ellipse shape (VML)
  358. setShape: function(newShape){
  359. // summary: sets an ellipse shape object (VML)
  360. // newShape: Object: an ellipse shape object
  361. var shape = this.shape = g.makeParameters(this.shape, newShape);
  362. this.bbox = null;
  363. var style = this.rawNode.style;
  364. style.left = (shape.cx - shape.rx).toFixed();
  365. style.top = (shape.cy - shape.ry).toFixed();
  366. style.width = (shape.rx * 2).toFixed();
  367. style.height = (shape.ry * 2).toFixed();
  368. return this.setTransform(this.matrix); // self
  369. }
  370. });
  371. vml.Ellipse.nodeType = "oval";
  372. dojo.declare("dojox.gfx.vml.Circle", [vml.Shape, gs.Circle], {
  373. // summary: a circle shape (VML)
  374. setShape: function(newShape){
  375. // summary: sets a circle shape object (VML)
  376. // newShape: Object: a circle shape object
  377. var shape = this.shape = g.makeParameters(this.shape, newShape);
  378. this.bbox = null;
  379. var style = this.rawNode.style;
  380. style.left = (shape.cx - shape.r).toFixed();
  381. style.top = (shape.cy - shape.r).toFixed();
  382. style.width = (shape.r * 2).toFixed();
  383. style.height = (shape.r * 2).toFixed();
  384. return this; // self
  385. }
  386. });
  387. vml.Circle.nodeType = "oval";
  388. dojo.declare("dojox.gfx.vml.Line", [vml.Shape, gs.Line], {
  389. // summary: a line shape (VML)
  390. constructor: function(rawNode){
  391. if(rawNode) rawNode.setAttribute("dojoGfxType", "line");
  392. },
  393. setShape: function(newShape){
  394. // summary: sets a line shape object (VML)
  395. // newShape: Object: a line shape object
  396. var shape = this.shape = g.makeParameters(this.shape, newShape);
  397. this.bbox = null;
  398. this.rawNode.path.v = "m" + shape.x1.toFixed() + " " + shape.y1.toFixed() +
  399. "l" + shape.x2.toFixed() + " " + shape.y2.toFixed() + "e";
  400. return this.setTransform(this.matrix); // self
  401. }
  402. });
  403. vml.Line.nodeType = "shape";
  404. dojo.declare("dojox.gfx.vml.Polyline", [vml.Shape, gs.Polyline], {
  405. // summary: a polyline/polygon shape (VML)
  406. constructor: function(rawNode){
  407. if(rawNode) rawNode.setAttribute("dojoGfxType", "polyline");
  408. },
  409. setShape: function(points, closed){
  410. // summary: sets a polyline/polygon shape object (VML)
  411. // points: Object: a polyline/polygon shape object
  412. // closed: Boolean?: if true, close the polyline explicitely
  413. if(points && points instanceof Array){
  414. // branch
  415. // points: Array: an array of points
  416. this.shape = g.makeParameters(this.shape, { points: points });
  417. if(closed && this.shape.points.length) this.shape.points.push(this.shape.points[0]);
  418. }else{
  419. this.shape = g.makeParameters(this.shape, points);
  420. }
  421. this.bbox = null;
  422. this._normalizePoints();
  423. var attr = [], p = this.shape.points;
  424. if(p.length > 0){
  425. attr.push("m");
  426. attr.push(p[0].x.toFixed(), p[0].y.toFixed());
  427. if(p.length > 1){
  428. attr.push("l");
  429. for(var i = 1; i < p.length; ++i){
  430. attr.push(p[i].x.toFixed(), p[i].y.toFixed());
  431. }
  432. }
  433. }
  434. attr.push("e");
  435. this.rawNode.path.v = attr.join(" ");
  436. return this.setTransform(this.matrix); // self
  437. }
  438. });
  439. vml.Polyline.nodeType = "shape";
  440. dojo.declare("dojox.gfx.vml.Image", [vml.Shape, gs.Image], {
  441. // summary: an image (VML)
  442. setShape: function(newShape){
  443. // summary: sets an image shape object (VML)
  444. // newShape: Object: an image shape object
  445. var shape = this.shape = g.makeParameters(this.shape, newShape);
  446. this.bbox = null;
  447. this.rawNode.firstChild.src = shape.src;
  448. return this.setTransform(this.matrix); // self
  449. },
  450. _applyTransform: function() {
  451. var matrix = this._getRealMatrix(),
  452. rawNode = this.rawNode,
  453. s = rawNode.style,
  454. shape = this.shape;
  455. if(matrix){
  456. matrix = m.multiply(matrix, {dx: shape.x, dy: shape.y});
  457. }else{
  458. matrix = m.normalize({dx: shape.x, dy: shape.y});
  459. }
  460. if(matrix.xy == 0 && matrix.yx == 0 && matrix.xx > 0 && matrix.yy > 0){
  461. // special case to avoid filters
  462. s.filter = "";
  463. s.width = Math.floor(matrix.xx * shape.width);
  464. s.height = Math.floor(matrix.yy * shape.height);
  465. s.left = Math.floor(matrix.dx);
  466. s.top = Math.floor(matrix.dy);
  467. }else{
  468. var ps = rawNode.parentNode.style;
  469. s.left = "0px";
  470. s.top = "0px";
  471. s.width = ps.width;
  472. s.height = ps.height;
  473. matrix = m.multiply(matrix,
  474. {xx: shape.width / parseInt(s.width), yy: shape.height / parseInt(s.height)});
  475. var f = rawNode.filters["DXImageTransform.Microsoft.Matrix"];
  476. if(f){
  477. f.M11 = matrix.xx;
  478. f.M12 = matrix.xy;
  479. f.M21 = matrix.yx;
  480. f.M22 = matrix.yy;
  481. f.Dx = matrix.dx;
  482. f.Dy = matrix.dy;
  483. }else{
  484. s.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + matrix.xx +
  485. ", M12=" + matrix.xy + ", M21=" + matrix.yx + ", M22=" + matrix.yy +
  486. ", Dx=" + matrix.dx + ", Dy=" + matrix.dy + ")";
  487. }
  488. }
  489. return this; // self
  490. },
  491. _setDimensions: function(width, height){
  492. // summary: sets the width and height of the rawNode,
  493. // if the surface sixe has been changed
  494. // width: String: width in pixels
  495. // height: String: height in pixels
  496. var r = this.rawNode, f = r.filters["DXImageTransform.Microsoft.Matrix"];
  497. if(f){
  498. var s = r.style;
  499. s.width = width;
  500. s.height = height;
  501. return this._applyTransform(); // self
  502. }
  503. return this; // self
  504. }
  505. });
  506. vml.Image.nodeType = "rect";
  507. dojo.declare("dojox.gfx.vml.Text", [vml.Shape, gs.Text], {
  508. // summary: an anchored text (VML)
  509. constructor: function(rawNode){
  510. if(rawNode){rawNode.setAttribute("dojoGfxType", "text");}
  511. this.fontStyle = null;
  512. },
  513. _alignment: {start: "left", middle: "center", end: "right"},
  514. setShape: function(newShape){
  515. // summary: sets a text shape object (VML)
  516. // newShape: Object: a text shape object
  517. this.shape = g.makeParameters(this.shape, newShape);
  518. this.bbox = null;
  519. var r = this.rawNode, s = this.shape, x = s.x, y = s.y.toFixed(), path;
  520. switch(s.align){
  521. case "middle":
  522. x -= 5;
  523. break;
  524. case "end":
  525. x -= 10;
  526. break;
  527. }
  528. path = "m" + x.toFixed() + "," + y + "l" + (x + 10).toFixed() + "," + y + "e";
  529. // find path and text path
  530. var p = null, t = null, c = r.childNodes;
  531. for(var i = 0; i < c.length; ++i){
  532. var tag = c[i].tagName;
  533. if(tag == "path"){
  534. p = c[i];
  535. if(t) break;
  536. }else if(tag == "textpath"){
  537. t = c[i];
  538. if(p) break;
  539. }
  540. }
  541. if(!p){
  542. p = r.ownerDocument.createElement("v:path");
  543. r.appendChild(p);
  544. }
  545. if(!t){
  546. t = r.ownerDocument.createElement("v:textpath");
  547. r.appendChild(t);
  548. }
  549. p.v = path;
  550. p.textPathOk = true;
  551. t.on = true;
  552. var a = vml.text_alignment[s.align];
  553. t.style["v-text-align"] = a ? a : "left";
  554. t.style["text-decoration"] = s.decoration;
  555. t.style["v-rotate-letters"] = s.rotated;
  556. t.style["v-text-kern"] = s.kerning;
  557. t.string = s.text;
  558. return this.setTransform(this.matrix); // self
  559. },
  560. _setFont: function(){
  561. // summary: sets a font object (VML)
  562. var f = this.fontStyle, c = this.rawNode.childNodes;
  563. for(var i = 0; i < c.length; ++i){
  564. if(c[i].tagName == "textpath"){
  565. c[i].style.font = g.makeFontString(f);
  566. break;
  567. }
  568. }
  569. this.setTransform(this.matrix);
  570. },
  571. _getRealMatrix: function(){
  572. // summary: returns the cumulative ("real") transformation matrix
  573. // by combining the shape's matrix with its parent's matrix;
  574. // it makes a correction for a font size
  575. var matrix = this.inherited(arguments);
  576. // It appears that text is always aligned vertically at a middle of x-height (???).
  577. // It is impossible to obtain these metrics from VML => I try to approximate it with
  578. // more-or-less util value of 0.7 * FontSize, which is typical for European fonts.
  579. if(matrix){
  580. matrix = m.multiply(matrix,
  581. {dy: -g.normalizedLength(this.fontStyle ? this.fontStyle.size : "10pt") * 0.35});
  582. }
  583. return matrix; // dojox.gfx.Matrix2D
  584. },
  585. getTextWidth: function(){
  586. // summary: get the text width, in px
  587. var rawNode = this.rawNode, _display = rawNode.style.display;
  588. rawNode.style.display = "inline";
  589. var _width = g.pt2px(parseFloat(rawNode.currentStyle.width));
  590. rawNode.style.display = _display;
  591. return _width;
  592. }
  593. });
  594. vml.Text.nodeType = "shape";
  595. dojo.declare("dojox.gfx.vml.Path", [vml.Shape, g.path.Path], {
  596. // summary: a path shape (VML)
  597. constructor: function(rawNode){
  598. if(rawNode && !rawNode.getAttribute("dojoGfxType")){
  599. rawNode.setAttribute("dojoGfxType", "path");
  600. }
  601. this.vmlPath = "";
  602. this.lastControl = {};
  603. },
  604. _updateWithSegment: function(segment){
  605. // summary: updates the bounding box of path with new segment
  606. // segment: Object: a segment
  607. var last = d.clone(this.last);
  608. this.inherited(arguments);
  609. if(arguments.length > 1){ return; } // skip transfomed bbox calculations
  610. // add a VML path segment
  611. var path = this[this.renderers[segment.action]](segment, last);
  612. if(typeof this.vmlPath == "string"){
  613. this.vmlPath += path.join("");
  614. this.rawNode.path.v = this.vmlPath + " r0,0 e";
  615. }else{
  616. Array.prototype.push.apply(this.vmlPath, path); //FIXME: why not push()?
  617. }
  618. },
  619. setShape: function(newShape){
  620. // summary: forms a path using a shape (VML)
  621. // newShape: Object: an VML path string or a path object (see dojox.gfx.defaultPath)
  622. this.vmlPath = [];
  623. this.lastControl.type = ""; // no prior control point
  624. this.inherited(arguments);
  625. this.vmlPath = this.vmlPath.join("");
  626. this.rawNode.path.v = this.vmlPath + " r0,0 e";
  627. return this;
  628. },
  629. _pathVmlToSvgMap: {m: "M", l: "L", t: "m", r: "l", c: "C", v: "c", qb: "Q", x: "z", e: ""},
  630. // VML-specific segment renderers
  631. renderers: {
  632. M: "_moveToA", m: "_moveToR",
  633. L: "_lineToA", l: "_lineToR",
  634. H: "_hLineToA", h: "_hLineToR",
  635. V: "_vLineToA", v: "_vLineToR",
  636. C: "_curveToA", c: "_curveToR",
  637. S: "_smoothCurveToA", s: "_smoothCurveToR",
  638. Q: "_qCurveToA", q: "_qCurveToR",
  639. T: "_qSmoothCurveToA", t: "_qSmoothCurveToR",
  640. A: "_arcTo", a: "_arcTo",
  641. Z: "_closePath", z: "_closePath"
  642. },
  643. _addArgs: function(path, segment, from, upto){
  644. var n = segment instanceof Array ? segment : segment.args;
  645. for(var i = from; i < upto; ++i){
  646. path.push(" ", n[i].toFixed());
  647. }
  648. },
  649. _adjustRelCrd: function(last, segment, step){
  650. var n = segment instanceof Array ? segment : segment.args, l = n.length,
  651. result = new Array(l), i = 0, x = last.x, y = last.y;
  652. if(typeof x != "number"){
  653. // there is no last coordinate =>
  654. // treat the first pair as an absolute coordinate
  655. result[0] = x = n[0];
  656. result[1] = y = n[1];
  657. i = 2;
  658. }
  659. if(typeof step == "number" && step != 2){
  660. var j = step;
  661. while(j <= l){
  662. for(; i < j; i += 2){
  663. result[i] = x + n[i];
  664. result[i + 1] = y + n[i + 1];
  665. }
  666. x = result[j - 2];
  667. y = result[j - 1];
  668. j += step;
  669. }
  670. }else{
  671. for(; i < l; i += 2){
  672. result[i] = (x += n[i]);
  673. result[i + 1] = (y += n[i + 1]);
  674. }
  675. }
  676. return result;
  677. },
  678. _adjustRelPos: function(last, segment){
  679. var n = segment instanceof Array ? segment : segment.args, l = n.length,
  680. result = new Array(l);
  681. for(var i = 0; i < l; ++i){
  682. result[i] = (last += n[i]);
  683. }
  684. return result;
  685. },
  686. _moveToA: function(segment){
  687. var p = [" m"], n = segment instanceof Array ? segment : segment.args, l = n.length;
  688. this._addArgs(p, n, 0, 2);
  689. if(l > 2){
  690. p.push(" l");
  691. this._addArgs(p, n, 2, l);
  692. }
  693. this.lastControl.type = ""; // no control point after this primitive
  694. return p;
  695. },
  696. _moveToR: function(segment, last){
  697. return this._moveToA(this._adjustRelCrd(last, segment));
  698. },
  699. _lineToA: function(segment){
  700. var p = [" l"], n = segment instanceof Array ? segment : segment.args;
  701. this._addArgs(p, n, 0, n.length);
  702. this.lastControl.type = ""; // no control point after this primitive
  703. return p;
  704. },
  705. _lineToR: function(segment, last){
  706. return this._lineToA(this._adjustRelCrd(last, segment));
  707. },
  708. _hLineToA: function(segment, last){
  709. var p = [" l"], y = " " + last.y.toFixed(),
  710. n = segment instanceof Array ? segment : segment.args, l = n.length;
  711. for(var i = 0; i < l; ++i){
  712. p.push(" ", n[i].toFixed(), y);
  713. }
  714. this.lastControl.type = ""; // no control point after this primitive
  715. return p;
  716. },
  717. _hLineToR: function(segment, last){
  718. return this._hLineToA(this._adjustRelPos(last.x, segment), last);
  719. },
  720. _vLineToA: function(segment, last){
  721. var p = [" l"], x = " " + last.x.toFixed(),
  722. n = segment instanceof Array ? segment : segment.args, l = n.length;
  723. for(var i = 0; i < l; ++i){
  724. p.push(x, " ", n[i].toFixed());
  725. }
  726. this.lastControl.type = ""; // no control point after this primitive
  727. return p;
  728. },
  729. _vLineToR: function(segment, last){
  730. return this._vLineToA(this._adjustRelPos(last.y, segment), last);
  731. },
  732. _curveToA: function(segment){
  733. var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
  734. lc = this.lastControl;
  735. for(var i = 0; i < l; i += 6){
  736. p.push(" c");
  737. this._addArgs(p, n, i, i + 6);
  738. }
  739. lc.x = n[l - 4];
  740. lc.y = n[l - 3];
  741. lc.type = "C";
  742. return p;
  743. },
  744. _curveToR: function(segment, last){
  745. return this._curveToA(this._adjustRelCrd(last, segment, 6));
  746. },
  747. _smoothCurveToA: function(segment, last){
  748. var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
  749. lc = this.lastControl, i = 0;
  750. if(lc.type != "C"){
  751. p.push(" c");
  752. this._addArgs(p, [last.x, last.y], 0, 2);
  753. this._addArgs(p, n, 0, 4);
  754. lc.x = n[0];
  755. lc.y = n[1];
  756. lc.type = "C";
  757. i = 4;
  758. }
  759. for(; i < l; i += 4){
  760. p.push(" c");
  761. this._addArgs(p, [
  762. 2 * last.x - lc.x,
  763. 2 * last.y - lc.y
  764. ], 0, 2);
  765. this._addArgs(p, n, i, i + 4);
  766. lc.x = n[i];
  767. lc.y = n[i + 1];
  768. }
  769. return p;
  770. },
  771. _smoothCurveToR: function(segment, last){
  772. return this._smoothCurveToA(this._adjustRelCrd(last, segment, 4), last);
  773. },
  774. _qCurveToA: function(segment){
  775. var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
  776. lc = this.lastControl;
  777. for(var i = 0; i < l; i += 4){
  778. p.push(" qb");
  779. this._addArgs(p, n, i, i + 4);
  780. }
  781. lc.x = n[l - 4];
  782. lc.y = n[l - 3];
  783. lc.type = "Q";
  784. return p;
  785. },
  786. _qCurveToR: function(segment, last){
  787. return this._qCurveToA(this._adjustRelCrd(last, segment, 4));
  788. },
  789. _qSmoothCurveToA: function(segment, last){
  790. var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
  791. lc = this.lastControl, i = 0;
  792. if(lc.type != "Q"){
  793. p.push(" qb");
  794. this._addArgs(p, [
  795. lc.x = last.x,
  796. lc.y = last.y
  797. ], 0, 2);
  798. lc.type = "Q";
  799. this._addArgs(p, n, 0, 2);
  800. i = 2;
  801. }
  802. for(; i < l; i += 2){
  803. p.push(" qb");
  804. this._addArgs(p, [
  805. lc.x = 2 * last.x - lc.x,
  806. lc.y = 2 * last.y - lc.y
  807. ], 0, 2);
  808. this._addArgs(p, n, i, i + 2);
  809. }
  810. return p;
  811. },
  812. _qSmoothCurveToR: function(segment, last){
  813. return this._qSmoothCurveToA(this._adjustRelCrd(last, segment, 2), last);
  814. },
  815. _arcTo: function(segment, last){
  816. var p = [], n = segment.args, l = n.length, relative = segment.action == "a";
  817. for(var i = 0; i < l; i += 7){
  818. var x1 = n[i + 5], y1 = n[i + 6];
  819. if(relative){
  820. x1 += last.x;
  821. y1 += last.y;
  822. }
  823. var result = g.arc.arcAsBezier(
  824. last, n[i], n[i + 1], n[i + 2],
  825. n[i + 3] ? 1 : 0, n[i + 4] ? 1 : 0,
  826. x1, y1
  827. );
  828. for(var j = 0; j < result.length; ++j){
  829. p.push(" c");
  830. var t = result[j];
  831. this._addArgs(p, t, 0, t.length);
  832. this._updateBBox(t[0], t[1]);
  833. this._updateBBox(t[2], t[3]);
  834. this._updateBBox(t[4], t[5]);
  835. }
  836. last.x = x1;
  837. last.y = y1;
  838. }
  839. this.lastControl.type = ""; // no control point after this primitive
  840. return p;
  841. },
  842. _closePath: function(){
  843. this.lastControl.type = ""; // no control point after this primitive
  844. return ["x"];
  845. }
  846. });
  847. vml.Path.nodeType = "shape";
  848. dojo.declare("dojox.gfx.vml.TextPath", [vml.Path, g.path.TextPath], {
  849. // summary: a textpath shape (VML)
  850. constructor: function(rawNode){
  851. if(rawNode){rawNode.setAttribute("dojoGfxType", "textpath");}
  852. this.fontStyle = null;
  853. if(!("text" in this)){
  854. this.text = d.clone(g.defaultTextPath);
  855. }
  856. if(!("fontStyle" in this)){
  857. this.fontStyle = d.clone(g.defaultFont);
  858. }
  859. },
  860. setText: function(newText){
  861. // summary: sets a text to be drawn along the path
  862. this.text = g.makeParameters(this.text,
  863. typeof newText == "string" ? {text: newText} : newText);
  864. this._setText();
  865. return this; // self
  866. },
  867. setFont: function(newFont){
  868. // summary: sets a font for text
  869. this.fontStyle = typeof newFont == "string" ?
  870. g.splitFontString(newFont) :
  871. g.makeParameters(g.defaultFont, newFont);
  872. this._setFont();
  873. return this; // self
  874. },
  875. _setText: function(){
  876. // summary: sets a text shape object (VML)
  877. this.bbox = null;
  878. var r = this.rawNode, s = this.text,
  879. // find path and text path
  880. p = null, t = null, c = r.childNodes;
  881. for(var i = 0; i < c.length; ++i){
  882. var tag = c[i].tagName;
  883. if(tag == "path"){
  884. p = c[i];
  885. if(t) break;
  886. }else if(tag == "textpath"){
  887. t = c[i];
  888. if(p) break;
  889. }
  890. }
  891. if(!p){
  892. p = this.rawNode.ownerDocument.createElement("v:path");
  893. r.appendChild(p);
  894. }
  895. if(!t){
  896. t = this.rawNode.ownerDocument.createElement("v:textpath");
  897. r.appendChild(t);
  898. }
  899. p.textPathOk = true;
  900. t.on = true;
  901. var a = vml.text_alignment[s.align];
  902. t.style["v-text-align"] = a ? a : "left";
  903. t.style["text-decoration"] = s.decoration;
  904. t.style["v-rotate-letters"] = s.rotated;
  905. t.style["v-text-kern"] = s.kerning;
  906. t.string = s.text;
  907. },
  908. _setFont: function(){
  909. // summary: sets a font object (VML)
  910. var f = this.fontStyle, c = this.rawNode.childNodes;
  911. for(var i = 0; i < c.length; ++i){
  912. if(c[i].tagName == "textpath"){
  913. c[i].style.font = g.makeFontString(f);
  914. break;
  915. }
  916. }
  917. }
  918. });
  919. vml.TextPath.nodeType = "shape";
  920. dojo.declare("dojox.gfx.vml.Surface", gs.Surface, {
  921. // summary: a surface object to be used for drawings (VML)
  922. constructor: function(){
  923. gs.Container._init.call(this);
  924. },
  925. setDimensions: function(width, height){
  926. // summary: sets the width and height of the rawNode
  927. // width: String: width of surface, e.g., "100px"
  928. // height: String: height of surface, e.g., "100px"
  929. this.width = g.normalizedLength(width); // in pixels
  930. this.height = g.normalizedLength(height); // in pixels
  931. if(!this.rawNode) return this;
  932. var cs = this.clipNode.style,
  933. r = this.rawNode, rs = r.style,
  934. bs = this.bgNode.style,
  935. ps = this._parent.style, i;
  936. ps.width = width;
  937. ps.height = height;
  938. cs.width = width;
  939. cs.height = height;
  940. cs.clip = "rect(0px " + width + "px " + height + "px 0px)";
  941. rs.width = width;
  942. rs.height = height;
  943. r.coordsize = width + " " + height;
  944. bs.width = width;
  945. bs.height = height;
  946. for(i = 0; i < this.children.length; ++i){
  947. this.children[i]._setDimensions(width, height);
  948. }
  949. return this; // self
  950. },
  951. getDimensions: function(){
  952. // summary: returns an object with properties "width" and "height"
  953. var t = this.rawNode ? {
  954. width: g.normalizedLength(this.rawNode.style.width),
  955. height: g.normalizedLength(this.rawNode.style.height)} : null;
  956. if(t.width <= 0){ t.width = this.width; }
  957. if(t.height <= 0){ t.height = this.height; }
  958. return t; // Object
  959. }
  960. });
  961. vml.createSurface = function(parentNode, width, height){
  962. // summary: creates a surface (VML)
  963. // parentNode: Node: a parent node
  964. // width: String: width of surface, e.g., "100px"
  965. // height: String: height of surface, e.g., "100px"
  966. if(!width && !height){
  967. var pos = d.position(parentNode);
  968. width = width || pos.w;
  969. height = height || pos.h;
  970. }
  971. if(typeof width == "number"){
  972. width = width + "px";
  973. }
  974. if(typeof height == "number"){
  975. height = height + "px";
  976. }
  977. var s = new vml.Surface(), p = d.byId(parentNode),
  978. c = s.clipNode = p.ownerDocument.createElement("div"),
  979. r = s.rawNode = p.ownerDocument.createElement("v:group"),
  980. cs = c.style, rs = r.style;
  981. if(d.isIE > 7){
  982. rs.display = "inline-block";
  983. }
  984. s._parent = p;
  985. s._nodes.push(c); // other elements will be deleted as parts of "c"
  986. p.style.width = width;
  987. p.style.height = height;
  988. cs.position = "absolute";
  989. cs.width = width;
  990. cs.height = height;
  991. cs.clip = "rect(0px " + width + " " + height + " 0px)";
  992. rs.position = "absolute";
  993. rs.width = width;
  994. rs.height = height;
  995. r.coordsize = (width === "100%" ? width : parseFloat(width)) + " " +
  996. (height === "100%" ? height : parseFloat(height));
  997. r.coordorigin = "0 0";
  998. // create a background rectangle, which is required to show all other shapes
  999. var b = s.bgNode = r.ownerDocument.createElement("v:rect"), bs = b.style;
  1000. bs.left = bs.top = 0;
  1001. bs.width = rs.width;
  1002. bs.height = rs.height;
  1003. b.filled = b.stroked = "f";
  1004. r.appendChild(b);
  1005. c.appendChild(r);
  1006. p.appendChild(c);
  1007. s.width = g.normalizedLength(width); // in pixels
  1008. s.height = g.normalizedLength(height); // in pixels
  1009. return s; // dojox.gfx.Surface
  1010. };
  1011. // Extenders
  1012. // copied from dojox.gfx.utils
  1013. function forEach(object, f, o){
  1014. o = o || d.global;
  1015. f.call(o, object);
  1016. if(object instanceof g.Surface || object instanceof g.Group){
  1017. d.forEach(object.children, function(shape){
  1018. forEach(shape, f, o);
  1019. });
  1020. }
  1021. }
  1022. var addPatch9624 = function(shape){
  1023. if(this != shape.getParent()){
  1024. // cleanup from old parent
  1025. var oldParent = shape.getParent();
  1026. if(oldParent) { oldParent.remove(shape); }
  1027. // then move the raw node
  1028. this.rawNode.appendChild(shape.rawNode);
  1029. C.add.apply(this, arguments);
  1030. // reapply visual attributes (slow..)
  1031. forEach(this, function(s){
  1032. if (typeof(s.getFont) == 'function'){ // text shapes need to be completely refreshed
  1033. s.setShape(s.getShape());
  1034. s.setFont(s.getFont());
  1035. }
  1036. if (typeof(s.setFill) == 'function'){ // if setFill is available a setStroke should be safe to assume also
  1037. s.setFill(s.getFill());
  1038. s.setStroke(s.getStroke());
  1039. }
  1040. });
  1041. }
  1042. return this; // self
  1043. };
  1044. var add15 = function(shape){
  1045. if(this != shape.getParent()){
  1046. this.rawNode.appendChild(shape.rawNode);
  1047. if(!shape.getParent()){
  1048. // reapply visual attributes
  1049. shape.setFill(shape.getFill());
  1050. shape.setStroke(shape.getStroke());
  1051. }
  1052. C.add.apply(this, arguments);
  1053. }
  1054. return this; // self
  1055. };
  1056. var C = gs.Container, Container = {
  1057. // fix bug #12456/#9624. For 1.6.1 backward compat, flag must be set explicitly falsy to revert to 1.5 behavior.
  1058. add: dojo.config.fixVmlAdd === false ? add15 : addPatch9624,
  1059. remove: function(shape, silently){
  1060. // summary: remove a shape from a group/surface
  1061. // shape: dojox.gfx.Shape: an VML shape object
  1062. // silently: Boolean?: if true, regenerate a picture
  1063. if(this == shape.getParent()){
  1064. if(this.rawNode == shape.rawNode.parentNode){
  1065. this.rawNode.removeChild(shape.rawNode);
  1066. }
  1067. C.remove.apply(this, arguments);
  1068. }
  1069. return this; // self
  1070. },
  1071. clear: function(){
  1072. // summary: removes all shapes from a group/surface
  1073. var r = this.rawNode;
  1074. while(r.firstChild != r.lastChild){
  1075. if(r.firstChild != this.bgNode){
  1076. r.removeChild(r.firstChild);
  1077. }
  1078. if(r.lastChild != this.bgNode){
  1079. r.removeChild(r.lastChild);
  1080. }
  1081. }
  1082. return C.clear.apply(this, arguments);
  1083. },
  1084. _moveChildToFront: C._moveChildToFront,
  1085. _moveChildToBack: C._moveChildToBack
  1086. };
  1087. var Creator = {
  1088. // summary: VML shape creators
  1089. createGroup: function(){
  1090. // summary: creates a VML group shape
  1091. var node = this.createObject(vml.Group, null); // dojox.gfx.Group
  1092. // create a background rectangle, which is required to show all other shapes
  1093. var r = node.rawNode.ownerDocument.createElement("v:rect");
  1094. r.style.left = r.style.top = 0;
  1095. r.style.width = node.rawNode.style.width;
  1096. r.style.height = node.rawNode.style.height;
  1097. r.filled = r.stroked = "f";
  1098. node.rawNode.appendChild(r);
  1099. node.bgNode = r;
  1100. return node; // dojox.gfx.Group
  1101. },
  1102. createImage: function(image){
  1103. // summary: creates a VML image shape
  1104. // image: Object: an image object (see dojox.gfx.defaultImage)
  1105. if(!this.rawNode) return null;
  1106. var shape = new vml.Image(),
  1107. doc = this.rawNode.ownerDocument,
  1108. node = doc.createElement('v:rect');
  1109. node.stroked = "f";
  1110. node.style.width = this.rawNode.style.width;
  1111. node.style.height = this.rawNode.style.height;
  1112. var img = doc.createElement('v:imagedata');
  1113. node.appendChild(img);
  1114. shape.setRawNode(node);
  1115. this.rawNode.appendChild(node);
  1116. shape.setShape(image);
  1117. this.add(shape);
  1118. return shape; // dojox.gfx.Image
  1119. },
  1120. createRect: function(rect){
  1121. // summary: creates a rectangle shape
  1122. // rect: Object: a path object (see dojox.gfx.defaultRect)
  1123. if(!this.rawNode) return null;
  1124. var shape = new vml.Rect,
  1125. node = this.rawNode.ownerDocument.createElement("v:roundrect");
  1126. if(d.isIE > 7){
  1127. node.style.display = "inline-block";
  1128. }
  1129. shape.setRawNode(node);
  1130. this.rawNode.appendChild(node);
  1131. shape.setShape(rect);
  1132. this.add(shape);
  1133. return shape; // dojox.gfx.Rect
  1134. },
  1135. createObject: function(shapeType, rawShape) {
  1136. // summary: creates an instance of the passed shapeType class
  1137. // shapeType: Function: a class constructor to create an instance of
  1138. // rawShape: Object: properties to be passed in to the classes "setShape" method
  1139. // overrideSize: Boolean: set the size explicitly, if true
  1140. if(!this.rawNode) return null;
  1141. var shape = new shapeType(),
  1142. node = this.rawNode.ownerDocument.createElement('v:' + shapeType.nodeType);
  1143. shape.setRawNode(node);
  1144. this.rawNode.appendChild(node);
  1145. switch(shapeType){
  1146. case vml.Group:
  1147. case vml.Line:
  1148. case vml.Polyline:
  1149. case vml.Image:
  1150. case vml.Text:
  1151. case vml.Path:
  1152. case vml.TextPath:
  1153. this._overrideSize(node);
  1154. }
  1155. shape.setShape(rawShape);
  1156. this.add(shape);
  1157. return shape; // dojox.gfx.Shape
  1158. },
  1159. _overrideSize: function(node){
  1160. var s = this.rawNode.style, w = s.width, h = s.height;
  1161. node.style.width = w;
  1162. node.style.height = h;
  1163. node.coordsize = parseInt(w) + " " + parseInt(h);
  1164. }
  1165. };
  1166. d.extend(vml.Group, Container);
  1167. d.extend(vml.Group, gs.Creator);
  1168. d.extend(vml.Group, Creator);
  1169. d.extend(vml.Surface, Container);
  1170. d.extend(vml.Surface, gs.Creator);
  1171. d.extend(vml.Surface, Creator);
  1172. // see if we are required to initilize
  1173. if(g.loadAndSwitch === "vml"){
  1174. g.switchTo("vml");
  1175. delete g.loadAndSwitch;
  1176. }
  1177. })();
  1178. }