API Docs for: 3.17.2
Show:

File: graphics/js/CanvasGraphic.js

  1. /**
  2. * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> implementation of the `Graphic` class.
  3. * `CanvasGraphic` is not intended to be used directly. Instead, use the <a href="Graphic.html">`Graphic`</a> class.
  4. * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities but has
  5. * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> capabilities, the <a href="Graphic.html">`Graphic`</a>
  6. * class will point to the `CanvasGraphic` class.
  7. *
  8. * @module graphics
  9. * @class CanvasGraphic
  10. * @constructor
  11. */
  12. function CanvasGraphic() {
  13.  
  14. CanvasGraphic.superclass.constructor.apply(this, arguments);
  15. }
  16.  
  17. CanvasGraphic.NAME = "canvasGraphic";
  18.  
  19. CanvasGraphic.ATTRS = {
  20. /**
  21. * Whether or not to render the `Graphic` automatically after to a specified parent node after init. This can be a Node
  22. * instance or a CSS selector string.
  23. *
  24. * @config render
  25. * @type Node | String
  26. */
  27. render: {},
  28.  
  29. /**
  30. * Unique id for class instance.
  31. *
  32. * @config id
  33. * @type String
  34. */
  35. id: {
  36. valueFn: function()
  37. {
  38. return Y.guid();
  39. },
  40.  
  41. setter: function(val)
  42. {
  43. var node = this._node;
  44. if(node)
  45. {
  46. node.setAttribute("id", val);
  47. }
  48. return val;
  49. }
  50. },
  51.  
  52. /**
  53. * Key value pairs in which a shape instance is associated with its id.
  54. *
  55. * @config shapes
  56. * @type Object
  57. * @readOnly
  58. */
  59. shapes: {
  60. readOnly: true,
  61.  
  62. getter: function()
  63. {
  64. return this._shapes;
  65. }
  66. },
  67.  
  68. /**
  69. * Object containing size and coordinate data for the content of a Graphic in relation to the graphic instance's position.
  70. *
  71. * @config contentBounds
  72. * @type Object
  73. * @readOnly
  74. */
  75. contentBounds: {
  76. readOnly: true,
  77.  
  78. getter: function()
  79. {
  80. return this._contentBounds;
  81. }
  82. },
  83.  
  84. /**
  85. * The outermost html element of the Graphic instance.
  86. *
  87. * @config node
  88. * @type HTMLElement
  89. * @readOnly
  90. */
  91. node: {
  92. readOnly: true,
  93.  
  94. getter: function()
  95. {
  96. return this._node;
  97. }
  98. },
  99.  
  100. /**
  101. * Indicates the width of the `Graphic`.
  102. *
  103. * @config width
  104. * @type Number
  105. */
  106. width: {
  107. setter: function(val)
  108. {
  109. if(this._node)
  110. {
  111. this._node.style.width = val + "px";
  112. }
  113. return val;
  114. }
  115. },
  116.  
  117. /**
  118. * Indicates the height of the `Graphic`.
  119. *
  120. * @config height
  121. * @type Number
  122. */
  123. height: {
  124. setter: function(val)
  125. {
  126. if(this._node)
  127. {
  128. this._node.style.height = val + "px";
  129. }
  130. return val;
  131. }
  132. },
  133.  
  134. /**
  135. * Determines the sizing of the Graphic.
  136. *
  137. * <dl>
  138. * <dt>sizeContentToGraphic</dt><dd>The Graphic's width and height attributes are, either explicitly set through the
  139. * <code>width</code> and <code>height</code> attributes or are determined by the dimensions of the parent element. The
  140. * content contained in the Graphic will be sized to fit with in the Graphic instance's dimensions. When using this
  141. * setting, the <code>preserveAspectRatio</code> attribute will determine how the contents are sized.</dd>
  142. * <dt>sizeGraphicToContent</dt><dd>(Also accepts a value of true) The Graphic's width and height are determined by the
  143. * size and positioning of the content.</dd>
  144. * <dt>false</dt><dd>The Graphic's width and height attributes are, either explicitly set through the <code>width</code>
  145. * and <code>height</code> attributes or are determined by the dimensions of the parent element. The contents of the
  146. * Graphic instance are not affected by this setting.</dd>
  147. * </dl>
  148. *
  149. *
  150. * @config autoSize
  151. * @type Boolean | String
  152. * @default false
  153. */
  154. autoSize: {
  155. value: false
  156. },
  157.  
  158. /**
  159. * Determines how content is sized when <code>autoSize</code> is set to <code>sizeContentToGraphic</code>.
  160. *
  161. * <dl>
  162. * <dt>none<dt><dd>Do not force uniform scaling. Scale the graphic content of the given element non-uniformly if necessary
  163. * such that the element's bounding box exactly matches the viewport rectangle.</dd>
  164. * <dt>xMinYMin</dt><dd>Force uniform scaling position along the top left of the Graphic's node.</dd>
  165. * <dt>xMidYMin</dt><dd>Force uniform scaling horizontally centered and positioned at the top of the Graphic's node.<dd>
  166. * <dt>xMaxYMin</dt><dd>Force uniform scaling positioned horizontally from the right and vertically from the top.</dd>
  167. * <dt>xMinYMid</dt>Force uniform scaling positioned horizontally from the left and vertically centered.</dd>
  168. * <dt>xMidYMid (the default)</dt><dd>Force uniform scaling with the content centered.</dd>
  169. * <dt>xMaxYMid</dt><dd>Force uniform scaling positioned horizontally from the right and vertically centered.</dd>
  170. * <dt>xMinYMax</dt><dd>Force uniform scaling positioned horizontally from the left and vertically from the bottom.</dd>
  171. * <dt>xMidYMax</dt><dd>Force uniform scaling horizontally centered and position vertically from the bottom.</dd>
  172. * <dt>xMaxYMax</dt><dd>Force uniform scaling positioned horizontally from the right and vertically from the bottom.</dd>
  173. * </dl>
  174. *
  175. * @config preserveAspectRatio
  176. * @type String
  177. * @default xMidYMid
  178. */
  179. preserveAspectRatio: {
  180. value: "xMidYMid"
  181. },
  182.  
  183. /**
  184. * The contentBounds will resize to greater values but not smaller values. (for performance)
  185. * When resizing the contentBounds down is desirable, set the resizeDown value to true.
  186. *
  187. * @config resizeDown
  188. * @type Boolean
  189. */
  190. resizeDown: {
  191. value: false
  192. },
  193.  
  194. /**
  195. * Indicates the x-coordinate for the instance.
  196. *
  197. * @config x
  198. * @type Number
  199. */
  200. x: {
  201. getter: function()
  202. {
  203. return this._x;
  204. },
  205.  
  206. setter: function(val)
  207. {
  208. this._x = val;
  209. if(this._node)
  210. {
  211. this._node.style.left = val + "px";
  212. }
  213. return val;
  214. }
  215. },
  216.  
  217. /**
  218. * Indicates the y-coordinate for the instance.
  219. *
  220. * @config y
  221. * @type Number
  222. */
  223. y: {
  224. getter: function()
  225. {
  226. return this._y;
  227. },
  228.  
  229. setter: function(val)
  230. {
  231. this._y = val;
  232. if(this._node)
  233. {
  234. this._node.style.top = val + "px";
  235. }
  236. return val;
  237. }
  238. },
  239.  
  240. /**
  241. * Indicates whether or not the instance will automatically redraw after a change is made to a shape.
  242. * This property will get set to false when batching operations.
  243. *
  244. * @config autoDraw
  245. * @type Boolean
  246. * @default true
  247. * @private
  248. */
  249. autoDraw: {
  250. value: true
  251. },
  252.  
  253. /**
  254. * Indicates whether the `Graphic` and its children are visible.
  255. *
  256. * @config visible
  257. * @type Boolean
  258. */
  259. visible: {
  260. value: true,
  261.  
  262. setter: function(val)
  263. {
  264. this._toggleVisible(val);
  265. return val;
  266. }
  267. }
  268. };
  269.  
  270. Y.extend(CanvasGraphic, Y.GraphicBase, {
  271. /**
  272. * Sets the value of an attribute.
  273. *
  274. * @method set
  275. * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can
  276. * be passed in to set multiple attributes at once.
  277. * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as
  278. * the name param.
  279. */
  280. set: function()
  281. {
  282. var host = this,
  283. attr = arguments[0],
  284. redrawAttrs = {
  285. autoDraw: true,
  286. autoSize: true,
  287. preserveAspectRatio: true,
  288. resizeDown: true
  289. },
  290. key,
  291. forceRedraw = false;
  292. AttributeLite.prototype.set.apply(host, arguments);
  293. if(host._state.autoDraw === true && Y.Object.size(this._shapes) > 0)
  294. {
  295. if(Y_LANG.isString && redrawAttrs[attr])
  296. {
  297. forceRedraw = true;
  298. }
  299. else if(Y_LANG.isObject(attr))
  300. {
  301. for(key in redrawAttrs)
  302. {
  303. if(redrawAttrs.hasOwnProperty(key) && attr[key])
  304. {
  305. forceRedraw = true;
  306. break;
  307. }
  308. }
  309. }
  310. }
  311. if(forceRedraw)
  312. {
  313. host._redraw();
  314. }
  315. },
  316.  
  317. /**
  318. * Storage for `x` attribute.
  319. *
  320. * @property _x
  321. * @type Number
  322. * @private
  323. */
  324. _x: 0,
  325.  
  326. /**
  327. * Storage for `y` attribute.
  328. *
  329. * @property _y
  330. * @type Number
  331. * @private
  332. */
  333. _y: 0,
  334.  
  335. /**
  336. * Gets the current position of the graphic instance in page coordinates.
  337. *
  338. * @method getXY
  339. * @return Array The XY position of the shape.
  340. */
  341. getXY: function()
  342. {
  343. var node = this._node,
  344. xy;
  345. if(node)
  346. {
  347. xy = Y.DOM.getXY(node);
  348. }
  349. return xy;
  350. },
  351.  
  352. /**
  353. * Initializes the class.
  354. *
  355. * @method initializer
  356. * @param {Object} config Optional attributes
  357. * @private
  358. */
  359. initializer: function() {
  360. var render = this.get("render"),
  361. visibility = this.get("visible") ? "visible" : "hidden",
  362. w = this.get("width") || 0,
  363. h = this.get("height") || 0;
  364. this._shapes = {};
  365. this._redrawQueue = {};
  366. this._contentBounds = {
  367. left: 0,
  368. top: 0,
  369. right: 0,
  370. bottom: 0
  371. };
  372. this._node = DOCUMENT.createElement('div');
  373. this._node.style.position = "absolute";
  374. this._node.style.visibility = visibility;
  375. this.set("width", w);
  376. this.set("height", h);
  377. if(render)
  378. {
  379. this.render(render);
  380. }
  381. },
  382.  
  383. /**
  384. * Adds the graphics node to the dom.
  385. *
  386. * @method render
  387. * @param {HTMLElement} parentNode node in which to render the graphics node into.
  388. */
  389. render: function(render) {
  390. var parentNode = render || DOCUMENT.body,
  391. node = this._node,
  392. w,
  393. h;
  394. if(render instanceof Y.Node)
  395. {
  396. parentNode = render._node;
  397. }
  398. else if(Y.Lang.isString(render))
  399. {
  400. parentNode = Y.Selector.query(render, DOCUMENT.body, true);
  401. }
  402. w = this.get("width") || parseInt(Y.DOM.getComputedStyle(parentNode, "width"), 10);
  403. h = this.get("height") || parseInt(Y.DOM.getComputedStyle(parentNode, "height"), 10);
  404. parentNode.appendChild(node);
  405. node.style.display = "block";
  406. node.style.position = "absolute";
  407. node.style.left = this.get("x") + "px";
  408. node.style.top = this.get("y") + "px";
  409. this.set("width", w);
  410. this.set("height", h);
  411. this.parentNode = parentNode;
  412. return this;
  413. },
  414.  
  415. /**
  416. * Removes all nodes.
  417. *
  418. * @method destroy
  419. */
  420. destroy: function()
  421. {
  422. this.removeAllShapes();
  423. if(this._node)
  424. {
  425. this._removeChildren(this._node);
  426. if(this._node.parentNode)
  427. {
  428. this._node.parentNode.removeChild(this._node);
  429. }
  430. this._node = null;
  431. }
  432. },
  433.  
  434. /**
  435. * Generates a shape instance by type.
  436. *
  437. * @method addShape
  438. * @param {Object} cfg attributes for the shape
  439. * @return Shape
  440. */
  441. addShape: function(cfg)
  442. {
  443. cfg.graphic = this;
  444. if(!this.get("visible"))
  445. {
  446. cfg.visible = false;
  447. }
  448. var ShapeClass = this._getShapeClass(cfg.type),
  449. shape = new ShapeClass(cfg);
  450. this._appendShape(shape);
  451. return shape;
  452. },
  453.  
  454. /**
  455. * Adds a shape instance to the graphic instance.
  456. *
  457. * @method _appendShape
  458. * @param {Shape} shape The shape instance to be added to the graphic.
  459. * @private
  460. */
  461. _appendShape: function(shape)
  462. {
  463. var node = shape.node,
  464. parentNode = this._frag || this._node;
  465. if(this.get("autoDraw"))
  466. {
  467. parentNode.appendChild(node);
  468. }
  469. else
  470. {
  471. this._getDocFrag().appendChild(node);
  472. }
  473. },
  474.  
  475. /**
  476. * Removes a shape instance from from the graphic instance.
  477. *
  478. * @method removeShape
  479. * @param {Shape|String} shape The instance or id of the shape to be removed.
  480. */
  481. removeShape: function(shape)
  482. {
  483. if(!(shape instanceof CanvasShape))
  484. {
  485. if(Y_LANG.isString(shape))
  486. {
  487. shape = this._shapes[shape];
  488. }
  489. }
  490. if(shape && shape instanceof CanvasShape)
  491. {
  492. shape._destroy();
  493. delete this._shapes[shape.get("id")];
  494. }
  495. if(this.get("autoDraw"))
  496. {
  497. this._redraw();
  498. }
  499. return shape;
  500. },
  501.  
  502. /**
  503. * Removes all shape instances from the dom.
  504. *
  505. * @method removeAllShapes
  506. */
  507. removeAllShapes: function()
  508. {
  509. var shapes = this._shapes,
  510. i;
  511. for(i in shapes)
  512. {
  513. if(shapes.hasOwnProperty(i))
  514. {
  515. shapes[i].destroy();
  516. }
  517. }
  518. this._shapes = {};
  519. },
  520.  
  521. /**
  522. * Clears the graphics object.
  523. *
  524. * @method clear
  525. */
  526. clear: function() {
  527. this.removeAllShapes();
  528. },
  529.  
  530. /**
  531. * Removes all child nodes.
  532. *
  533. * @method _removeChildren
  534. * @param {HTMLElement} node
  535. * @private
  536. */
  537. _removeChildren: function(node)
  538. {
  539. if(node && node.hasChildNodes())
  540. {
  541. var child;
  542. while(node.firstChild)
  543. {
  544. child = node.firstChild;
  545. this._removeChildren(child);
  546. node.removeChild(child);
  547. }
  548. }
  549. },
  550.  
  551. /**
  552. * Toggles visibility
  553. *
  554. * @method _toggleVisible
  555. * @param {Boolean} val indicates visibilitye
  556. * @private
  557. */
  558. _toggleVisible: function(val)
  559. {
  560. var i,
  561. shapes = this._shapes,
  562. visibility = val ? "visible" : "hidden";
  563. if(shapes)
  564. {
  565. for(i in shapes)
  566. {
  567. if(shapes.hasOwnProperty(i))
  568. {
  569. shapes[i].set("visible", val);
  570. }
  571. }
  572. }
  573. if(this._node)
  574. {
  575. this._node.style.visibility = visibility;
  576. }
  577. },
  578.  
  579. /**
  580. * Returns a shape class. Used by `addShape`.
  581. *
  582. * @method _getShapeClass
  583. * @param {Shape | String} val Indicates which shape class.
  584. * @return Function
  585. * @private
  586. */
  587. _getShapeClass: function(val)
  588. {
  589. var shape = this._shapeClass[val];
  590. if(shape)
  591. {
  592. return shape;
  593. }
  594. return val;
  595. },
  596.  
  597. /**
  598. * Look up for shape classes. Used by `addShape` to retrieve a class for instantiation.
  599. *
  600. * @property _shapeClass
  601. * @type Object
  602. * @private
  603. */
  604. _shapeClass: {
  605. circle: Y.CanvasCircle,
  606. rect: Y.CanvasRect,
  607. path: Y.CanvasPath,
  608. ellipse: Y.CanvasEllipse,
  609. pieslice: Y.CanvasPieSlice
  610. },
  611.  
  612. /**
  613. * Returns a shape based on the id of its dom node.
  614. *
  615. * @method getShapeById
  616. * @param {String} id Dom id of the shape's node attribute.
  617. * @return Shape
  618. */
  619. getShapeById: function(id)
  620. {
  621. var shape = this._shapes[id];
  622. return shape;
  623. },
  624.  
  625. /**
  626. * Allows for creating multiple shapes in order to batch appending and redraw operations.
  627. *
  628. * @method batch
  629. * @param {Function} method Method to execute.
  630. */
  631. batch: function(method)
  632. {
  633. var autoDraw = this.get("autoDraw");
  634. this.set("autoDraw", false);
  635. method();
  636. this.set("autoDraw", autoDraw);
  637. },
  638.  
  639. /**
  640. * Returns a document fragment to for attaching shapes.
  641. *
  642. * @method _getDocFrag
  643. * @return DocumentFragment
  644. * @private
  645. */
  646. _getDocFrag: function()
  647. {
  648. if(!this._frag)
  649. {
  650. this._frag = DOCUMENT.createDocumentFragment();
  651. }
  652. return this._frag;
  653. },
  654.  
  655. /**
  656. * Redraws all shapes.
  657. *
  658. * @method _redraw
  659. * @private
  660. */
  661. _redraw: function()
  662. {
  663. var autoSize = this.get("autoSize"),
  664. preserveAspectRatio = this.get("preserveAspectRatio"),
  665. box = this.get("resizeDown") ? this._getUpdatedContentBounds() : this._contentBounds,
  666. contentWidth,
  667. contentHeight,
  668. w,
  669. h,
  670. xScale,
  671. yScale,
  672. translateX = 0,
  673. translateY = 0,
  674. matrix,
  675. node = this.get("node");
  676. if(autoSize)
  677. {
  678. if(autoSize === "sizeContentToGraphic")
  679. {
  680. contentWidth = box.right - box.left;
  681. contentHeight = box.bottom - box.top;
  682. w = parseFloat(Y_DOM.getComputedStyle(node, "width"));
  683. h = parseFloat(Y_DOM.getComputedStyle(node, "height"));
  684. matrix = new Y.Matrix();
  685. if(preserveAspectRatio === "none")
  686. {
  687. xScale = w/contentWidth;
  688. yScale = h/contentHeight;
  689. }
  690. else
  691. {
  692. if(contentWidth/contentHeight !== w/h)
  693. {
  694. if(contentWidth * h/contentHeight > w)
  695. {
  696. xScale = yScale = w/contentWidth;
  697. translateY = this._calculateTranslate(preserveAspectRatio.slice(5).toLowerCase(), contentHeight * w/contentWidth, h);
  698. }
  699. else
  700. {
  701. xScale = yScale = h/contentHeight;
  702. translateX = this._calculateTranslate(preserveAspectRatio.slice(1, 4).toLowerCase(), contentWidth * h/contentHeight, w);
  703. }
  704. }
  705. }
  706. Y_DOM.setStyle(node, "transformOrigin", "0% 0%");
  707. translateX = translateX - (box.left * xScale);
  708. translateY = translateY - (box.top * yScale);
  709. matrix.translate(translateX, translateY);
  710. matrix.scale(xScale, yScale);
  711. Y_DOM.setStyle(node, "transform", matrix.toCSSText());
  712. }
  713. else
  714. {
  715. this.set("width", box.right);
  716. this.set("height", box.bottom);
  717. }
  718. }
  719. if(this._frag)
  720. {
  721. this._node.appendChild(this._frag);
  722. this._frag = null;
  723. }
  724. },
  725.  
  726. /**
  727. * Determines the value for either an x or y value to be used for the <code>translate</code> of the Graphic.
  728. *
  729. * @method _calculateTranslate
  730. * @param {String} position The position for placement. Possible values are min, mid and max.
  731. * @param {Number} contentSize The total size of the content.
  732. * @param {Number} boundsSize The total size of the Graphic.
  733. * @return Number
  734. * @private
  735. */
  736. _calculateTranslate: function(position, contentSize, boundsSize)
  737. {
  738. var ratio = boundsSize - contentSize,
  739. coord;
  740. switch(position)
  741. {
  742. case "mid" :
  743. coord = ratio * 0.5;
  744. break;
  745. case "max" :
  746. coord = ratio;
  747. break;
  748. default :
  749. coord = 0;
  750. break;
  751. }
  752. return coord;
  753. },
  754.  
  755. /**
  756. * Adds a shape to the redraw queue and calculates the contentBounds. Used internally
  757. * by `Shape` instances.
  758. *
  759. * @method addToRedrawQueue
  760. * @param Shape shape The shape instance to add to the queue
  761. * @protected
  762. */
  763. addToRedrawQueue: function(shape)
  764. {
  765. var shapeBox,
  766. box;
  767. this._shapes[shape.get("id")] = shape;
  768. if(!this.get("resizeDown"))
  769. {
  770. shapeBox = shape.getBounds();
  771. box = this._contentBounds;
  772. box.left = box.left < shapeBox.left ? box.left : shapeBox.left;
  773. box.top = box.top < shapeBox.top ? box.top : shapeBox.top;
  774. box.right = box.right > shapeBox.right ? box.right : shapeBox.right;
  775. box.bottom = box.bottom > shapeBox.bottom ? box.bottom : shapeBox.bottom;
  776. this._contentBounds = box;
  777. }
  778. if(this.get("autoDraw"))
  779. {
  780. this._redraw();
  781. }
  782. },
  783.  
  784. /**
  785. * Recalculates and returns the `contentBounds` for the `Graphic` instance.
  786. *
  787. * @method _getUpdatedContentBounds
  788. * @return {Object}
  789. * @private
  790. */
  791. _getUpdatedContentBounds: function()
  792. {
  793. var bounds,
  794. i,
  795. shape,
  796. queue = this._shapes,
  797. box = {};
  798. for(i in queue)
  799. {
  800. if(queue.hasOwnProperty(i))
  801. {
  802. shape = queue[i];
  803. bounds = shape.getBounds();
  804. box.left = Y_LANG.isNumber(box.left) ? Math.min(box.left, bounds.left) : bounds.left;
  805. box.top = Y_LANG.isNumber(box.top) ? Math.min(box.top, bounds.top) : bounds.top;
  806. box.right = Y_LANG.isNumber(box.right) ? Math.max(box.right, bounds.right) : bounds.right;
  807. box.bottom = Y_LANG.isNumber(box.bottom) ? Math.max(box.bottom, bounds.bottom) : bounds.bottom;
  808. }
  809. }
  810. box.left = Y_LANG.isNumber(box.left) ? box.left : 0;
  811. box.top = Y_LANG.isNumber(box.top) ? box.top : 0;
  812. box.right = Y_LANG.isNumber(box.right) ? box.right : 0;
  813. box.bottom = Y_LANG.isNumber(box.bottom) ? box.bottom : 0;
  814. this._contentBounds = box;
  815. return box;
  816. },
  817.  
  818. /**
  819. * Inserts shape on the top of the tree.
  820. *
  821. * @method _toFront
  822. * @param {CanvasShape} Shape to add.
  823. * @private
  824. */
  825. _toFront: function(shape)
  826. {
  827. var contentNode = this.get("node");
  828. if(shape instanceof Y.CanvasShape)
  829. {
  830. shape = shape.get("node");
  831. }
  832. if(contentNode && shape)
  833. {
  834. contentNode.appendChild(shape);
  835. }
  836. },
  837.  
  838. /**
  839. * Inserts shape as the first child of the content node.
  840. *
  841. * @method _toBack
  842. * @param {CanvasShape} Shape to add.
  843. * @private
  844. */
  845. _toBack: function(shape)
  846. {
  847. var contentNode = this.get("node"),
  848. targetNode;
  849. if(shape instanceof Y.CanvasShape)
  850. {
  851. shape = shape.get("node");
  852. }
  853. if(contentNode && shape)
  854. {
  855. targetNode = contentNode.firstChild;
  856. if(targetNode)
  857. {
  858. contentNode.insertBefore(shape, targetNode);
  859. }
  860. else
  861. {
  862. contentNode.appendChild(shape);
  863. }
  864. }
  865. }
  866. });
  867.  
  868. Y.CanvasGraphic = CanvasGraphic;
  869.