svg.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. if (!dojo._hasResource["dojox.gfx.svg"]) { // _hasResource checks added by
  2. // build. Do not use _hasResource
  3. // directly in your code.
  4. dojo._hasResource["dojox.gfx.svg"] = true;
  5. dojo.provide("dojox.gfx.svg");
  6. dojo.require("dojox.gfx._base");
  7. dojo.require("dojox.gfx.shape");
  8. dojo.require("dojox.gfx.path");
  9. dojox.gfx.svg.xmlns = {
  10. xlink : "http://www.w3.org/1999/xlink",
  11. svg : "http://www.w3.org/2000/svg"
  12. };
  13. dojox.gfx.svg.getRef = function(name) {
  14. // summary: returns a DOM Node specified by the name argument or null
  15. // name: String: an SVG external reference
  16. if (!name || name == "none")
  17. return null;
  18. if (name.match(/^url\(#.+\)$/)) {
  19. return dojo.byId(name.slice(5, -1)); // Node
  20. }
  21. // alternative representation of a reference
  22. if (name.match(/^#dojoUnique\d+$/)) {
  23. // we assume here that a reference was generated by dojox.gfx
  24. return dojo.byId(name.slice(1)); // Node
  25. }
  26. return null; // Node
  27. };
  28. dojox.gfx.svg.dasharray = {
  29. solid : "none",
  30. shortdash : [4, 1],
  31. shortdot : [1, 1],
  32. shortdashdot : [4, 1, 1, 1],
  33. shortdashdotdot : [4, 1, 1, 1, 1, 1],
  34. dot : [1, 3],
  35. dash : [4, 3],
  36. longdash : [8, 3],
  37. dashdot : [4, 3, 1, 3],
  38. longdashdot : [8, 3, 1, 3],
  39. longdashdotdot : [8, 3, 1, 3, 1, 3]
  40. };
  41. dojo.extend(dojox.gfx.Shape, {
  42. // summary: SVG-specific implementation of dojox.gfx.Shape methods
  43. setFill : function(fill) {
  44. // summary: sets a fill object (SVG)
  45. // fill: Object: a fill object
  46. // (see dojox.gfx.defaultLinearGradient,
  47. // dojox.gfx.defaultRadialGradient,
  48. // dojox.gfx.defaultPattern,
  49. // or dojo.Color)
  50. if (!fill) {
  51. // don't fill
  52. this.fillStyle = null;
  53. this.rawNode.setAttribute("fill", "none");
  54. this.rawNode.setAttribute("fill-opacity", 0);
  55. return this;
  56. }
  57. var f;
  58. // FIXME: slightly magical. We're using the outer scope's "f", but
  59. // setting it later
  60. var setter = function(x) {
  61. // we assume that we're executing in the scope of the node to
  62. // mutate
  63. this.setAttribute(x, f[x].toFixed(8));
  64. };
  65. if (typeof(fill) == "object" && "type" in fill) {
  66. // gradient
  67. switch (fill.type) {
  68. case "linear" :
  69. f = dojox.gfx.makeParameters(
  70. dojox.gfx.defaultLinearGradient, fill);
  71. var gradient = this._setFillObject(f, "linearGradient");
  72. dojo
  73. .forEach(["x1", "y1", "x2", "y2"], setter,
  74. gradient);
  75. break;
  76. case "radial" :
  77. f = dojox.gfx.makeParameters(
  78. dojox.gfx.defaultRadialGradient, fill);
  79. var gradient = this._setFillObject(f, "radialGradient");
  80. dojo.forEach(["cx", "cy", "r"], setter, gradient);
  81. break;
  82. case "pattern" :
  83. f = dojox.gfx.makeParameters(dojox.gfx.defaultPattern,
  84. fill);
  85. var pattern = this._setFillObject(f, "pattern");
  86. dojo.forEach(["x", "y", "width", "height"], setter,
  87. pattern);
  88. break;
  89. }
  90. this.fillStyle = f;
  91. return this;
  92. }
  93. // color object
  94. var f = dojox.gfx.normalizeColor(fill);
  95. this.fillStyle = f;
  96. this.rawNode.setAttribute("fill", f.toCss());
  97. this.rawNode.setAttribute("fill-opacity", f.a);
  98. this.rawNode.setAttribute("fill-rule", "evenodd");
  99. return this; // self
  100. },
  101. setStroke : function(stroke) {
  102. // summary: sets a stroke object (SVG)
  103. // stroke: Object: a stroke object
  104. // (see dojox.gfx.defaultStroke)
  105. if (!stroke) {
  106. // don't stroke
  107. this.strokeStyle = null;
  108. this.rawNode.setAttribute("stroke", "none");
  109. this.rawNode.setAttribute("stroke-opacity", 0);
  110. return this;
  111. }
  112. // normalize the stroke
  113. if (typeof stroke == "string") {
  114. stroke = {
  115. color : stroke
  116. };
  117. }
  118. var s = this.strokeStyle = dojox.gfx.makeParameters(
  119. dojox.gfx.defaultStroke, stroke);
  120. s.color = dojox.gfx.normalizeColor(s.color);
  121. // generate attributes
  122. var rn = this.rawNode;
  123. if (s) {
  124. rn.setAttribute("stroke", s.color.toCss());
  125. rn.setAttribute("stroke-opacity", s.color.a);
  126. rn.setAttribute("stroke-width", s.width);
  127. rn.setAttribute("stroke-linecap", s.cap);
  128. if (typeof s.join == "number") {
  129. rn.setAttribute("stroke-linejoin", "miter");
  130. rn.setAttribute("stroke-miterlimit", s.join);
  131. } else {
  132. rn.setAttribute("stroke-linejoin", s.join);
  133. }
  134. var da = s.style.toLowerCase();
  135. if (da in dojox.gfx.svg.dasharray) {
  136. da = dojox.gfx.svg.dasharray[da];
  137. }
  138. if (da instanceof Array) {
  139. da = dojo.clone(da);
  140. for (var i = 0; i < da.length; ++i) {
  141. da[i] *= s.width;
  142. }
  143. if (s.cap != "butt") {
  144. for (var i = 0; i < da.length; i += 2) {
  145. da[i] -= s.width;
  146. if (da[i] < 1) {
  147. da[i] = 1;
  148. }
  149. }
  150. for (var i = 1; i < da.length; i += 2) {
  151. da[i] += s.width;
  152. }
  153. }
  154. da = da.join(",");
  155. }
  156. rn.setAttribute("stroke-dasharray", da);
  157. rn.setAttribute("dojoGfxStrokeStyle", s.style);
  158. }
  159. return this; // self
  160. },
  161. _getParentSurface : function() {
  162. var surface = this.parent;
  163. for (; surface && !(surface instanceof dojox.gfx.Surface); surface = surface.parent);
  164. return surface;
  165. },
  166. _setFillObject : function(f, nodeType) {
  167. var svgns = dojox.gfx.svg.xmlns.svg;
  168. this.fillStyle = f;
  169. var surface = this._getParentSurface();
  170. var defs = surface.defNode;
  171. var fill = this.rawNode.getAttribute("fill");
  172. var ref = dojox.gfx.svg.getRef(fill);
  173. if (ref) {
  174. fill = ref;
  175. if (fill.tagName.toLowerCase() != nodeType.toLowerCase()) {
  176. var id = fill.id;
  177. fill.parentNode.removeChild(fill);
  178. fill = document.createElementNS(svgns, nodeType);
  179. fill.setAttribute("id", id);
  180. defs.appendChild(fill);
  181. } else {
  182. while (fill.childNodes.length) {
  183. fill.removeChild(fill.lastChild);
  184. }
  185. }
  186. } else {
  187. fill = document.createElementNS(svgns, nodeType);
  188. fill.setAttribute("id", dojox.gfx._base._getUniqueId());
  189. defs.appendChild(fill);
  190. }
  191. if (nodeType == "pattern") {
  192. if (dojo.isSafari) {
  193. fill.setAttributeNS(null, "patternUnits", "userSpaceOnUse");
  194. } else {
  195. fill.setAttribute("patternUnits", "userSpaceOnUse");
  196. }
  197. var img = document.createElementNS(svgns, "image");
  198. img.setAttribute("x", 0);
  199. img.setAttribute("y", 0);
  200. img.setAttribute("width", f.width.toFixed(8));
  201. img.setAttribute("height", f.height.toFixed(8));
  202. img.setAttributeNS(dojox.gfx.svg.xmlns.xlink, "href", f.src);
  203. fill.appendChild(img);
  204. } else {
  205. if (dojo.isSafari) {
  206. fill
  207. .setAttributeNS(null, "gradientUnits",
  208. "userSpaceOnUse");
  209. } else {
  210. fill.setAttribute("gradientUnits", "userSpaceOnUse");
  211. }
  212. for (var i = 0; i < f.colors.length; ++i) {
  213. var c = f.colors[i], t = document.createElementNS(svgns,
  214. "stop"), cc = c.color = dojox.gfx
  215. .normalizeColor(c.color);
  216. t.setAttribute("offset", c.offset.toFixed(8));
  217. t.setAttribute("stop-color", cc.toCss());
  218. t.setAttribute("stop-opacity", cc.a);
  219. fill.appendChild(t);
  220. }
  221. }
  222. this.rawNode.setAttribute("fill", "url(#" + fill.getAttribute("id")
  223. + ")");
  224. this.rawNode.removeAttribute("fill-opacity");
  225. this.rawNode.setAttribute("fill-rule", "evenodd");
  226. return fill;
  227. },
  228. _applyTransform : function() {
  229. var matrix = this.matrix;
  230. if (matrix) {
  231. var tm = this.matrix;
  232. this.rawNode.setAttribute("transform", "matrix("
  233. + tm.xx.toFixed(8) + "," + tm.yx.toFixed(8)
  234. + "," + tm.xy.toFixed(8) + ","
  235. + tm.yy.toFixed(8) + "," + tm.dx.toFixed(8)
  236. + "," + tm.dy.toFixed(8) + ")");
  237. } else {
  238. this.rawNode.removeAttribute("transform");
  239. }
  240. return this;
  241. },
  242. setRawNode : function(rawNode) {
  243. // summary:
  244. // assigns and clears the underlying node that will represent this
  245. // shape. Once set, transforms, gradients, etc, can be applied.
  246. // (no fill & stroke by default)
  247. var r = this.rawNode = rawNode;
  248. r.setAttribute("fill", "none");
  249. r.setAttribute("fill-opacity", 0);
  250. r.setAttribute("stroke", "none");
  251. r.setAttribute("stroke-opacity", 0);
  252. r.setAttribute("stroke-width", 1);
  253. r.setAttribute("stroke-linecap", "butt");
  254. r.setAttribute("stroke-linejoin", "miter");
  255. r.setAttribute("stroke-miterlimit", 4);
  256. },
  257. setShape : function(newShape) {
  258. // summary: sets a shape object (SVG)
  259. // newShape: Object: a shape object
  260. // (see dojox.gfx.defaultPath,
  261. // dojox.gfx.defaultPolyline,
  262. // dojox.gfx.defaultRect,
  263. // dojox.gfx.defaultEllipse,
  264. // dojox.gfx.defaultCircle,
  265. // dojox.gfx.defaultLine,
  266. // or dojox.gfx.defaultImage)
  267. this.shape = dojox.gfx.makeParameters(this.shape, newShape);
  268. for (var i in this.shape) {
  269. if (i != "type") {
  270. this.rawNode.setAttribute(i, this.shape[i]);
  271. }
  272. }
  273. return this; // self
  274. },
  275. // move family
  276. _moveToFront : function() {
  277. // summary: moves a shape to front of its parent's list of shapes
  278. // (SVG)
  279. this.rawNode.parentNode.appendChild(this.rawNode);
  280. return this; // self
  281. },
  282. _moveToBack : function() {
  283. // summary: moves a shape to back of its parent's list of shapes
  284. // (SVG)
  285. this.rawNode.parentNode.insertBefore(this.rawNode,
  286. this.rawNode.parentNode.firstChild);
  287. return this; // self
  288. }
  289. });
  290. dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, {
  291. // summary: a group shape (SVG), which can be used
  292. // to logically group shapes (e.g, to propagate matricies)
  293. constructor : function() {
  294. dojox.gfx.svg.Container._init.call(this);
  295. },
  296. setRawNode : function(rawNode) {
  297. // summary: sets a raw SVG node to be used by this shape
  298. // rawNode: Node: an SVG node
  299. this.rawNode = rawNode;
  300. }
  301. });
  302. dojox.gfx.Group.nodeType = "g";
  303. dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, {
  304. // summary: a rectangle shape (SVG)
  305. setShape : function(newShape) {
  306. // summary: sets a rectangle shape object (SVG)
  307. // newShape: Object: a rectangle shape object
  308. this.shape = dojox.gfx.makeParameters(this.shape, newShape);
  309. this.bbox = null;
  310. for (var i in this.shape) {
  311. if (i != "type" && i != "r") {
  312. this.rawNode.setAttribute(i, this.shape[i]);
  313. }
  314. }
  315. if (this.shape.r) {
  316. this.rawNode.setAttribute("ry", this.shape.r);
  317. this.rawNode.setAttribute("rx", this.shape.r);
  318. }
  319. return this; // self
  320. }
  321. });
  322. dojox.gfx.Rect.nodeType = "rect";
  323. dojox.gfx.Ellipse = dojox.gfx.shape.Ellipse;
  324. dojox.gfx.Ellipse.nodeType = "ellipse";
  325. dojox.gfx.Circle = dojox.gfx.shape.Circle;
  326. dojox.gfx.Circle.nodeType = "circle";
  327. dojox.gfx.Line = dojox.gfx.shape.Line;
  328. dojox.gfx.Line.nodeType = "line";
  329. dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline, {
  330. // summary: a polyline/polygon shape (SVG)
  331. setShape : function(points, closed) {
  332. // summary: sets a polyline/polygon shape object (SVG)
  333. // points: Object: a polyline/polygon shape object
  334. if (points && points instanceof Array) {
  335. // branch
  336. // points: Array: an array of points
  337. this.shape = dojox.gfx.makeParameters(this.shape, {
  338. points : points
  339. });
  340. if (closed && this.shape.points.length) {
  341. this.shape.points.push(this.shape.points[0]);
  342. }
  343. } else {
  344. this.shape = dojox.gfx.makeParameters(this.shape,
  345. points);
  346. }
  347. this.box = null;
  348. var attr = [];
  349. var p = this.shape.points;
  350. for (var i = 0; i < p.length; ++i) {
  351. if (typeof p[i] == "number") {
  352. attr.push(p[i].toFixed(8));
  353. } else {
  354. attr.push(p[i].x.toFixed(8));
  355. attr.push(p[i].y.toFixed(8));
  356. }
  357. }
  358. this.rawNode.setAttribute("points", attr.join(" "));
  359. return this; // self
  360. }
  361. });
  362. dojox.gfx.Polyline.nodeType = "polyline";
  363. dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, {
  364. // summary: an image (SVG)
  365. setShape : function(newShape) {
  366. // summary: sets an image shape object (SVG)
  367. // newShape: Object: an image shape object
  368. this.shape = dojox.gfx.makeParameters(this.shape, newShape);
  369. this.bbox = null;
  370. var rawNode = this.rawNode;
  371. for (var i in this.shape) {
  372. if (i != "type" && i != "src") {
  373. rawNode.setAttribute(i, this.shape[i]);
  374. }
  375. }
  376. rawNode.setAttributeNS(dojox.gfx.svg.xmlns.xlink, "href",
  377. this.shape.src);
  378. return this; // self
  379. }
  380. });
  381. dojox.gfx.Image.nodeType = "image";
  382. dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, {
  383. // summary: an anchored text (SVG)
  384. setShape : function(newShape) {
  385. // summary: sets a text shape object (SVG)
  386. // newShape: Object: a text shape object
  387. this.shape = dojox.gfx.makeParameters(this.shape, newShape);
  388. this.bbox = null;
  389. var r = this.rawNode;
  390. var s = this.shape;
  391. r.setAttribute("x", s.x);
  392. r.setAttribute("y", s.y);
  393. r.setAttribute("text-anchor", s.align);
  394. r.setAttribute("text-decoration", s.decoration);
  395. r.setAttribute("rotate", s.rotated ? 90 : 0);
  396. r.setAttribute("kerning", s.kerning ? "auto" : 0);
  397. r.setAttribute("text-rendering", "optimizeLegibility");
  398. r.textContent = s.text;
  399. return this; // self
  400. },
  401. getTextWidth : function() {
  402. // summary: get the text width in pixels
  403. var rawNode = this.rawNode;
  404. var oldParent = rawNode.parentNode;
  405. var _measurementNode = rawNode.cloneNode(true);
  406. _measurementNode.style.visibility = "hidden";
  407. // solution to the "orphan issue" in FF
  408. var _width = 0;
  409. var _text = _measurementNode.firstChild.nodeValue;
  410. oldParent.appendChild(_measurementNode);
  411. // solution to the "orphan issue" in Opera
  412. // (nodeValue == "" hangs firefox)
  413. if (_text != "") {
  414. while (!_width) {
  415. _width = parseInt(_measurementNode.getBBox().width);
  416. }
  417. }
  418. oldParent.removeChild(_measurementNode);
  419. return _width;
  420. }
  421. });
  422. dojox.gfx.Text.nodeType = "text";
  423. dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, {
  424. // summary: a path shape (SVG)
  425. _updateWithSegment : function(segment) {
  426. // summary: updates the bounding box of path with new segment
  427. // segment: Object: a segment
  428. dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
  429. if (typeof(this.shape.path) == "string") {
  430. this.rawNode.setAttribute("d", this.shape.path);
  431. }
  432. },
  433. setShape : function(newShape) {
  434. // summary: forms a path using a shape (SVG)
  435. // newShape: Object: an SVG path string or a path object (see
  436. // dojox.gfx.defaultPath)
  437. dojox.gfx.Path.superclass.setShape.apply(this, arguments);
  438. this.rawNode.setAttribute("d", this.shape.path);
  439. return this; // self
  440. }
  441. });
  442. dojox.gfx.Path.nodeType = "path";
  443. dojo.declare("dojox.gfx.TextPath", dojox.gfx.path.TextPath, {
  444. // summary: a textpath shape (SVG)
  445. _updateWithSegment : function(segment) {
  446. // summary: updates the bounding box of path with new segment
  447. // segment: Object: a segment
  448. dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
  449. this._setTextPath();
  450. },
  451. setShape : function(newShape) {
  452. // summary: forms a path using a shape (SVG)
  453. // newShape: Object: an SVG path string or a path object (see
  454. // dojox.gfx.defaultPath)
  455. dojox.gfx.Path.superclass.setShape.apply(this, arguments);
  456. this._setTextPath();
  457. return this; // self
  458. },
  459. _setTextPath : function() {
  460. if (typeof this.shape.path != "string") {
  461. return;
  462. }
  463. var r = this.rawNode;
  464. if (!r.firstChild) {
  465. var tp = document.createElementNS(dojox.gfx.svg.xmlns.svg,
  466. "textPath");
  467. var tx = document.createTextNode("");
  468. tp.appendChild(tx);
  469. r.appendChild(tp);
  470. }
  471. var ref = r.firstChild.getAttributeNS(dojox.gfx.svg.xmlns.xlink,
  472. "href");
  473. var path = ref && dojox.gfx.svg.getRef(ref);
  474. if (!path) {
  475. var surface = this._getParentSurface();
  476. if (surface) {
  477. var defs = surface.defNode;
  478. path = document.createElementNS(dojox.gfx.svg.xmlns.svg,
  479. "path");
  480. var id = dojox.gfx._base._getUniqueId();
  481. path.setAttribute("id", id);
  482. defs.appendChild(path);
  483. r.firstChild.setAttributeNS(dojox.gfx.svg.xmlns.xlink,
  484. "href", "#" + id);
  485. }
  486. }
  487. if (path) {
  488. path.setAttribute("d", this.shape.path);
  489. }
  490. },
  491. _setText : function() {
  492. var r = this.rawNode;
  493. if (!r.firstChild) {
  494. var tp = document.createElementNS(dojox.gfx.svg.xmlns.svg,
  495. "textPath");
  496. var tx = document.createTextNode("");
  497. tp.appendChild(tx);
  498. r.appendChild(tp);
  499. }
  500. r = r.firstChild;
  501. var t = this.text;
  502. r.setAttribute("alignment-baseline", "middle");
  503. switch (t.align) {
  504. case "middle" :
  505. r.setAttribute("text-anchor", "middle");
  506. r.setAttribute("startOffset", "50%");
  507. break;
  508. case "end" :
  509. r.setAttribute("text-anchor", "end");
  510. r.setAttribute("startOffset", "100%");
  511. break;
  512. default :
  513. r.setAttribute("text-anchor", "start");
  514. r.setAttribute("startOffset", "0%");
  515. break;
  516. }
  517. // r.parentNode.setAttribute("alignment-baseline", "central");
  518. // r.setAttribute("dominant-baseline", "central");
  519. r.setAttribute("baseline-shift", "0.5ex");
  520. r.setAttribute("text-decoration", t.decoration);
  521. r.setAttribute("rotate", t.rotated ? 90 : 0);
  522. r.setAttribute("kerning", t.kerning ? "auto" : 0);
  523. r.firstChild.data = t.text;
  524. }
  525. });
  526. dojox.gfx.TextPath.nodeType = "text";
  527. dojo.declare("dojox.gfx.Surface", dojox.gfx.shape.Surface, {
  528. // summary: a surface object to be used for drawings (SVG)
  529. constructor : function() {
  530. dojox.gfx.svg.Container._init.call(this);
  531. },
  532. setDimensions : function(width, height) {
  533. // summary: sets the width and height of the rawNode
  534. // width: String: width of surface, e.g., "100px"
  535. // height: String: height of surface, e.g., "100px"
  536. if (!this.rawNode) {
  537. return this;
  538. }
  539. this.rawNode.setAttribute("width", width);
  540. this.rawNode.setAttribute("height", height);
  541. return this; // self
  542. },
  543. getDimensions : function() {
  544. // summary: returns an object with properties "width" and
  545. // "height"
  546. return this.rawNode ? {
  547. width : this.rawNode.getAttribute("width"),
  548. height : this.rawNode.getAttribute("height")
  549. } : null; // Object
  550. }
  551. });
  552. dojox.gfx.createSurface = function(parentNode, width, height) {
  553. // summary: creates a surface (SVG)
  554. // parentNode: Node: a parent node
  555. // width: String: width of surface, e.g., "100px"
  556. // height: String: height of surface, e.g., "100px"
  557. var s = new dojox.gfx.Surface();
  558. s.rawNode = document.createElementNS(dojox.gfx.svg.xmlns.svg, "svg");
  559. s.rawNode.setAttribute("width", width);
  560. s.rawNode.setAttribute("height", height);
  561. var node = document.createElementNS(dojox.gfx.svg.xmlns.svg, "defs");
  562. s.rawNode.appendChild(node);
  563. s.defNode = node;
  564. dojo.byId(parentNode).appendChild(s.rawNode);
  565. return s; // dojox.gfx.Surface
  566. };
  567. // Extenders
  568. dojox.gfx.svg.Font = {
  569. _setFont : function() {
  570. // summary: sets a font object (SVG)
  571. var f = this.fontStyle;
  572. // next line doesn't work in Firefox 2 or Opera 9
  573. // this.rawNode.setAttribute("font",
  574. // dojox.gfx.makeFontString(this.fontStyle));
  575. this.rawNode.setAttribute("font-style", f.style);
  576. this.rawNode.setAttribute("font-variant", f.variant);
  577. this.rawNode.setAttribute("font-weight", f.weight);
  578. this.rawNode.setAttribute("font-size", f.size);
  579. this.rawNode.setAttribute("font-family", f.family);
  580. }
  581. };
  582. dojox.gfx.svg.Container = {
  583. _init : function() {
  584. dojox.gfx.shape.Container._init.call(this);
  585. },
  586. add : function(shape) {
  587. // summary: adds a shape to a group/surface
  588. // shape: dojox.gfx.Shape: an VML shape object
  589. if (this != shape.getParent()) {
  590. this.rawNode.appendChild(shape.rawNode);
  591. // dojox.gfx.Group.superclass.add.apply(this, arguments);
  592. // this.inherited(arguments);
  593. dojox.gfx.shape.Container.add.apply(this, arguments);
  594. }
  595. return this; // self
  596. },
  597. remove : function(shape, silently) {
  598. // summary: remove a shape from a group/surface
  599. // shape: dojox.gfx.Shape: an VML shape object
  600. // silently: Boolean?: if true, regenerate a picture
  601. if (this == shape.getParent()) {
  602. if (this.rawNode == shape.rawNode.parentNode) {
  603. this.rawNode.removeChild(shape.rawNode);
  604. }
  605. // dojox.gfx.Group.superclass.remove.apply(this, arguments);
  606. // this.inherited(arguments);
  607. dojox.gfx.shape.Container.remove.apply(this, arguments);
  608. }
  609. return this; // self
  610. },
  611. clear : function() {
  612. // summary: removes all shapes from a group/surface
  613. var r = this.rawNode;
  614. while (r.lastChild) {
  615. r.removeChild(r.lastChild);
  616. }
  617. // return this.inherited(arguments); // self
  618. return dojox.gfx.shape.Container.clear.apply(this, arguments);
  619. },
  620. _moveChildToFront : dojox.gfx.shape.Container._moveChildToFront,
  621. _moveChildToBack : dojox.gfx.shape.Container._moveChildToBack
  622. };
  623. dojo.mixin(dojox.gfx.shape.Creator, {
  624. // summary: SVG shape creators
  625. createObject : function(shapeType, rawShape) {
  626. // summary: creates an instance of the passed shapeType
  627. // class
  628. // shapeType: Function: a class constructor to create an
  629. // instance of
  630. // rawShape: Object: properties to be passed in to the
  631. // classes "setShape" method
  632. if (!this.rawNode) {
  633. return null;
  634. }
  635. var shape = new shapeType();
  636. var node = document.createElementNS(
  637. dojox.gfx.svg.xmlns.svg, shapeType.nodeType);
  638. shape.setRawNode(node);
  639. this.rawNode.appendChild(node);
  640. shape.setShape(rawShape);
  641. this.add(shape);
  642. return shape; // dojox.gfx.Shape
  643. }
  644. });
  645. dojo.extend(dojox.gfx.Text, dojox.gfx.svg.Font);
  646. dojo.extend(dojox.gfx.TextPath, dojox.gfx.svg.Font);
  647. dojo.extend(dojox.gfx.Group, dojox.gfx.svg.Container);
  648. dojo.extend(dojox.gfx.Group, dojox.gfx.shape.Creator);
  649. dojo.extend(dojox.gfx.Surface, dojox.gfx.svg.Container);
  650. dojo.extend(dojox.gfx.Surface, dojox.gfx.shape.Creator);
  651. }