vml.js 40 KB

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