5fad100e516426980eef8d208c5cb7f5d10e54a9.svn-base 37 KB

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