[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/graphics-svg/ -> graphics-svg-debug.js (source)

   1  /*
   2  YUI 3.17.2 (build 9c3c78e)
   3  Copyright 2014 Yahoo! Inc. All rights reserved.
   4  Licensed under the BSD License.
   5  http://yuilibrary.com/license/
   6  */
   7  
   8  YUI.add('graphics-svg', function (Y, NAME) {
   9  
  10  var IMPLEMENTATION = "svg",
  11      SHAPE = "shape",
  12      SPLITPATHPATTERN = /[a-z][^a-z]*/ig,
  13      SPLITARGSPATTERN = /[\-]?[0-9]*[0-9|\.][0-9]*/g,
  14      Y_LANG = Y.Lang,
  15      AttributeLite = Y.AttributeLite,
  16      SVGGraphic,
  17      SVGShape,
  18      SVGCircle,
  19      SVGRect,
  20      SVGPath,
  21      SVGEllipse,
  22      SVGPieSlice,
  23      DOCUMENT = Y.config.doc,
  24      _getClassName = Y.ClassNameManager.getClassName;
  25  
  26  function SVGDrawing(){}
  27  
  28  /**
  29   * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Drawing.html">`Drawing`</a> class.
  30   * `SVGDrawing` is not intended to be used directly. Instead, use the <a href="Drawing.html">`Drawing`</a> class.
  31   * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Drawing.html">`Drawing`</a>
  32   * class will point to the `SVGDrawing` class.
  33   *
  34   * @module graphics
  35   * @class SVGDrawing
  36   * @constructor
  37   */
  38  SVGDrawing.prototype = {
  39      /**
  40       * Rounds a value to the nearest hundredth.
  41       *
  42       * @method _round
  43       * @param {Number} val Value to be rounded.
  44       * @return Number
  45       * @private
  46       */
  47      _round: function(val) {
  48          return Math.round(val * 100)/100;
  49      },
  50  
  51      /**
  52       * Maps path to methods
  53       *
  54       * @property _pathSymbolToMethod
  55       * @type Object
  56       * @private
  57       */
  58      _pathSymbolToMethod: {
  59          M: "moveTo",
  60          m: "relativeMoveTo",
  61          L: "lineTo",
  62          l: "relativeLineTo",
  63          C: "curveTo",
  64          c: "relativeCurveTo",
  65          Q: "quadraticCurveTo",
  66          q: "relativeQuadraticCurveTo",
  67          z: "closePath",
  68          Z: "closePath"
  69      },
  70  
  71      /**
  72       * Current x position of the drawing.
  73       *
  74       * @property _currentX
  75       * @type Number
  76       * @private
  77       */
  78      _currentX: 0,
  79  
  80      /**
  81       * Current y position of the drqwing.
  82       *
  83       * @property _currentY
  84       * @type Number
  85       * @private
  86       */
  87      _currentY: 0,
  88  
  89      /**
  90       * Indicates the type of shape
  91       *
  92       * @private
  93       * @property _type
  94       * @readOnly
  95       * @type String
  96       */
  97      _type: "path",
  98  
  99      /**
 100       * Draws a bezier curve.
 101       *
 102       * @method curveTo
 103       * @param {Number} cp1x x-coordinate for the first control point.
 104       * @param {Number} cp1y y-coordinate for the first control point.
 105       * @param {Number} cp2x x-coordinate for the second control point.
 106       * @param {Number} cp2y y-coordinate for the second control point.
 107       * @param {Number} x x-coordinate for the end point.
 108       * @param {Number} y y-coordinate for the end point.
 109       * @chainable
 110       */
 111      curveTo: function() {
 112          this._curveTo.apply(this, [Y.Array(arguments), false]);
 113          return this;
 114      },
 115  
 116      /**
 117       * Draws a bezier curve relative to the current coordinates.
 118       *
 119       * @method relativeCurveTo
 120       * @param {Number} cp1x x-coordinate for the first control point.
 121       * @param {Number} cp1y y-coordinate for the first control point.
 122       * @param {Number} cp2x x-coordinate for the second control point.
 123       * @param {Number} cp2y y-coordinate for the second control point.
 124       * @param {Number} x x-coordinate for the end point.
 125       * @param {Number} y y-coordinate for the end point.
 126       * @chainable
 127       */
 128      relativeCurveTo: function() {
 129          this._curveTo.apply(this, [Y.Array(arguments), true]);
 130          return this;
 131      },
 132  
 133      /**
 134       * Implements curveTo methods.
 135       *
 136       * @method _curveTo
 137       * @param {Array} args The arguments to be used.
 138       * @param {Boolean} relative Indicates whether or not to use relative coordinates.
 139       * @private
 140       */
 141      _curveTo: function(args, relative) {
 142          var w,
 143              h,
 144              pts,
 145              cp1x,
 146              cp1y,
 147              cp2x,
 148              cp2y,
 149              x,
 150              y,
 151              right,
 152              left,
 153              bottom,
 154              top,
 155              i,
 156              len,
 157              pathArrayLen,
 158              currentArray,
 159              command = relative ? "c" : "C",
 160              relativeX = relative ? parseFloat(this._currentX) : 0,
 161              relativeY = relative ? parseFloat(this._currentY) : 0;
 162          this._pathArray = this._pathArray || [];
 163          if(this._pathType !== command)
 164          {
 165              this._pathType = command;
 166              currentArray = [command];
 167              this._pathArray.push(currentArray);
 168          }
 169          else
 170          {
 171              currentArray = this._pathArray[Math.max(0, this._pathArray.length - 1)];
 172              if(!currentArray)
 173              {
 174                  currentArray = [];
 175                  this._pathArray.push(currentArray);
 176              }
 177          }
 178          pathArrayLen = this._pathArray.length - 1;
 179          this._pathArray[pathArrayLen] = this._pathArray[pathArrayLen].concat(args);
 180          len = args.length - 5;
 181          for(i = 0; i < len; i = i + 6)
 182          {
 183              cp1x = parseFloat(args[i]) + relativeX;
 184              cp1y = parseFloat(args[i + 1]) + relativeY;
 185              cp2x = parseFloat(args[i + 2]) + relativeX;
 186              cp2y = parseFloat(args[i + 3]) + relativeY;
 187              x = parseFloat(args[i + 4]) + relativeX;
 188              y = parseFloat(args[i + 5]) + relativeY;
 189              right = Math.max(x, Math.max(cp1x, cp2x));
 190              bottom = Math.max(y, Math.max(cp1y, cp2y));
 191              left = Math.min(x, Math.min(cp1x, cp2x));
 192              top = Math.min(y, Math.min(cp1y, cp2y));
 193              w = Math.abs(right - left);
 194              h = Math.abs(bottom - top);
 195              pts = [[this._currentX, this._currentY] , [cp1x, cp1y], [cp2x, cp2y], [x, y]];
 196              this._setCurveBoundingBox(pts, w, h);
 197              this._currentX = x;
 198              this._currentY = y;
 199          }
 200      },
 201  
 202      /**
 203       * Draws a quadratic bezier curve.
 204       *
 205       * @method quadraticCurveTo
 206       * @param {Number} cpx x-coordinate for the control point.
 207       * @param {Number} cpy y-coordinate for the control point.
 208       * @param {Number} x x-coordinate for the end point.
 209       * @param {Number} y y-coordinate for the end point.
 210       * @chainable
 211       */
 212      quadraticCurveTo: function() {
 213          this._quadraticCurveTo.apply(this, [Y.Array(arguments), false]);
 214          return this;
 215      },
 216  
 217      /**
 218       * Draws a quadratic bezier curve relative to the current position.
 219       *
 220       * @method quadraticCurveTo
 221       * @param {Number} cpx x-coordinate for the control point.
 222       * @param {Number} cpy y-coordinate for the control point.
 223       * @param {Number} x x-coordinate for the end point.
 224       * @param {Number} y y-coordinate for the end point.
 225       * @chainable
 226       */
 227      relativeQuadraticCurveTo: function() {
 228          this._quadraticCurveTo.apply(this, [Y.Array(arguments), true]);
 229          return this;
 230      },
 231  
 232      /**
 233       * Implements quadraticCurveTo methods.
 234       *
 235       * @method _quadraticCurveTo
 236       * @param {Array} args The arguments to be used.
 237       * @param {Boolean} relative Indicates whether or not to use relative coordinates.
 238       * @private
 239       */
 240      _quadraticCurveTo: function(args, relative) {
 241          var cpx,
 242              cpy,
 243              x,
 244              y,
 245              pathArrayLen,
 246              currentArray,
 247              w,
 248              h,
 249              pts,
 250              right,
 251              left,
 252              bottom,
 253              top,
 254              i,
 255              len,
 256              command = relative ? "q" : "Q",
 257              relativeX = relative ? parseFloat(this._currentX) : 0,
 258              relativeY = relative ? parseFloat(this._currentY) : 0;
 259          this._pathArray = this._pathArray || [];
 260          if(this._pathType !== command)
 261          {
 262              this._pathType = command;
 263              currentArray = [command];
 264              this._pathArray.push(currentArray);
 265          }
 266          else
 267          {
 268              currentArray = this._pathArray[Math.max(0, this._pathArray.length - 1)];
 269              if(!currentArray)
 270              {
 271                  currentArray = [];
 272                  this._pathArray.push(currentArray);
 273              }
 274          }
 275          pathArrayLen = this._pathArray.length - 1;
 276          this._pathArray[pathArrayLen] = this._pathArray[pathArrayLen].concat(args);
 277          len = args.length - 3;
 278          for(i = 0; i < len; i = i + 4)
 279          {
 280              cpx = parseFloat(args[i]) + relativeX;
 281              cpy = parseFloat(args[i + 1]) + relativeY;
 282              x = parseFloat(args[i + 2]) + relativeX;
 283              y = parseFloat(args[i + 3]) + relativeY;
 284              right = Math.max(x, cpx);
 285              bottom = Math.max(y, cpy);
 286              left = Math.min(x, cpx);
 287              top = Math.min(y, cpy);
 288              w = Math.abs(right - left);
 289              h = Math.abs(bottom - top);
 290              pts = [[this._currentX, this._currentY] , [cpx, cpy], [x, y]];
 291              this._setCurveBoundingBox(pts, w, h);
 292              this._currentX = x;
 293              this._currentY = y;
 294          }
 295      },
 296  
 297      /**
 298       * Draws a rectangle.
 299       *
 300       * @method drawRect
 301       * @param {Number} x x-coordinate
 302       * @param {Number} y y-coordinate
 303       * @param {Number} w width
 304       * @param {Number} h height
 305       * @chainable
 306       */
 307      drawRect: function(x, y, w, h) {
 308          this.moveTo(x, y);
 309          this.lineTo(x + w, y);
 310          this.lineTo(x + w, y + h);
 311          this.lineTo(x, y + h);
 312          this.lineTo(x, y);
 313          return this;
 314      },
 315  
 316      /**
 317       * Draws a rectangle with rounded corners.
 318       *
 319       * @method drawRoundRect
 320       * @param {Number} x x-coordinate
 321       * @param {Number} y y-coordinate
 322       * @param {Number} w width
 323       * @param {Number} h height
 324       * @param {Number} ew width of the ellipse used to draw the rounded corners
 325       * @param {Number} eh height of the ellipse used to draw the rounded corners
 326       * @chainable
 327       */
 328      drawRoundRect: function(x, y, w, h, ew, eh) {
 329          this.moveTo(x, y + eh);
 330          this.lineTo(x, y + h - eh);
 331          this.quadraticCurveTo(x, y + h, x + ew, y + h);
 332          this.lineTo(x + w - ew, y + h);
 333          this.quadraticCurveTo(x + w, y + h, x + w, y + h - eh);
 334          this.lineTo(x + w, y + eh);
 335          this.quadraticCurveTo(x + w, y, x + w - ew, y);
 336          this.lineTo(x + ew, y);
 337          this.quadraticCurveTo(x, y, x, y + eh);
 338          return this;
 339      },
 340  
 341      /**
 342       * Draws a circle.
 343       *
 344       * @method drawCircle
 345       * @param {Number} x y-coordinate
 346       * @param {Number} y x-coordinate
 347       * @param {Number} r radius
 348       * @chainable
 349       * @protected
 350       */
 351      drawCircle: function(x, y, radius) {
 352          var circum = radius * 2;
 353          this._drawingComplete = false;
 354          this._trackSize(x, y);
 355          this._trackSize(x + circum, y + circum);
 356          this._pathArray = this._pathArray || [];
 357          this._pathArray.push(["M", x + radius, y]);
 358          this._pathArray.push(["A",  radius, radius, 0, 1, 0, x + radius, y + circum]);
 359          this._pathArray.push(["A",  radius, radius, 0, 1, 0, x + radius, y]);
 360          this._currentX = x;
 361          this._currentY = y;
 362          return this;
 363      },
 364  
 365      /**
 366       * Draws an ellipse.
 367       *
 368       * @method drawEllipse
 369       * @param {Number} x x-coordinate
 370       * @param {Number} y y-coordinate
 371       * @param {Number} w width
 372       * @param {Number} h height
 373       * @chainable
 374       * @protected
 375       */
 376      drawEllipse: function(x, y, w, h) {
 377          var radius = w * 0.5,
 378              yRadius = h * 0.5;
 379          this._drawingComplete = false;
 380          this._trackSize(x, y);
 381          this._trackSize(x + w, y + h);
 382          this._pathArray = this._pathArray || [];
 383          this._pathArray.push(["M", x + radius, y]);
 384          this._pathArray.push(["A",  radius, yRadius, 0, 1, 0, x + radius, y + h]);
 385          this._pathArray.push(["A",  radius, yRadius, 0, 1, 0, x + radius, y]);
 386          this._currentX = x;
 387          this._currentY = y;
 388          return this;
 389      },
 390  
 391      /**
 392       * Draws a diamond.
 393       *
 394       * @method drawDiamond
 395       * @param {Number} x y-coordinate
 396       * @param {Number} y x-coordinate
 397       * @param {Number} width width
 398       * @param {Number} height height
 399       * @chainable
 400       * @protected
 401       */
 402      drawDiamond: function(x, y, width, height)
 403      {
 404          var midWidth = width * 0.5,
 405              midHeight = height * 0.5;
 406          this.moveTo(x + midWidth, y);
 407          this.lineTo(x + width, y + midHeight);
 408          this.lineTo(x + midWidth, y + height);
 409          this.lineTo(x, y + midHeight);
 410          this.lineTo(x + midWidth, y);
 411          return this;
 412      },
 413  
 414      /**
 415       * Draws a wedge.
 416       *
 417       * @method drawWedge
 418       * @param {Number} x x-coordinate of the wedge's center point
 419       * @param {Number} y y-coordinate of the wedge's center point
 420       * @param {Number} startAngle starting angle in degrees
 421       * @param {Number} arc sweep of the wedge. Negative values draw clockwise.
 422       * @param {Number} radius radius of wedge. If [optional] yRadius is defined, then radius is the x radius.
 423       * @param {Number} yRadius [optional] y radius for wedge.
 424       * @chainable
 425       * @private
 426       */
 427      drawWedge: function(x, y, startAngle, arc, radius, yRadius)
 428      {
 429          var segs,
 430              segAngle,
 431              theta,
 432              angle,
 433              angleMid,
 434              ax,
 435              ay,
 436              bx,
 437              by,
 438              cx,
 439              cy,
 440              i,
 441              diameter = radius * 2,
 442              currentArray,
 443              pathArrayLen;
 444          this._pathArray = this._pathArray || [];
 445          yRadius = yRadius || radius;
 446          if(this._pathType !== "M")
 447          {
 448              this._pathType = "M";
 449              currentArray = ["M"];
 450              this._pathArray.push(currentArray);
 451          }
 452          else
 453          {
 454              currentArray = this._getCurrentArray();
 455          }
 456          pathArrayLen = this._pathArray.length - 1;
 457          this._pathArray[pathArrayLen].push(x);
 458          this._pathArray[pathArrayLen].push(x);
 459  
 460          // limit sweep to reasonable numbers
 461          if(Math.abs(arc) > 360)
 462          {
 463              arc = 360;
 464          }
 465  
 466          // First we calculate how many segments are needed
 467          // for a smooth arc.
 468          segs = Math.ceil(Math.abs(arc) / 45);
 469  
 470          // Now calculate the sweep of each segment.
 471          segAngle = arc / segs;
 472  
 473          // The math requires radians rather than degrees. To convert from degrees
 474          // use the formula (degrees/180)*Math.PI to get radians.
 475          theta = -(segAngle / 180) * Math.PI;
 476  
 477          // convert angle startAngle to radians
 478          angle = (startAngle / 180) * Math.PI;
 479          if(segs > 0)
 480          {
 481              // draw a line from the center to the start of the curve
 482              ax = x + Math.cos(startAngle / 180 * Math.PI) * radius;
 483              ay = y + Math.sin(startAngle / 180 * Math.PI) * yRadius;
 484              this._pathType = "L";
 485              pathArrayLen++;
 486              this._pathArray[pathArrayLen] = ["L"];
 487              this._pathArray[pathArrayLen].push(this._round(ax));
 488              this._pathArray[pathArrayLen].push(this._round(ay));
 489              pathArrayLen++;
 490              this._pathType = "Q";
 491              this._pathArray[pathArrayLen] = ["Q"];
 492              for(i = 0; i < segs; ++i)
 493              {
 494                  angle += theta;
 495                  angleMid = angle - (theta / 2);
 496                  bx = x + Math.cos(angle) * radius;
 497                  by = y + Math.sin(angle) * yRadius;
 498                  cx = x + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
 499                  cy = y + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
 500                  this._pathArray[pathArrayLen].push(this._round(cx));
 501                  this._pathArray[pathArrayLen].push(this._round(cy));
 502                  this._pathArray[pathArrayLen].push(this._round(bx));
 503                  this._pathArray[pathArrayLen].push(this._round(by));
 504              }
 505          }
 506          this._currentX = x;
 507          this._currentY = y;
 508          this._trackSize(diameter, diameter);
 509          return this;
 510      },
 511  
 512      /**
 513       * Draws a line segment using the current line style from the current drawing position to the specified x and y coordinates.
 514       *
 515       * @method lineTo
 516       * @param {Number} point1 x-coordinate for the end point.
 517       * @param {Number} point2 y-coordinate for the end point.
 518       * @chainable
 519       */
 520      lineTo: function()
 521      {
 522          this._lineTo.apply(this, [Y.Array(arguments), false]);
 523          return this;
 524      },
 525  
 526      /**
 527       * Draws a line segment using the current line style from the current drawing position to the relative x and y coordinates.
 528       *
 529       * @method relativeLineTo
 530       * @param {Number} point1 x-coordinate for the end point.
 531       * @param {Number} point2 y-coordinate for the end point.
 532       * @chainable
 533       */
 534      relativeLineTo: function()
 535      {
 536          this._lineTo.apply(this, [Y.Array(arguments), true]);
 537          return this;
 538      },
 539  
 540      /**
 541       * Implements lineTo methods.
 542       *
 543       * @method _lineTo
 544       * @param {Array} args The arguments to be used.
 545       * @param {Boolean} relative Indicates whether or not to use relative coordinates.
 546       * @private
 547       */
 548      _lineTo: function(args, relative) {
 549          var point1 = args[0],
 550              i,
 551              len,
 552              pathArrayLen,
 553              currentArray,
 554              x,
 555              y,
 556              command = relative ? "l" : "L",
 557              relativeX = relative ? parseFloat(this._currentX) : 0,
 558              relativeY = relative ? parseFloat(this._currentY) : 0;
 559          this._pathArray = this._pathArray || [];
 560          this._shapeType = "path";
 561          len = args.length;
 562          if(this._pathType !== command)
 563          {
 564              this._pathType = command;
 565              currentArray = [command];
 566              this._pathArray.push(currentArray);
 567          }
 568          else
 569          {
 570              currentArray = this._getCurrentArray();
 571          }
 572          pathArrayLen = this._pathArray.length - 1;
 573          if (typeof point1 === 'string' || typeof point1 === 'number') {
 574              for (i = 0; i < len; i = i + 2) {
 575                  x = parseFloat(args[i]);
 576                  y = parseFloat(args[i + 1]);
 577                  this._pathArray[pathArrayLen].push(x);
 578                  this._pathArray[pathArrayLen].push(y);
 579                  x = x + relativeX;
 580                  y = y + relativeY;
 581                  this._currentX = x;
 582                  this._currentY = y;
 583                  this._trackSize.apply(this, [x, y]);
 584              }
 585          }
 586          else
 587          {
 588              for (i = 0; i < len; ++i) {
 589                  x = parseFloat(args[i][0]);
 590                  y = parseFloat(args[i][1]);
 591                  this._pathArray[pathArrayLen].push(x);
 592                  this._pathArray[pathArrayLen].push(y);
 593                  this._currentX = x;
 594                  this._currentY = y;
 595                  x = x + relativeX;
 596                  y = y + relativeY;
 597                  this._trackSize.apply(this, [x, y]);
 598              }
 599          }
 600      },
 601  
 602      /**
 603       * Moves the current drawing position to specified x and y coordinates.
 604       *
 605       * @method moveTo
 606       * @param {Number} x x-coordinate for the end point.
 607       * @param {Number} y y-coordinate for the end point.
 608       * @chainable
 609       */
 610      moveTo: function()
 611      {
 612          this._moveTo.apply(this, [Y.Array(arguments), false]);
 613          return this;
 614      },
 615  
 616      /**
 617       * Moves the current drawing position relative to specified x and y coordinates.
 618       *
 619       * @method relativeMoveTo
 620       * @param {Number} x x-coordinate for the end point.
 621       * @param {Number} y y-coordinate for the end point.
 622       * @chainable
 623       */
 624      relativeMoveTo: function()
 625      {
 626          this._moveTo.apply(this, [Y.Array(arguments), true]);
 627          return this;
 628      },
 629  
 630      /**
 631       * Implements moveTo methods.
 632       *
 633       * @method _moveTo
 634       * @param {Array} args The arguments to be used.
 635       * @param {Boolean} relative Indicates whether or not to use relative coordinates.
 636       * @private
 637       */
 638      _moveTo: function(args, relative) {
 639          var pathArrayLen,
 640              currentArray,
 641              x = parseFloat(args[0]),
 642              y = parseFloat(args[1]),
 643              command = relative ? "m" : "M",
 644              relativeX = relative ? parseFloat(this._currentX) : 0,
 645              relativeY = relative ? parseFloat(this._currentY) : 0;
 646          this._pathArray = this._pathArray || [];
 647          this._pathType = command;
 648          currentArray = [command];
 649          this._pathArray.push(currentArray);
 650          pathArrayLen = this._pathArray.length - 1;
 651          this._pathArray[pathArrayLen] = this._pathArray[pathArrayLen].concat([x, y]);
 652          x = x + relativeX;
 653          y = y + relativeY;
 654          this._currentX = x;
 655          this._currentY = y;
 656          this._trackSize(x, y);
 657      },
 658  
 659      /**
 660       * Completes a drawing operation.
 661       *
 662       * @method end
 663       * @chainable
 664       */
 665      end: function()
 666      {
 667          this._closePath();
 668          return this;
 669      },
 670  
 671      /**
 672       * Clears the path.
 673       *
 674       * @method clear
 675       * @chainable
 676       */
 677      clear: function()
 678      {
 679          this._currentX = 0;
 680          this._currentY = 0;
 681          this._width = 0;
 682          this._height = 0;
 683          this._left = 0;
 684          this._right = 0;
 685          this._top = 0;
 686          this._bottom = 0;
 687          this._pathArray = [];
 688          this._path = "";
 689          this._pathType = "";
 690          return this;
 691      },
 692  
 693      /**
 694       * Draws the path.
 695       *
 696       * @method _closePath
 697       * @private
 698       */
 699      _closePath: function()
 700      {
 701          var pathArray,
 702              segmentArray,
 703              pathType,
 704              len,
 705              val,
 706              i,
 707              path = "",
 708              node = this.node,
 709              left = parseFloat(this._left),
 710              top = parseFloat(this._top),
 711              fill = this.get("fill");
 712          if(this._pathArray)
 713          {
 714              pathArray = this._pathArray.concat();
 715              while(pathArray && pathArray.length > 0)
 716              {
 717                  segmentArray = pathArray.shift();
 718                  len = segmentArray.length;
 719                  pathType = segmentArray[0];
 720                  if(pathType === "A")
 721                  {
 722                      path += pathType + segmentArray[1] + "," + segmentArray[2];
 723                  }
 724                  else if(pathType === "z" || pathType === "Z")
 725                  {
 726                      path += " z ";
 727                  }
 728                  else if(pathType === "C" || pathType === "c")
 729                  {
 730                      path += pathType + (segmentArray[1] - left)+ "," + (segmentArray[2] - top);
 731                  }
 732                  else
 733                  {
 734                      path += " " + pathType + parseFloat(segmentArray[1] - left);
 735                  }
 736                  switch(pathType)
 737                  {
 738                      case "L" :
 739                      case "l" :
 740                      case "M" :
 741                      case "m" :
 742                      case "Q" :
 743                      case "q" :
 744                          for(i = 2; i < len; ++i)
 745                          {
 746                              val = (i % 2 === 0) ? top : left;
 747                              val = segmentArray[i] - val;
 748                              path += ", " + parseFloat(val);
 749                          }
 750                      break;
 751                      case "A" :
 752                          val = " " + parseFloat(segmentArray[3]) + " " + parseFloat(segmentArray[4]);
 753                          val += "," + parseFloat(segmentArray[5]) + " " + parseFloat(segmentArray[6] - left);
 754                          val += "," + parseFloat(segmentArray[7] - top);
 755                          path += " " + val;
 756                      break;
 757                      case "C" :
 758                      case "c" :
 759                          for(i = 3; i < len - 1; i = i + 2)
 760                          {
 761                              val = parseFloat(segmentArray[i] - left);
 762                              val = val + ", ";
 763                              val = val + parseFloat(segmentArray[i + 1] - top);
 764                              path += " " + val;
 765                          }
 766                      break;
 767                  }
 768              }
 769              if(fill && fill.color)
 770              {
 771                  path += 'z';
 772              }
 773              Y.Lang.trim(path);
 774              if(path)
 775              {
 776                  node.setAttribute("d", path);
 777              }
 778  
 779              this._path = path;
 780              this._fillChangeHandler();
 781              this._strokeChangeHandler();
 782              this._updateTransform();
 783          }
 784      },
 785  
 786      /**
 787       * Ends a fill and stroke
 788       *
 789       * @method closePath
 790       * @chainable
 791       */
 792      closePath: function()
 793      {
 794          this._pathArray.push(["z"]);
 795          return this;
 796      },
 797  
 798      /**
 799       * Returns the current array of drawing commands.
 800       *
 801       * @method _getCurrentArray
 802       * @return Array
 803       * @private
 804       */
 805      _getCurrentArray: function()
 806      {
 807          var currentArray = this._pathArray[Math.max(0, this._pathArray.length - 1)];
 808          if(!currentArray)
 809          {
 810              currentArray = [];
 811              this._pathArray.push(currentArray);
 812          }
 813          return currentArray;
 814      },
 815  
 816      /**
 817       * Returns the points on a curve
 818       *
 819       * @method getBezierData
 820       * @param Array points Array containing the begin, end and control points of a curve.
 821       * @param Number t The value for incrementing the next set of points.
 822       * @return Array
 823       * @private
 824       */
 825      getBezierData: function(points, t) {
 826          var n = points.length,
 827              tmp = [],
 828              i,
 829              j;
 830  
 831          for (i = 0; i < n; ++i){
 832              tmp[i] = [points[i][0], points[i][1]]; // save input
 833          }
 834  
 835          for (j = 1; j < n; ++j) {
 836              for (i = 0; i < n - j; ++i) {
 837                  tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
 838                  tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
 839              }
 840          }
 841          return [ tmp[0][0], tmp[0][1] ];
 842      },
 843  
 844      /**
 845       * Calculates the bounding box for a curve
 846       *
 847       * @method _setCurveBoundingBox
 848       * @param Array pts Array containing points for start, end and control points of a curve.
 849       * @param Number w Width used to calculate the number of points to describe the curve.
 850       * @param Number h Height used to calculate the number of points to describe the curve.
 851       * @private
 852       */
 853      _setCurveBoundingBox: function(pts, w, h)
 854      {
 855          var i,
 856              left = this._currentX,
 857              right = left,
 858              top = this._currentY,
 859              bottom = top,
 860              len = Math.round(Math.sqrt((w * w) + (h * h))),
 861              t = 1/len,
 862              xy;
 863          for(i = 0; i < len; ++i)
 864          {
 865              xy = this.getBezierData(pts, t * i);
 866              left = isNaN(left) ? xy[0] : Math.min(xy[0], left);
 867              right = isNaN(right) ? xy[0] : Math.max(xy[0], right);
 868              top = isNaN(top) ? xy[1] : Math.min(xy[1], top);
 869              bottom = isNaN(bottom) ? xy[1] : Math.max(xy[1], bottom);
 870          }
 871          left = Math.round(left * 10)/10;
 872          right = Math.round(right * 10)/10;
 873          top = Math.round(top * 10)/10;
 874          bottom = Math.round(bottom * 10)/10;
 875          this._trackSize(right, bottom);
 876          this._trackSize(left, top);
 877      },
 878  
 879      /**
 880       * Updates the size of the graphics object
 881       *
 882       * @method _trackSize
 883       * @param {Number} w width
 884       * @param {Number} h height
 885       * @private
 886       */
 887      _trackSize: function(w, h) {
 888          if (w > this._right) {
 889              this._right = w;
 890          }
 891          if(w < this._left)
 892          {
 893              this._left = w;
 894          }
 895          if (h < this._top)
 896          {
 897              this._top = h;
 898          }
 899          if (h > this._bottom)
 900          {
 901              this._bottom = h;
 902          }
 903          this._width = this._right - this._left;
 904          this._height = this._bottom - this._top;
 905      }
 906  };
 907  Y.SVGDrawing = SVGDrawing;
 908  /**
 909   * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Shape.html">`Shape`</a> class.
 910   * `SVGShape` is not intended to be used directly. Instead, use the <a href="Shape.html">`Shape`</a> class.
 911   * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Shape.html">`Shape`</a>
 912   * class will point to the `SVGShape` class.
 913   *
 914   * @module graphics
 915   * @class SVGShape
 916   * @constructor
 917   * @param {Object} cfg (optional) Attribute configs
 918   */
 919  SVGShape = function()
 920  {
 921      this._transforms = [];
 922      this.matrix = new Y.Matrix();
 923      this._normalizedMatrix = new Y.Matrix();
 924      SVGShape.superclass.constructor.apply(this, arguments);
 925  };
 926  
 927  SVGShape.NAME = "shape";
 928  
 929  Y.extend(SVGShape, Y.GraphicBase, Y.mix({
 930      /**
 931       * Storage for x attribute.
 932       *
 933       * @property _x
 934       * @protected
 935       */
 936      _x: 0,
 937  
 938      /**
 939       * Storage for y attribute.
 940       *
 941       * @property _y
 942       * @protected
 943       */
 944      _y: 0,
 945  
 946      /**
 947       * Init method, invoked during construction.
 948       * Calls `initializer` method.
 949       *
 950       * @method init
 951       * @protected
 952       */
 953      init: function()
 954      {
 955          this.initializer.apply(this, arguments);
 956      },
 957  
 958      /**
 959       * Initializes the shape
 960       *
 961       * @private
 962       * @method initializer
 963       */
 964      initializer: function(cfg)
 965      {
 966          var host = this,
 967              graphic = cfg.graphic,
 968              data = this.get("data");
 969          host.createNode();
 970          if(graphic)
 971          {
 972              host._setGraphic(graphic);
 973          }
 974          if(data)
 975          {
 976              host._parsePathData(data);
 977          }
 978          host._updateHandler();
 979      },
 980  
 981      /**
 982       * Set the Graphic instance for the shape.
 983       *
 984       * @method _setGraphic
 985       * @param {Graphic | Node | HTMLElement | String} render This param is used to determine the graphic instance. If it is a
 986       * `Graphic` instance, it will be assigned to the `graphic` attribute. Otherwise, a new Graphic instance will be created
 987       * and rendered into the dom element that the render represents.
 988       * @private
 989       */
 990      _setGraphic: function(render)
 991      {
 992          var graphic;
 993          if(render instanceof Y.SVGGraphic)
 994          {
 995              this._graphic = render;
 996          }
 997          else
 998          {
 999              graphic = new Y.SVGGraphic({
1000                  render: render
1001              });
1002              graphic._appendShape(this);
1003              this._graphic = graphic;
1004          }
1005      },
1006  
1007      /**
1008       * Add a class name to each node.
1009       *
1010       * @method addClass
1011       * @param {String} className the class name to add to the node's class attribute
1012       */
1013      addClass: function(className)
1014      {
1015          var node = this.node;
1016          node.className.baseVal = Y_LANG.trim([node.className.baseVal, className].join(' '));
1017      },
1018  
1019      /**
1020       * Removes a class name from each node.
1021       *
1022       * @method removeClass
1023       * @param {String} className the class name to remove from the node's class attribute
1024       */
1025      removeClass: function(className)
1026      {
1027          var node = this.node,
1028              classString = node.className.baseVal;
1029          classString = classString.replace(new RegExp(className + ' '), className).replace(new RegExp(className), '');
1030          node.className.baseVal = classString;
1031      },
1032  
1033      /**
1034       * Gets the current position of the node in page coordinates.
1035       *
1036       * @method getXY
1037       * @return Array The XY position of the shape.
1038       */
1039      getXY: function()
1040      {
1041          var graphic = this._graphic,
1042              parentXY = graphic.getXY(),
1043              x = this._x,
1044              y = this._y;
1045          return [parentXY[0] + x, parentXY[1] + y];
1046      },
1047  
1048      /**
1049       * Set the position of the shape in page coordinates, regardless of how the node is positioned.
1050       *
1051       * @method setXY
1052       * @param {Array} Contains x & y values for new position (coordinates are page-based)
1053       */
1054      setXY: function(xy)
1055      {
1056          var graphic = this._graphic,
1057              parentXY = graphic.getXY();
1058          this._x = xy[0] - parentXY[0];
1059          this._y = xy[1] - parentXY[1];
1060          this.set("transform", this.get("transform"));
1061      },
1062  
1063      /**
1064       * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
1065       *
1066       * @method contains
1067       * @param {SVGShape | HTMLElement} needle The possible node or descendent
1068       * @return Boolean Whether or not this shape is the needle or its ancestor.
1069       */
1070      contains: function(needle)
1071      {
1072          var node = needle instanceof Y.Node ? needle._node : needle;
1073          return node === this.node;
1074      },
1075  
1076      /**
1077       * Compares nodes to determine if they match.
1078       * Node instances can be compared to each other and/or HTMLElements.
1079       * @method compareTo
1080       * @param {HTMLElement | Node} refNode The reference node to compare to the node.
1081       * @return {Boolean} True if the nodes match, false if they do not.
1082       */
1083      compareTo: function(refNode) {
1084          var node = this.node;
1085  
1086          return node === refNode;
1087      },
1088  
1089      /**
1090       * Test if the supplied node matches the supplied selector.
1091       *
1092       * @method test
1093       * @param {String} selector The CSS selector to test against.
1094       * @return Boolean Wheter or not the shape matches the selector.
1095       */
1096      test: function(selector)
1097      {
1098          return Y.Selector.test(this.node, selector);
1099      },
1100  
1101      /**
1102       * Value function for fill attribute
1103       *
1104       * @private
1105       * @method _getDefaultFill
1106       * @return Object
1107       */
1108      _getDefaultFill: function() {
1109          return {
1110              type: "solid",
1111              opacity: 1,
1112              cx: 0.5,
1113              cy: 0.5,
1114              fx: 0.5,
1115              fy: 0.5,
1116              r: 0.5
1117          };
1118      },
1119  
1120      /**
1121       * Value function for stroke attribute
1122       *
1123       * @private
1124       * @method _getDefaultStroke
1125       * @return Object
1126       */
1127      _getDefaultStroke: function()
1128      {
1129          return {
1130              weight: 1,
1131              dashstyle: "none",
1132              color: "#000",
1133              opacity: 1.0
1134          };
1135      },
1136  
1137      /**
1138       * Creates the dom node for the shape.
1139       *
1140       * @method createNode
1141       * @return HTMLElement
1142       * @private
1143       */
1144      createNode: function()
1145      {
1146          var host = this,
1147              node = DOCUMENT.createElementNS("http://www.w3.org/2000/svg", "svg:" + this._type),
1148              id = host.get("id"),
1149              name = host.name,
1150              concat = host._camelCaseConcat,
1151              pointerEvents = host.get("pointerEvents");
1152          host.node = node;
1153          host.addClass(
1154              _getClassName(SHAPE) +
1155              " " +
1156              _getClassName(concat(IMPLEMENTATION, SHAPE)) +
1157              " " +
1158              _getClassName(name) +
1159              " " +
1160              _getClassName(concat(IMPLEMENTATION, name))
1161          );
1162          if(id)
1163          {
1164              node.setAttribute("id", id);
1165          }
1166          if(pointerEvents)
1167          {
1168              node.setAttribute("pointer-events", pointerEvents);
1169          }
1170          if(!host.get("visible"))
1171          {
1172              Y.DOM.setStyle(node, "visibility", "hidden");
1173          }
1174          Y.DOM.setAttribute(this.node, "shape-rendering", this.get("shapeRendering"));
1175      },
1176  
1177  
1178      /**
1179       * Overrides default `on` method. Checks to see if its a dom interaction event. If so,
1180       * return an event attached to the `node` element. If not, return the normal functionality.
1181       *
1182       * @method on
1183       * @param {String} type event type
1184       * @param {Object} callback function
1185       * @private
1186       */
1187      on: function(type, fn)
1188      {
1189          if(Y.Node.DOM_EVENTS[type])
1190          {
1191              return Y.on(type, fn, "#" + this.get("id"));
1192          }
1193          return Y.on.apply(this, arguments);
1194      },
1195  
1196      /**
1197       * Adds a stroke to the shape node.
1198       *
1199       * @method _strokeChangeHandler
1200       * @private
1201       */
1202      _strokeChangeHandler: function()
1203      {
1204          var node = this.node,
1205              stroke = this.get("stroke"),
1206              strokeOpacity,
1207              dashstyle,
1208              dash,
1209              linejoin;
1210          if(stroke && stroke.weight && stroke.weight > 0)
1211          {
1212              linejoin = stroke.linejoin || "round";
1213              strokeOpacity = parseFloat(stroke.opacity);
1214              dashstyle = stroke.dashstyle || "none";
1215              dash = Y_LANG.isArray(dashstyle) ? dashstyle.toString() : dashstyle;
1216              stroke.color = stroke.color || "#000000";
1217              stroke.weight = stroke.weight || 1;
1218              stroke.opacity = Y_LANG.isNumber(strokeOpacity) ? strokeOpacity : 1;
1219              stroke.linecap = stroke.linecap || "butt";
1220              node.setAttribute("stroke-dasharray", dash);
1221              node.setAttribute("stroke", stroke.color);
1222              node.setAttribute("stroke-linecap", stroke.linecap);
1223              node.setAttribute("stroke-width",  stroke.weight);
1224              node.setAttribute("stroke-opacity", stroke.opacity);
1225              if(linejoin === "round" || linejoin === "bevel")
1226              {
1227                  node.setAttribute("stroke-linejoin", linejoin);
1228              }
1229              else
1230              {
1231                  linejoin = parseInt(linejoin, 10);
1232                  if(Y_LANG.isNumber(linejoin))
1233                  {
1234                      node.setAttribute("stroke-miterlimit",  Math.max(linejoin, 1));
1235                      node.setAttribute("stroke-linejoin", "miter");
1236                  }
1237              }
1238          }
1239          else
1240          {
1241              node.setAttribute("stroke", "none");
1242          }
1243      },
1244  
1245      /**
1246       * Adds a fill to the shape node.
1247       *
1248       * @method _fillChangeHandler
1249       * @private
1250       */
1251      _fillChangeHandler: function()
1252      {
1253          var node = this.node,
1254              fill = this.get("fill"),
1255              fillOpacity,
1256              type;
1257          if(fill)
1258          {
1259              type = fill.type;
1260              if(type === "linear" || type === "radial")
1261              {
1262                  this._setGradientFill(fill);
1263                  node.setAttribute("fill", "url(#grad" + this.get("id") + ")");
1264              }
1265              else if(!fill.color)
1266              {
1267                  node.setAttribute("fill", "none");
1268              }
1269              else
1270              {
1271                  fillOpacity = parseFloat(fill.opacity);
1272                  fillOpacity = Y_LANG.isNumber(fillOpacity) ? fillOpacity : 1;
1273                  node.setAttribute("fill", fill.color);
1274                  node.setAttribute("fill-opacity", fillOpacity);
1275              }
1276          }
1277          else
1278          {
1279              node.setAttribute("fill", "none");
1280          }
1281      },
1282  
1283      /**
1284       * Creates a gradient fill
1285       *
1286       * @method _setGradientFill
1287       * @param {String} type gradient type
1288       * @private
1289       */
1290      _setGradientFill: function(fill) {
1291          var offset,
1292              opacity,
1293              color,
1294              stopNode,
1295              newStop,
1296              isNumber = Y_LANG.isNumber,
1297              graphic = this._graphic,
1298              type = fill.type,
1299              gradientNode = graphic.getGradientNode("grad" + this.get("id"), type),
1300              stops = fill.stops,
1301              w = this.get("width"),
1302              h = this.get("height"),
1303              rotation = fill.rotation || 0,
1304              radCon = Math.PI/180,
1305              tanRadians = parseFloat(parseFloat(Math.tan(rotation * radCon)).toFixed(8)),
1306              i,
1307              len,
1308              def,
1309              stop,
1310              x1 = "0%",
1311              x2 = "100%",
1312              y1 = "0%",
1313              y2 = "0%",
1314              cx = fill.cx,
1315              cy = fill.cy,
1316              fx = fill.fx,
1317              fy = fill.fy,
1318              r = fill.r,
1319              stopNodes = [];
1320          if(type === "linear")
1321          {
1322              cx = w/2;
1323              cy = h/2;
1324              if(Math.abs(tanRadians) * w/2 >= h/2)
1325              {
1326                  if(rotation < 180)
1327                  {
1328                      y1 = 0;
1329                      y2 = h;
1330                  }
1331                  else
1332                  {
1333                      y1 = h;
1334                      y2 = 0;
1335                  }
1336                  x1 = cx - ((cy - y1)/tanRadians);
1337                  x2 = cx - ((cy - y2)/tanRadians);
1338              }
1339              else
1340              {
1341                  if(rotation > 90 && rotation < 270)
1342                  {
1343                      x1 = w;
1344                      x2 = 0;
1345                  }
1346                  else
1347                  {
1348                      x1 = 0;
1349                      x2 = w;
1350                  }
1351                  y1 = ((tanRadians * (cx - x1)) - cy) * -1;
1352                  y2 = ((tanRadians * (cx - x2)) - cy) * -1;
1353              }
1354  
1355              x1 = Math.round(100 * x1/w);
1356              x2 = Math.round(100 * x2/w);
1357              y1 = Math.round(100 * y1/h);
1358              y2 = Math.round(100 * y2/h);
1359  
1360              //Set default value if not valid
1361              x1 = isNumber(x1) ? x1 : 0;
1362              x2 = isNumber(x2) ? x2 : 100;
1363              y1 = isNumber(y1) ? y1 : 0;
1364              y2 = isNumber(y2) ? y2 : 0;
1365  
1366              gradientNode.setAttribute("spreadMethod", "pad");
1367              gradientNode.setAttribute("width", w);
1368              gradientNode.setAttribute("height", h);
1369              gradientNode.setAttribute("x1", x1 + "%");
1370              gradientNode.setAttribute("x2", x2 + "%");
1371              gradientNode.setAttribute("y1", y1 + "%");
1372              gradientNode.setAttribute("y2", y2 + "%");
1373          }
1374          else
1375          {
1376              gradientNode.setAttribute("cx", (cx * 100) + "%");
1377              gradientNode.setAttribute("cy", (cy * 100) + "%");
1378              gradientNode.setAttribute("fx", (fx * 100) + "%");
1379              gradientNode.setAttribute("fy", (fy * 100) + "%");
1380              gradientNode.setAttribute("r", (r * 100) + "%");
1381          }
1382  
1383          len = stops.length;
1384          def = 0;
1385          for(i = 0; i < len; ++i)
1386          {
1387              if(this._stops && this._stops.length > 0)
1388              {
1389                  stopNode = this._stops.shift();
1390                  newStop = false;
1391              }
1392              else
1393              {
1394                  stopNode = graphic._createGraphicNode("stop");
1395                  newStop = true;
1396              }
1397              stop = stops[i];
1398              opacity = stop.opacity;
1399              color = stop.color;
1400              offset = stop.offset || i/(len - 1);
1401              offset = Math.round(offset * 100) + "%";
1402              opacity = isNumber(opacity) ? opacity : 1;
1403              opacity = Math.max(0, Math.min(1, opacity));
1404              def = (i + 1) / len;
1405              stopNode.setAttribute("offset", offset);
1406              stopNode.setAttribute("stop-color", color);
1407              stopNode.setAttribute("stop-opacity", opacity);
1408              if(newStop)
1409              {
1410                  gradientNode.appendChild(stopNode);
1411              }
1412              stopNodes.push(stopNode);
1413          }
1414          while(this._stops && this._stops.length > 0)
1415          {
1416              gradientNode.removeChild(this._stops.shift());
1417          }
1418          this._stops = stopNodes;
1419      },
1420  
1421      _stops: null,
1422  
1423      /**
1424       * Sets the value of an attribute.
1425       *
1426       * @method set
1427       * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can
1428       * be passed in to set multiple attributes at once.
1429       * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as
1430       * the name param.
1431       */
1432      set: function()
1433      {
1434          var host = this;
1435          AttributeLite.prototype.set.apply(host, arguments);
1436          if(host.initialized)
1437          {
1438              host._updateHandler();
1439          }
1440      },
1441  
1442      /**
1443       * Specifies a 2d translation.
1444       *
1445       * @method translate
1446       * @param {Number} x The value to transate on the x-axis.
1447       * @param {Number} y The value to translate on the y-axis.
1448       */
1449      translate: function()
1450      {
1451          this._addTransform("translate", arguments);
1452      },
1453  
1454      /**
1455       * Translates the shape along the x-axis. When translating x and y coordinates,
1456       * use the `translate` method.
1457       *
1458       * @method translateX
1459       * @param {Number} x The value to translate.
1460       */
1461      translateX: function()
1462      {
1463          this._addTransform("translateX", arguments);
1464      },
1465  
1466      /**
1467       * Translates the shape along the y-axis. When translating x and y coordinates,
1468       * use the `translate` method.
1469       *
1470       * @method translateY
1471       * @param {Number} y The value to translate.
1472       */
1473      translateY: function()
1474      {
1475          this._addTransform("translateY", arguments);
1476      },
1477  
1478      /**
1479       * Skews the shape around the x-axis and y-axis.
1480       *
1481       * @method skew
1482       * @param {Number} x The value to skew on the x-axis.
1483       * @param {Number} y The value to skew on the y-axis.
1484       */
1485      skew: function()
1486      {
1487          this._addTransform("skew", arguments);
1488      },
1489  
1490      /**
1491       * Skews the shape around the x-axis.
1492       *
1493       * @method skewX
1494       * @param {Number} x x-coordinate
1495       */
1496      skewX: function()
1497      {
1498          this._addTransform("skewX", arguments);
1499      },
1500  
1501      /**
1502       * Skews the shape around the y-axis.
1503       *
1504       * @method skewY
1505       * @param {Number} y y-coordinate
1506       */
1507      skewY: function()
1508      {
1509          this._addTransform("skewY", arguments);
1510      },
1511  
1512      /**
1513       * Rotates the shape clockwise around it transformOrigin.
1514       *
1515       * @method rotate
1516       * @param {Number} deg The degree of the rotation.
1517       */
1518      rotate: function()
1519      {
1520          this._addTransform("rotate", arguments);
1521      },
1522  
1523      /**
1524       * Specifies a 2d scaling operation.
1525       *
1526       * @method scale
1527       * @param {Number} val
1528       */
1529      scale: function()
1530      {
1531          this._addTransform("scale", arguments);
1532      },
1533  
1534      /**
1535       * Adds a transform to the shape.
1536       *
1537       * @method _addTransform
1538       * @param {String} type The transform being applied.
1539       * @param {Array} args The arguments for the transform.
1540       * @private
1541       */
1542      _addTransform: function(type, args)
1543      {
1544          args = Y.Array(args);
1545          this._transform = Y_LANG.trim(this._transform + " " + type + "(" + args.join(", ") + ")");
1546          args.unshift(type);
1547          this._transforms.push(args);
1548          if(this.initialized)
1549          {
1550              this._updateTransform();
1551          }
1552      },
1553  
1554      /**
1555       * Applies all transforms.
1556       *
1557       * @method _updateTransform
1558       * @private
1559       */
1560      _updateTransform: function()
1561      {
1562          var isPath = this._type === "path",
1563              node = this.node,
1564              key,
1565              transform,
1566              transformOrigin,
1567              x,
1568              y,
1569              tx,
1570              ty,
1571              matrix = this.matrix,
1572              normalizedMatrix = this._normalizedMatrix,
1573              i,
1574              len = this._transforms.length;
1575  
1576          if(isPath || (this._transforms && this._transforms.length > 0))
1577          {
1578              x = this._x;
1579              y = this._y;
1580              transformOrigin = this.get("transformOrigin");
1581              tx = x + (transformOrigin[0] * this.get("width"));
1582              ty = y + (transformOrigin[1] * this.get("height"));
1583              //need to use translate for x/y coords
1584              if(isPath)
1585              {
1586                  //adjust origin for custom shapes
1587                  if(!(this instanceof Y.SVGPath))
1588                  {
1589                      tx = this._left + (transformOrigin[0] * this.get("width"));
1590                      ty = this._top + (transformOrigin[1] * this.get("height"));
1591                  }
1592                  normalizedMatrix.init({dx: x + this._left, dy: y + this._top});
1593              }
1594              normalizedMatrix.translate(tx, ty);
1595              for(i = 0; i < len; ++i)
1596              {
1597                  key = this._transforms[i].shift();
1598                  if(key)
1599                  {
1600                      normalizedMatrix[key].apply(normalizedMatrix, this._transforms[i]);
1601                      matrix[key].apply(matrix, this._transforms[i]);
1602                  }
1603                  if(isPath)
1604                  {
1605                      this._transforms[i].unshift(key);
1606                  }
1607              }
1608              normalizedMatrix.translate(-tx, -ty);
1609              transform = "matrix(" + normalizedMatrix.a + "," +
1610                              normalizedMatrix.b + "," +
1611                              normalizedMatrix.c + "," +
1612                              normalizedMatrix.d + "," +
1613                              normalizedMatrix.dx + "," +
1614                              normalizedMatrix.dy + ")";
1615          }
1616          this._graphic.addToRedrawQueue(this);
1617          if(transform)
1618          {
1619              node.setAttribute("transform", transform);
1620          }
1621          if(!isPath)
1622          {
1623              this._transforms = [];
1624          }
1625      },
1626  
1627      /**
1628       * Draws the shape.
1629       *
1630       * @method _draw
1631       * @private
1632       */
1633      _draw: function()
1634      {
1635          var node = this.node;
1636          node.setAttribute("width", this.get("width"));
1637          node.setAttribute("height", this.get("height"));
1638          node.setAttribute("x", this._x);
1639          node.setAttribute("y", this._y);
1640          node.style.left = this._x + "px";
1641          node.style.top = this._y + "px";
1642          this._fillChangeHandler();
1643          this._strokeChangeHandler();
1644          this._updateTransform();
1645      },
1646  
1647      /**
1648       * Updates `Shape` based on attribute changes.
1649       *
1650       * @method _updateHandler
1651       * @private
1652       */
1653      _updateHandler: function()
1654      {
1655          this._draw();
1656      },
1657  
1658      /**
1659       * Storage for the transform attribute.
1660       *
1661       * @property _transform
1662       * @type String
1663       * @private
1664       */
1665      _transform: "",
1666  
1667      /**
1668       * Returns the bounds for a shape.
1669       *
1670       * Calculates the a new bounding box from the original corner coordinates (base on size and position) and the transform matrix.
1671       * The calculated bounding box is used by the graphic instance to calculate its viewBox.
1672       *
1673       * @method getBounds
1674       * @return Object
1675       */
1676      getBounds: function()
1677      {
1678          var type = this._type,
1679              stroke = this.get("stroke"),
1680              w = this.get("width"),
1681              h = this.get("height"),
1682              x = type === "path" ? 0 : this._x,
1683              y = type === "path" ? 0 : this._y,
1684              wt = 0;
1685          if(stroke && stroke.weight)
1686          {
1687              wt = stroke.weight;
1688              w = (x + w + wt) - (x - wt);
1689              h = (y + h + wt) - (y - wt);
1690              x -= wt;
1691              y -= wt;
1692          }
1693          return this._normalizedMatrix.getContentRect(w, h, x, y);
1694      },
1695  
1696      /**
1697       * Places the shape above all other shapes.
1698       *
1699       * @method toFront
1700       */
1701      toFront: function()
1702      {
1703          var graphic = this.get("graphic");
1704          if(graphic)
1705          {
1706              graphic._toFront(this);
1707          }
1708      },
1709  
1710      /**
1711       * Places the shape underneath all other shapes.
1712       *
1713       * @method toFront
1714       */
1715      toBack: function()
1716      {
1717          var graphic = this.get("graphic");
1718          if(graphic)
1719          {
1720              graphic._toBack(this);
1721          }
1722      },
1723  
1724      /**
1725       * Parses path data string and call mapped methods.
1726       *
1727       * @method _parsePathData
1728       * @param {String} val The path data
1729       * @private
1730       */
1731      _parsePathData: function(val)
1732      {
1733          var method,
1734              methodSymbol,
1735              args,
1736              commandArray = Y.Lang.trim(val.match(SPLITPATHPATTERN)),
1737              i,
1738              len,
1739              str,
1740              symbolToMethod = this._pathSymbolToMethod;
1741          if(commandArray)
1742          {
1743              this.clear();
1744              len = commandArray.length || 0;
1745              for(i = 0; i < len; i = i + 1)
1746              {
1747                  str = commandArray[i];
1748                  methodSymbol = str.substr(0, 1);
1749                  args = str.substr(1).match(SPLITARGSPATTERN);
1750                  method = symbolToMethod[methodSymbol];
1751                  if(method)
1752                  {
1753                      if(args)
1754                      {
1755                          this[method].apply(this, args);
1756                      }
1757                      else
1758                      {
1759                          this[method].apply(this);
1760                      }
1761                  }
1762              }
1763              this.end();
1764          }
1765      },
1766  
1767      /**
1768       * Destroys the shape instance.
1769       *
1770       * @method destroy
1771       */
1772      destroy: function()
1773      {
1774          var graphic = this.get("graphic");
1775          if(graphic)
1776          {
1777              graphic.removeShape(this);
1778          }
1779          else
1780          {
1781              this._destroy();
1782          }
1783      },
1784  
1785      /**
1786       *  Implementation for shape destruction
1787       *
1788       *  @method destroy
1789       *  @protected
1790       */
1791      _destroy: function()
1792      {
1793          if(this.node)
1794          {
1795              Y.Event.purgeElement(this.node, true);
1796              if(this.node.parentNode)
1797              {
1798                  this.node.parentNode.removeChild(this.node);
1799              }
1800              this.node = null;
1801          }
1802      }
1803   }, Y.SVGDrawing.prototype));
1804  
1805  SVGShape.ATTRS = {
1806      /**
1807       * An array of x, y values which indicates the transformOrigin in which to rotate the shape. Valid values range between 0 and 1 representing a
1808       * fraction of the shape's corresponding bounding box dimension. The default value is [0.5, 0.5].
1809       *
1810       * @config transformOrigin
1811       * @type Array
1812       */
1813      transformOrigin: {
1814          valueFn: function()
1815          {
1816              return [0.5, 0.5];
1817          }
1818      },
1819  
1820      /**
1821       * <p>A string containing, in order, transform operations applied to the shape instance. The `transform` string can contain the following values:
1822       *
1823       *    <dl>
1824       *        <dt>rotate</dt><dd>Rotates the shape clockwise around it transformOrigin.</dd>
1825       *        <dt>translate</dt><dd>Specifies a 2d translation.</dd>
1826       *        <dt>skew</dt><dd>Skews the shape around the x-axis and y-axis.</dd>
1827       *        <dt>scale</dt><dd>Specifies a 2d scaling operation.</dd>
1828       *        <dt>translateX</dt><dd>Translates the shape along the x-axis.</dd>
1829       *        <dt>translateY</dt><dd>Translates the shape along the y-axis.</dd>
1830       *        <dt>skewX</dt><dd>Skews the shape around the x-axis.</dd>
1831       *        <dt>skewY</dt><dd>Skews the shape around the y-axis.</dd>
1832       *        <dt>matrix</dt><dd>Specifies a 2D transformation matrix comprised of the specified six values.</dd>
1833       *    </dl>
1834       * </p>
1835       * <p>Applying transforms through the transform attribute will reset the transform matrix and apply a new transform. The shape class also contains
1836       * corresponding methods for each transform that will apply the transform to the current matrix. The below code illustrates how you might use the
1837       * `transform` attribute to instantiate a recangle with a rotation of 45 degrees.</p>
1838              var myRect = new Y.Rect({
1839                  type:"rect",
1840                  width: 50,
1841                  height: 40,
1842                  transform: "rotate(45)"
1843              };
1844       * <p>The code below would apply `translate` and `rotate` to an existing shape.</p>
1845  
1846          myRect.set("transform", "translate(40, 50) rotate(45)");
1847       * @config transform
1848       * @type String
1849       */
1850      transform: {
1851          setter: function(val)
1852          {
1853              this.matrix.init();
1854              this._normalizedMatrix.init();
1855              this._transforms = this.matrix.getTransformArray(val);
1856              this._transform = val;
1857              return val;
1858          },
1859  
1860          getter: function()
1861          {
1862              return this._transform;
1863          }
1864      },
1865  
1866      /**
1867       * Unique id for class instance.
1868       *
1869       * @config id
1870       * @type String
1871       */
1872      id: {
1873          valueFn: function()
1874          {
1875              return Y.guid();
1876          },
1877  
1878          setter: function(val)
1879          {
1880              var node = this.node;
1881              if(node)
1882              {
1883                  node.setAttribute("id", val);
1884              }
1885              return val;
1886          }
1887      },
1888  
1889      /**
1890       * Indicates the x position of shape.
1891       *
1892       * @config x
1893       * @type Number
1894       */
1895      x: {
1896          getter: function()
1897          {
1898              return this._x;
1899          },
1900  
1901          setter: function(val)
1902          {
1903              var transform = this.get("transform");
1904              this._x = val;
1905              if(transform)
1906              {
1907                  this.set("transform", transform);
1908              }
1909          }
1910      },
1911  
1912      /**
1913       * Indicates the y position of shape.
1914       *
1915       * @config y
1916       * @type Number
1917       */
1918      y: {
1919          getter: function()
1920          {
1921              return this._y;
1922          },
1923  
1924          setter: function(val)
1925          {
1926              var transform = this.get("transform");
1927              this._y = val;
1928              if(transform)
1929              {
1930                  this.set("transform", transform);
1931              }
1932          }
1933      },
1934  
1935      /**
1936       * Indicates the width of the shape
1937       *
1938       * @config width
1939       * @type Number
1940       */
1941      width: {
1942          value: 0
1943      },
1944  
1945      /**
1946       * Indicates the height of the shape
1947       *
1948       * @config height
1949       * @type Number
1950       */
1951      height: {
1952          value: 0
1953      },
1954  
1955      /**
1956       * Indicates whether the shape is visible.
1957       *
1958       * @config visible
1959       * @type Boolean
1960       */
1961      visible: {
1962          value: true,
1963  
1964          setter: function(val){
1965              var visibility = val ? "visible" : "hidden";
1966              if(this.node)
1967              {
1968                  this.node.style.visibility = visibility;
1969              }
1970              return val;
1971          }
1972      },
1973  
1974      /**
1975       * Only implemented in SVG implementation.
1976       * Applies the SVG shape-rendering attribute to the shape.
1977       *  <dl>
1978       *      <dt>auto</dt>
1979       *      <dd>Indicates that the user agent shall make appropriate tradeoffs to balance speed,
1980       *      crisp edges and geometric precision, but with geometric precision given more importance than speed and crisp edges.</dd>
1981       *      <dt>optimizeSpeed</dt>
1982       *      <dd>Indicates that the user agent shall emphasize rendering speed over geometric precision and crisp edges.
1983       *      This option will sometimes cause the user agent to turn off shape anti-aliasing.</dd>
1984       *      <dt>crispEdges</dt>
1985       *      <dd>Indicates that the user agent shall attempt to emphasize the contrast between clean edges of artwork over rendering
1986       *      speed and geometric precision. To achieve crisp edges, the user agent might turn off anti-aliasing for all lines and curves
1987       *      or possibly just for straight lines which are close to vertical or horizontal. Also, the user agent might adjust line
1988       *      positions and line widths to align edges with device pixels.</dd>
1989       *      <dt>geometricPrecision</dt>
1990       *      <dd>Indicates that the user agent shall emphasize geometric precision over speed and crisp edges.</dd>
1991       *  </dl>
1992       *
1993       *  @config shapeRendering
1994       *  @type String
1995       */
1996      shapeRendering: {
1997          value: "auto",
1998  
1999          setter: function(val) {
2000              if(this.node)
2001              {
2002                  Y.DOM.setAttribute(this.node, "shape-rendering", val);
2003              }
2004              return val;
2005          }
2006      },
2007  
2008  
2009      /**
2010       * Contains information about the fill of the shape.
2011       *  <dl>
2012       *      <dt>color</dt><dd>The color of the fill.</dd>
2013       *      <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the fill. The default value is 1.</dd>
2014       *      <dt>type</dt><dd>Type of fill.
2015       *          <dl>
2016       *              <dt>solid</dt><dd>Solid single color fill. (default)</dd>
2017       *              <dt>linear</dt><dd>Linear gradient fill.</dd>
2018       *              <dt>radial</dt><dd>Radial gradient fill.</dd>
2019       *          </dl>
2020       *      </dd>
2021       *  </dl>
2022       *  <p>If a `linear` or `radial` is specified as the fill type. The following additional property is used:
2023       *  <dl>
2024       *      <dt>stops</dt><dd>An array of objects containing the following properties:
2025       *          <dl>
2026       *              <dt>color</dt><dd>The color of the stop.</dd>
2027       *              <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the stop. The default value is 1.
2028       *              Note: No effect for IE 6 - 8</dd>
2029       *              <dt>offset</dt><dd>Number between 0 and 1 indicating where the color stop is positioned.</dd>
2030       *          </dl>
2031       *      </dd>
2032       *      <p>Linear gradients also have the following property:</p>
2033       *      <dt>rotation</dt><dd>Linear gradients flow left to right by default. The rotation property allows you to change the
2034       *      flow by rotation. (e.g. A rotation of 180 would make the gradient pain from right to left.)</dd>
2035       *      <p>Radial gradients have the following additional properties:</p>
2036       *      <dt>r</dt><dd>Radius of the gradient circle.</dd>
2037       *      <dt>fx</dt><dd>Focal point x-coordinate of the gradient.</dd>
2038       *      <dt>fy</dt><dd>Focal point y-coordinate of the gradient.</dd>
2039       *      <dt>cx</dt><dd>
2040       *          <p>The x-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
2041       *          <p><strong>Note: </strong>Currently, this property is not implemented for corresponding `CanvasShape` and
2042       *          `VMLShape` classes which are used on Android or IE 6 - 8.</p>
2043       *      </dd>
2044       *      <dt>cy</dt><dd>
2045       *          <p>The y-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
2046       *          <p><strong>Note: </strong>Currently, this property is not implemented for corresponding `CanvasShape` and `VMLShape`
2047       *          classes which are used on Android or IE 6 - 8.</p>
2048       *      </dd>
2049       *  </dl>
2050       *
2051       * @config fill
2052       * @type Object
2053       */
2054      fill: {
2055          valueFn: "_getDefaultFill",
2056  
2057          setter: function(val)
2058          {
2059              var fill,
2060                  tmpl = this.get("fill") || this._getDefaultFill();
2061              fill = (val) ? Y.merge(tmpl, val) : null;
2062              if(fill && fill.color)
2063              {
2064                  if(fill.color === undefined || fill.color === "none")
2065                  {
2066                      fill.color = null;
2067                  }
2068              }
2069              return fill;
2070          }
2071      },
2072  
2073      /**
2074       * Contains information about the stroke of the shape.
2075       *  <dl>
2076       *      <dt>color</dt><dd>The color of the stroke.</dd>
2077       *      <dt>weight</dt><dd>Number that indicates the width of the stroke.</dd>
2078       *      <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the stroke. The default value is 1.</dd>
2079       *      <dt>dashstyle</dt>Indicates whether to draw a dashed stroke. When set to "none", a solid stroke is drawn. When set
2080       *      to an array, the first index indicates the length of the dash. The second index indicates the length of gap.
2081       *      <dt>linecap</dt><dd>Specifies the linecap for the stroke. The following values can be specified:
2082       *          <dl>
2083       *              <dt>butt (default)</dt><dd>Specifies a butt linecap.</dd>
2084       *              <dt>square</dt><dd>Specifies a sqare linecap.</dd>
2085       *              <dt>round</dt><dd>Specifies a round linecap.</dd>
2086       *          </dl>
2087       *      </dd>
2088       *      <dt>linejoin</dt><dd>Specifies a linejoin for the stroke. The following values can be specified:
2089       *          <dl>
2090       *              <dt>round (default)</dt><dd>Specifies that the linejoin will be round.</dd>
2091       *              <dt>bevel</dt><dd>Specifies a bevel for the linejoin.</dd>
2092       *              <dt>miter limit</dt><dd>An integer specifying the miter limit of a miter linejoin. If you want to specify a linejoin
2093       *              of miter, you simply specify the limit as opposed to having separate miter and miter limit values.</dd>
2094       *          </dl>
2095       *      </dd>
2096       *  </dl>
2097       *
2098       * @config stroke
2099       * @type Object
2100       */
2101      stroke: {
2102          valueFn: "_getDefaultStroke",
2103  
2104          setter: function(val)
2105          {
2106              var tmpl = this.get("stroke") || this._getDefaultStroke(),
2107                  wt;
2108              if(val && val.hasOwnProperty("weight"))
2109              {
2110                  wt = parseInt(val.weight, 10);
2111                  if(!isNaN(wt))
2112                  {
2113                      val.weight = wt;
2114                  }
2115              }
2116              return (val) ? Y.merge(tmpl, val) : null;
2117          }
2118      },
2119  
2120      // Only implemented in SVG
2121      // Determines whether the instance will receive mouse events.
2122      //
2123      // @config pointerEvents
2124      // @type string
2125      //
2126      pointerEvents: {
2127          valueFn: function()
2128          {
2129              var val = "visiblePainted",
2130                  node = this.node;
2131              if(node)
2132              {
2133                  node.setAttribute("pointer-events", val);
2134              }
2135              return val;
2136          },
2137  
2138          setter: function(val)
2139          {
2140              var node = this.node;
2141              if(node)
2142              {
2143                  node.setAttribute("pointer-events", val);
2144              }
2145              return val;
2146          }
2147      },
2148  
2149      /**
2150       * Dom node for the shape.
2151       *
2152       * @config node
2153       * @type HTMLElement
2154       * @readOnly
2155       */
2156      node: {
2157          readOnly: true,
2158  
2159          getter: function()
2160          {
2161              return this.node;
2162          }
2163      },
2164  
2165      /**
2166       * Represents an SVG Path string. This will be parsed and added to shape's API to represent the SVG data across all
2167       * implementations. Note that when using VML or SVG implementations, part of this content will be added to the DOM using
2168       * respective VML/SVG attributes. If your content comes from an untrusted source, you will need to ensure that no
2169       * malicious code is included in that content.
2170       *
2171       * @config data
2172       * @type String
2173       */
2174      data: {
2175          setter: function(val)
2176          {
2177              if(this.get("node"))
2178              {
2179                  this._parsePathData(val);
2180              }
2181              return val;
2182          }
2183      },
2184  
2185      /**
2186       * Reference to the parent graphic instance
2187       *
2188       * @config graphic
2189       * @type SVGGraphic
2190       * @readOnly
2191       */
2192      graphic: {
2193          readOnly: true,
2194  
2195          getter: function()
2196          {
2197              return this._graphic;
2198          }
2199      }
2200  };
2201  Y.SVGShape = SVGShape;
2202  
2203  /**
2204   * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Path.html">`Path`</a> class.
2205   * `SVGPath` is not intended to be used directly. Instead, use the <a href="Path.html">`Path`</a> class.
2206   * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Path.html">`Path`</a>
2207   * class will point to the `SVGPath` class.
2208   *
2209   * @module graphics
2210   * @class SVGPath
2211   * @extends SVGShape
2212   * @constructor
2213   */
2214  SVGPath = function()
2215  {
2216      SVGPath.superclass.constructor.apply(this, arguments);
2217  };
2218  SVGPath.NAME = "path";
2219  Y.extend(SVGPath, Y.SVGShape, {
2220      /**
2221       * Left edge of the path
2222       *
2223       * @property _left
2224       * @type Number
2225       * @private
2226       */
2227      _left: 0,
2228  
2229      /**
2230       * Right edge of the path
2231       *
2232       * @property _right
2233       * @type Number
2234       * @private
2235       */
2236      _right: 0,
2237  
2238      /**
2239       * Top edge of the path
2240       *
2241       * @property _top
2242       * @type Number
2243       * @private
2244       */
2245      _top: 0,
2246  
2247      /**
2248       * Bottom edge of the path
2249       *
2250       * @property _bottom
2251       * @type Number
2252       * @private
2253       */
2254      _bottom: 0,
2255  
2256      /**
2257       * Indicates the type of shape
2258       *
2259       * @property _type
2260       * @readOnly
2261       * @type String
2262       * @private
2263       */
2264      _type: "path",
2265  
2266      /**
2267       * Storage for path
2268       *
2269       * @property _path
2270       * @type String
2271       * @private
2272       */
2273      _path: ""
2274  });
2275  
2276  SVGPath.ATTRS = Y.merge(Y.SVGShape.ATTRS, {
2277      /**
2278       * Indicates the path used for the node.
2279       *
2280       * @config path
2281       * @type String
2282       * @readOnly
2283       */
2284      path: {
2285          readOnly: true,
2286  
2287          getter: function()
2288          {
2289              return this._path;
2290          }
2291      },
2292  
2293      /**
2294       * Indicates the width of the shape
2295       *
2296       * @config width
2297       * @type Number
2298       */
2299      width: {
2300          getter: function()
2301          {
2302              var val = Math.max(this._right - this._left, 0);
2303              return val;
2304          }
2305      },
2306  
2307      /**
2308       * Indicates the height of the shape
2309       *
2310       * @config height
2311       * @type Number
2312       */
2313      height: {
2314          getter: function()
2315          {
2316              return Math.max(this._bottom - this._top, 0);
2317          }
2318      }
2319  });
2320  Y.SVGPath = SVGPath;
2321  /**
2322   * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Rect.html">`Rect`</a> class.
2323   * `SVGRect` is not intended to be used directly. Instead, use the <a href="Rect.html">`Rect`</a> class.
2324   * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Rect.html">`Rect`</a>
2325   * class will point to the `SVGRect` class.
2326   *
2327   * @module graphics
2328   * @class SVGRect
2329   * @constructor
2330   */
2331  SVGRect = function()
2332  {
2333      SVGRect.superclass.constructor.apply(this, arguments);
2334  };
2335  SVGRect.NAME = "rect";
2336  Y.extend(SVGRect, Y.SVGShape, {
2337      /**
2338       * Indicates the type of shape
2339       *
2340       * @property _type
2341       * @type String
2342       * @private
2343       */
2344      _type: "rect"
2345   });
2346  SVGRect.ATTRS = Y.SVGShape.ATTRS;
2347  Y.SVGRect = SVGRect;
2348  /**
2349   * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Ellipse.html">`Ellipse`</a> class.
2350   * `SVGEllipse` is not intended to be used directly. Instead, use the <a href="Ellipse.html">`Ellipse`</a> class.
2351   * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Ellipse.html">`Ellipse`</a>
2352   * class will point to the `SVGEllipse` class.
2353   *
2354   * @module graphics
2355   * @class SVGEllipse
2356   * @constructor
2357   */
2358  SVGEllipse = function()
2359  {
2360      SVGEllipse.superclass.constructor.apply(this, arguments);
2361  };
2362  
2363  SVGEllipse.NAME = "ellipse";
2364  
2365  Y.extend(SVGEllipse, SVGShape, {
2366      /**
2367       * Indicates the type of shape
2368       *
2369       * @property _type
2370       * @type String
2371       * @private
2372       */
2373      _type: "ellipse",
2374  
2375      /**
2376       * Updates the shape.
2377       *
2378       * @method _draw
2379       * @private
2380       */
2381      _draw: function()
2382      {
2383          var node = this.node,
2384              w = this.get("width"),
2385              h = this.get("height"),
2386              x = this.get("x"),
2387              y = this.get("y"),
2388              xRadius = w * 0.5,
2389              yRadius = h * 0.5,
2390              cx = x + xRadius,
2391              cy = y + yRadius;
2392          node.setAttribute("rx", xRadius);
2393          node.setAttribute("ry", yRadius);
2394          node.setAttribute("cx", cx);
2395          node.setAttribute("cy", cy);
2396          this._fillChangeHandler();
2397          this._strokeChangeHandler();
2398          this._updateTransform();
2399      }
2400  });
2401  
2402  SVGEllipse.ATTRS = Y.merge(SVGShape.ATTRS, {
2403      /**
2404       * Horizontal radius for the ellipse.
2405       *
2406       * @config xRadius
2407       * @type Number
2408       */
2409      xRadius: {
2410          setter: function(val)
2411          {
2412              this.set("width", val * 2);
2413          },
2414  
2415          getter: function()
2416          {
2417              var val = this.get("width");
2418              if(val)
2419              {
2420                  val *= 0.5;
2421              }
2422              return val;
2423          }
2424      },
2425  
2426      /**
2427       * Vertical radius for the ellipse.
2428       *
2429       * @config yRadius
2430       * @type Number
2431       * @readOnly
2432       */
2433      yRadius: {
2434          setter: function(val)
2435          {
2436              this.set("height", val * 2);
2437          },
2438  
2439          getter: function()
2440          {
2441              var val = this.get("height");
2442              if(val)
2443              {
2444                  val *= 0.5;
2445              }
2446              return val;
2447          }
2448      }
2449  });
2450  Y.SVGEllipse = SVGEllipse;
2451  /**
2452   * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Circle.html">`Circle`</a> class.
2453   * `SVGCircle` is not intended to be used directly. Instead, use the <a href="Circle.html">`Circle`</a> class.
2454   * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Circle.html">`Circle`</a>
2455   * class will point to the `SVGCircle` class.
2456   *
2457   * @module graphics
2458   * @class SVGCircle
2459   * @constructor
2460   */
2461   SVGCircle = function()
2462   {
2463      SVGCircle.superclass.constructor.apply(this, arguments);
2464   };
2465  
2466   SVGCircle.NAME = "circle";
2467  
2468   Y.extend(SVGCircle, Y.SVGShape, {
2469  
2470      /**
2471       * Indicates the type of shape
2472       *
2473       * @property _type
2474       * @type String
2475       * @private
2476       */
2477      _type: "circle",
2478  
2479      /**
2480       * Updates the shape.
2481       *
2482       * @method _draw
2483       * @private
2484       */
2485      _draw: function()
2486      {
2487          var node = this.node,
2488              x = this.get("x"),
2489              y = this.get("y"),
2490              radius = this.get("radius"),
2491              cx = x + radius,
2492              cy = y + radius;
2493          node.setAttribute("r", radius);
2494          node.setAttribute("cx", cx);
2495          node.setAttribute("cy", cy);
2496          this._fillChangeHandler();
2497          this._strokeChangeHandler();
2498          this._updateTransform();
2499      }
2500   });
2501  
2502  SVGCircle.ATTRS = Y.merge(Y.SVGShape.ATTRS, {
2503      /**
2504       * Indicates the width of the shape
2505       *
2506       * @config width
2507       * @type Number
2508       */
2509      width: {
2510          setter: function(val)
2511          {
2512              this.set("radius", val/2);
2513              return val;
2514          },
2515  
2516          getter: function()
2517          {
2518              return this.get("radius") * 2;
2519          }
2520      },
2521  
2522      /**
2523       * Indicates the height of the shape
2524       *
2525       * @config height
2526       * @type Number
2527       */
2528      height: {
2529          setter: function(val)
2530          {
2531              this.set("radius", val/2);
2532              return val;
2533          },
2534  
2535          getter: function()
2536          {
2537              return this.get("radius") * 2;
2538          }
2539      },
2540  
2541      /**
2542       * Radius of the circle
2543       *
2544       * @config radius
2545       * @type Number
2546       */
2547      radius: {
2548          value: 0
2549      }
2550  });
2551  Y.SVGCircle = SVGCircle;
2552  /**
2553   * Draws pie slices
2554   *
2555   * @module graphics
2556   * @class SVGPieSlice
2557   * @constructor
2558   */
2559  SVGPieSlice = function()
2560  {
2561      SVGPieSlice.superclass.constructor.apply(this, arguments);
2562  };
2563  SVGPieSlice.NAME = "svgPieSlice";
2564  Y.extend(SVGPieSlice, Y.SVGShape, Y.mix({
2565      /**
2566       * Indicates the type of shape
2567       *
2568       * @property _type
2569       * @type String
2570       * @private
2571       */
2572      _type: "path",
2573  
2574      /**
2575       * Change event listener
2576       *
2577       * @private
2578       * @method _updateHandler
2579       */
2580      _draw: function()
2581      {
2582          var x = this.get("cx"),
2583              y = this.get("cy"),
2584              startAngle = this.get("startAngle"),
2585              arc = this.get("arc"),
2586              radius = this.get("radius");
2587          this.clear();
2588          this.drawWedge(x, y, startAngle, arc, radius);
2589          this.end();
2590      }
2591   }, Y.SVGDrawing.prototype));
2592  SVGPieSlice.ATTRS = Y.mix({
2593      cx: {
2594          value: 0
2595      },
2596  
2597      cy: {
2598          value: 0
2599      },
2600      /**
2601       * Starting angle in relation to a circle in which to begin the pie slice drawing.
2602       *
2603       * @config startAngle
2604       * @type Number
2605       */
2606      startAngle: {
2607          value: 0
2608      },
2609  
2610      /**
2611       * Arc of the slice.
2612       *
2613       * @config arc
2614       * @type Number
2615       */
2616      arc: {
2617          value: 0
2618      },
2619  
2620      /**
2621       * Radius of the circle in which the pie slice is drawn
2622       *
2623       * @config radius
2624       * @type Number
2625       */
2626      radius: {
2627          value: 0
2628      }
2629  }, Y.SVGShape.ATTRS);
2630  Y.SVGPieSlice = SVGPieSlice;
2631  /**
2632   * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Graphic.html">`Graphic`</a> class.
2633   * `SVGGraphic` is not intended to be used directly. Instead, use the <a href="Graphic.html">`Graphic`</a> class.
2634   * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Graphic.html">`Graphic`</a>
2635   * class will point to the `SVGGraphic` class.
2636   *
2637   * @module graphics
2638   * @class SVGGraphic
2639   * @constructor
2640   */
2641  SVGGraphic = function() {
2642      SVGGraphic.superclass.constructor.apply(this, arguments);
2643  };
2644  
2645  SVGGraphic.NAME = "svgGraphic";
2646  
2647  SVGGraphic.ATTRS = {
2648      /**
2649       * Whether or not to render the `Graphic` automatically after to a specified parent node after init. This can be a Node
2650       * instance or a CSS selector string.
2651       *
2652       * @config render
2653       * @type Node | String
2654       */
2655      render: {},
2656  
2657      /**
2658       * Unique id for class instance.
2659       *
2660       * @config id
2661       * @type String
2662       */
2663      id: {
2664          valueFn: function()
2665          {
2666              return Y.guid();
2667          },
2668  
2669          setter: function(val)
2670          {
2671              var node = this._node;
2672              if(node)
2673              {
2674                  node.setAttribute("id", val);
2675              }
2676              return val;
2677          }
2678      },
2679  
2680      /**
2681       * Key value pairs in which a shape instance is associated with its id.
2682       *
2683       *  @config shapes
2684       *  @type Object
2685       *  @readOnly
2686       */
2687      shapes: {
2688          readOnly: true,
2689  
2690          getter: function()
2691          {
2692              return this._shapes;
2693          }
2694      },
2695  
2696      /**
2697       *  Object containing size and coordinate data for the content of a Graphic in relation to the coordSpace node.
2698       *
2699       *  @config contentBounds
2700       *  @type Object
2701       *  @readOnly
2702       */
2703      contentBounds: {
2704          readOnly: true,
2705  
2706          getter: function()
2707          {
2708              return this._contentBounds;
2709          }
2710      },
2711  
2712      /**
2713       *  The html element that represents to coordinate system of the Graphic instance.
2714       *
2715       *  @config node
2716       *  @type HTMLElement
2717       *  @readOnly
2718       */
2719      node: {
2720          readOnly: true,
2721  
2722          getter: function()
2723          {
2724              return this._node;
2725          }
2726      },
2727  
2728      /**
2729       * Indicates the width of the `Graphic`.
2730       *
2731       * @config width
2732       * @type Number
2733       */
2734      width: {
2735          setter: function(val)
2736          {
2737              if(this._node)
2738              {
2739                  this._node.style.width = val + "px";
2740              }
2741              return val;
2742          }
2743      },
2744  
2745      /**
2746       * Indicates the height of the `Graphic`.
2747       *
2748       * @config height
2749       * @type Number
2750       */
2751      height: {
2752          setter: function(val)
2753          {
2754              if(this._node)
2755              {
2756                  this._node.style.height = val  + "px";
2757              }
2758              return val;
2759          }
2760      },
2761  
2762      /**
2763       *  Determines the sizing of the Graphic.
2764       *
2765       *  <dl>
2766       *      <dt>sizeContentToGraphic</dt><dd>The Graphic's width and height attributes are, either explicitly set through the
2767       *      <code>width</code> and <code>height</code> attributes or are determined by the dimensions of the parent element. The
2768       *      content contained in the Graphic will be sized to fit with in the Graphic instance's dimensions. When using this
2769       *      setting, the <code>preserveAspectRatio</code> attribute will determine how the contents are sized.</dd>
2770       *      <dt>sizeGraphicToContent</dt><dd>(Also accepts a value of true) The Graphic's width and height are determined by the
2771       *      size and positioning of the content.</dd>
2772       *      <dt>false</dt><dd>The Graphic's width and height attributes are, either explicitly set through the <code>width</code>
2773       *      and <code>height</code> attributes or are determined by the dimensions of the parent element. The contents of the
2774       *      Graphic instance are not affected by this setting.</dd>
2775       *  </dl>
2776       *
2777       *
2778       *  @config autoSize
2779       *  @type Boolean | String
2780       *  @default false
2781       */
2782      autoSize: {
2783          value: false
2784      },
2785  
2786      /**
2787       * Determines how content is sized when <code>autoSize</code> is set to <code>sizeContentToGraphic</code>.
2788       *
2789       *  <dl>
2790       *      <dt>none<dt><dd>Do not force uniform scaling. Scale the graphic content of the given element non-uniformly if necessary
2791       *      such that the element's bounding box exactly matches the viewport rectangle.</dd>
2792       *      <dt>xMinYMin</dt><dd>Force uniform scaling position along the top left of the Graphic's node.</dd>
2793       *      <dt>xMidYMin</dt><dd>Force uniform scaling horizontally centered and positioned at the top of the Graphic's node.<dd>
2794       *      <dt>xMaxYMin</dt><dd>Force uniform scaling positioned horizontally from the right and vertically from the top.</dd>
2795       *      <dt>xMinYMid</dt>Force uniform scaling positioned horizontally from the left and vertically centered.</dd>
2796       *      <dt>xMidYMid (the default)</dt><dd>Force uniform scaling with the content centered.</dd>
2797       *      <dt>xMaxYMid</dt><dd>Force uniform scaling positioned horizontally from the right and vertically centered.</dd>
2798       *      <dt>xMinYMax</dt><dd>Force uniform scaling positioned horizontally from the left and vertically from the bottom.</dd>
2799       *      <dt>xMidYMax</dt><dd>Force uniform scaling horizontally centered and position vertically from the bottom.</dd>
2800       *      <dt>xMaxYMax</dt><dd>Force uniform scaling positioned horizontally from the right and vertically from the bottom.</dd>
2801       *  </dl>
2802       *
2803       * @config preserveAspectRatio
2804       * @type String
2805       * @default xMidYMid
2806       */
2807      preserveAspectRatio: {
2808          value: "xMidYMid"
2809      },
2810  
2811      /**
2812       * The contentBounds will resize to greater values but not to smaller values. (for performance)
2813       * When resizing the contentBounds down is desirable, set the resizeDown value to true.
2814       *
2815       * @config resizeDown
2816       * @type Boolean
2817       */
2818      resizeDown: {
2819          value: false
2820      },
2821  
2822      /**
2823       * Indicates the x-coordinate for the instance.
2824       *
2825       * @config x
2826       * @type Number
2827       */
2828      x: {
2829          getter: function()
2830          {
2831              return this._x;
2832          },
2833  
2834          setter: function(val)
2835          {
2836              this._x = val;
2837              if(this._node)
2838              {
2839                  this._node.style.left = val + "px";
2840              }
2841              return val;
2842          }
2843      },
2844  
2845      /**
2846       * Indicates the y-coordinate for the instance.
2847       *
2848       * @config y
2849       * @type Number
2850       */
2851      y: {
2852          getter: function()
2853          {
2854              return this._y;
2855          },
2856  
2857          setter: function(val)
2858          {
2859              this._y = val;
2860              if(this._node)
2861              {
2862                  this._node.style.top = val + "px";
2863              }
2864              return val;
2865          }
2866      },
2867  
2868      /**
2869       * Indicates whether or not the instance will automatically redraw after a change is made to a shape.
2870       * This property will get set to false when batching operations.
2871       *
2872       * @config autoDraw
2873       * @type Boolean
2874       * @default true
2875       * @private
2876       */
2877      autoDraw: {
2878          value: true
2879      },
2880  
2881      visible: {
2882          value: true,
2883  
2884          setter: function(val)
2885          {
2886              this._toggleVisible(val);
2887              return val;
2888          }
2889      },
2890  
2891      //
2892      //  Indicates the pointer-events setting for the svg:svg element.
2893      //
2894      //  @config pointerEvents
2895      //  @type String
2896      //
2897      pointerEvents: {
2898          value: "none"
2899      }
2900  };
2901  
2902  Y.extend(SVGGraphic, Y.GraphicBase, {
2903      /**
2904       * Sets the value of an attribute.
2905       *
2906       * @method set
2907       * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can
2908       * be passed in to set multiple attributes at once.
2909       * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as
2910       * the name param.
2911       */
2912      set: function()
2913      {
2914          var host = this,
2915              attr = arguments[0],
2916              redrawAttrs = {
2917                  autoDraw: true,
2918                  autoSize: true,
2919                  preserveAspectRatio: true,
2920                  resizeDown: true
2921              },
2922              key,
2923              forceRedraw = false;
2924          AttributeLite.prototype.set.apply(host, arguments);
2925          if(host._state.autoDraw === true && Y.Object.size(this._shapes) > 0)
2926          {
2927              if(Y_LANG.isString && redrawAttrs[attr])
2928              {
2929                  forceRedraw = true;
2930              }
2931              else if(Y_LANG.isObject(attr))
2932              {
2933                  for(key in redrawAttrs)
2934                  {
2935                      if(redrawAttrs.hasOwnProperty(key) && attr[key])
2936                      {
2937                          forceRedraw = true;
2938                          break;
2939                      }
2940                  }
2941              }
2942          }
2943          if(forceRedraw)
2944          {
2945              host._redraw();
2946          }
2947      },
2948  
2949      /**
2950       * Storage for `x` attribute.
2951       *
2952       * @property _x
2953       * @type Number
2954       * @private
2955       */
2956      _x: 0,
2957  
2958      /**
2959       * Storage for `y` attribute.
2960       *
2961       * @property _y
2962       * @type Number
2963       * @private
2964       */
2965      _y: 0,
2966  
2967      /**
2968       * Gets the current position of the graphic instance in page coordinates.
2969       *
2970       * @method getXY
2971       * @return Array The XY position of the shape.
2972       */
2973      getXY: function()
2974      {
2975          var node = this._node,
2976              xy;
2977          if(node)
2978          {
2979              xy = Y.DOM.getXY(node);
2980          }
2981          return xy;
2982      },
2983  
2984      /**
2985       * Initializes the class.
2986       *
2987       * @method initializer
2988       * @private
2989       */
2990      initializer: function() {
2991          var render = this.get("render"),
2992              visibility = this.get("visible") ? "visible" : "hidden";
2993          this._shapes = {};
2994          this._contentBounds = {
2995              left: 0,
2996              top: 0,
2997              right: 0,
2998              bottom: 0
2999          };
3000          this._gradients = {};
3001          this._node = DOCUMENT.createElement('div');
3002          this._node.style.position = "absolute";
3003          this._node.style.left = this.get("x") + "px";
3004          this._node.style.top = this.get("y") + "px";
3005          this._node.style.visibility = visibility;
3006          this._contentNode = this._createGraphics();
3007          this._contentNode.style.visibility = visibility;
3008          this._contentNode.setAttribute("id", this.get("id"));
3009          this._node.appendChild(this._contentNode);
3010          if(render)
3011          {
3012              this.render(render);
3013          }
3014      },
3015  
3016      /**
3017       * Adds the graphics node to the dom.
3018       *
3019       * @method render
3020       * @param {HTMLElement} parentNode node in which to render the graphics node into.
3021       */
3022      render: function(render) {
3023          var parentNode = render || DOCUMENT.body,
3024              w,
3025              h;
3026          if(render instanceof Y.Node)
3027          {
3028              parentNode = render._node;
3029          }
3030          else if(Y.Lang.isString(render))
3031          {
3032              parentNode = Y.Selector.query(render, DOCUMENT.body, true);
3033          }
3034          w = this.get("width") || parseInt(Y.DOM.getComputedStyle(parentNode, "width"), 10);
3035          h = this.get("height") || parseInt(Y.DOM.getComputedStyle(parentNode, "height"), 10);
3036          parentNode.appendChild(this._node);
3037          this.set("width", w);
3038          this.set("height", h);
3039          return this;
3040      },
3041      
3042      /**
3043       * Removes all nodes.
3044       *
3045       * @method destroy
3046       */
3047      destroy: function()
3048      {
3049          this.removeAllShapes();
3050          if(this._contentNode)
3051          {
3052              this._removeChildren(this._contentNode);
3053              if(this._contentNode.parentNode)
3054              {
3055                  this._contentNode.parentNode.removeChild(this._contentNode);
3056              }
3057              this._contentNode = null;
3058          }
3059          if(this._node)
3060          {
3061              this._removeChildren(this._node);
3062              if(this._node.parentNode)
3063              {
3064                  this._node.parentNode.removeChild(this._node);
3065              }
3066              this._node = null;
3067          }
3068      },
3069  
3070      /**
3071       * Generates a shape instance by type.
3072       *
3073       * @method addShape
3074       * @param {Object} cfg attributes for the shape
3075       * @return Shape
3076       */
3077      addShape: function(cfg)
3078      {
3079          cfg.graphic = this;
3080          if(!this.get("visible"))
3081          {
3082              cfg.visible = false;
3083          }
3084          var ShapeClass = this._getShapeClass(cfg.type),
3085              shape = new ShapeClass(cfg);
3086          this._appendShape(shape);
3087          return shape;
3088      },
3089  
3090      /**
3091       * Adds a shape instance to the graphic instance.
3092       *
3093       * @method _appendShape
3094       * @param {Shape} shape The shape instance to be added to the graphic.
3095       * @private
3096       */
3097      _appendShape: function(shape)
3098      {
3099          var node = shape.node,
3100              parentNode = this._frag || this._contentNode;
3101          if(this.get("autoDraw"))
3102          {
3103              parentNode.appendChild(node);
3104          }
3105          else
3106          {
3107              this._getDocFrag().appendChild(node);
3108          }
3109      },
3110  
3111      /**
3112       * Removes a shape instance from from the graphic instance.
3113       *
3114       * @method removeShape
3115       * @param {Shape|String} shape The instance or id of the shape to be removed.
3116       */
3117      removeShape: function(shape)
3118      {
3119          if(!(shape instanceof SVGShape))
3120          {
3121              if(Y_LANG.isString(shape))
3122              {
3123                  shape = this._shapes[shape];
3124              }
3125          }
3126          if(shape && shape instanceof SVGShape)
3127          {
3128              shape._destroy();
3129              delete this._shapes[shape.get("id")];
3130          }
3131          if(this.get("autoDraw"))
3132          {
3133              this._redraw();
3134          }
3135          return shape;
3136      },
3137  
3138      /**
3139       * Removes all shape instances from the dom.
3140       *
3141       * @method removeAllShapes
3142       */
3143      removeAllShapes: function()
3144      {
3145          var shapes = this._shapes,
3146              i;
3147          for(i in shapes)
3148          {
3149              if(shapes.hasOwnProperty(i))
3150              {
3151                  shapes[i]._destroy();
3152              }
3153          }
3154          this._shapes = {};
3155      },
3156  
3157      /**
3158       * Removes all child nodes.
3159       *
3160       * @method _removeChildren
3161       * @param {HTMLElement} node
3162       * @private
3163       */
3164      _removeChildren: function(node)
3165      {
3166          if(node.hasChildNodes())
3167          {
3168              var child;
3169              while(node.firstChild)
3170              {
3171                  child = node.firstChild;
3172                  this._removeChildren(child);
3173                  node.removeChild(child);
3174              }
3175          }
3176      },
3177  
3178      /**
3179       * Clears the graphics object.
3180       *
3181       * @method clear
3182       */
3183      clear: function() {
3184          this.removeAllShapes();
3185      },
3186  
3187      /**
3188       * Toggles visibility
3189       *
3190       * @method _toggleVisible
3191       * @param {Boolean} val indicates visibilitye
3192       * @private
3193       */
3194      _toggleVisible: function(val)
3195      {
3196          var i,
3197              shapes = this._shapes,
3198              visibility = val ? "visible" : "hidden";
3199          if(shapes)
3200          {
3201              for(i in shapes)
3202              {
3203                  if(shapes.hasOwnProperty(i))
3204                  {
3205                      shapes[i].set("visible", val);
3206                  }
3207              }
3208          }
3209          if(this._contentNode)
3210          {
3211              this._contentNode.style.visibility = visibility;
3212          }
3213          if(this._node)
3214          {
3215              this._node.style.visibility = visibility;
3216          }
3217      },
3218  
3219      /**
3220       * Returns a shape class. Used by `addShape`.
3221       *
3222       * @method _getShapeClass
3223       * @param {Shape | String} val Indicates which shape class.
3224       * @return Function
3225       * @private
3226       */
3227      _getShapeClass: function(val)
3228      {
3229          var shape = this._shapeClass[val];
3230          if(shape)
3231          {
3232              return shape;
3233          }
3234          return val;
3235      },
3236  
3237      /**
3238       * Look up for shape classes. Used by `addShape` to retrieve a class for instantiation.
3239       *
3240       * @property _shapeClass
3241       * @type Object
3242       * @private
3243       */
3244      _shapeClass: {
3245          circle: Y.SVGCircle,
3246          rect: Y.SVGRect,
3247          path: Y.SVGPath,
3248          ellipse: Y.SVGEllipse,
3249          pieslice: Y.SVGPieSlice
3250      },
3251  
3252      /**
3253       * Returns a shape based on the id of its dom node.
3254       *
3255       * @method getShapeById
3256       * @param {String} id Dom id of the shape's node attribute.
3257       * @return Shape
3258       */
3259      getShapeById: function(id)
3260      {
3261          var shape = this._shapes[id];
3262          return shape;
3263      },
3264  
3265      /**
3266       * Allows for creating multiple shapes in order to batch appending and redraw operations.
3267       *
3268       * @method batch
3269       * @param {Function} method Method to execute.
3270       */
3271      batch: function(method)
3272      {
3273          var autoDraw = this.get("autoDraw");
3274          this.set("autoDraw", false);
3275          method();
3276          this.set("autoDraw", autoDraw);
3277      },
3278  
3279      /**
3280       * Returns a document fragment to for attaching shapes.
3281       *
3282       * @method _getDocFrag
3283       * @return DocumentFragment
3284       * @private
3285       */
3286      _getDocFrag: function()
3287      {
3288          if(!this._frag)
3289          {
3290              this._frag = DOCUMENT.createDocumentFragment();
3291          }
3292          return this._frag;
3293      },
3294  
3295      /**
3296       * Redraws all shapes.
3297       *
3298       * @method _redraw
3299       * @private
3300       */
3301      _redraw: function()
3302      {
3303          var autoSize = this.get("autoSize"),
3304              preserveAspectRatio = this.get("preserveAspectRatio"),
3305              box = this.get("resizeDown") ? this._getUpdatedContentBounds() : this._contentBounds,
3306              left = box.left,
3307              right = box.right,
3308              top = box.top,
3309              bottom = box.bottom,
3310              width = right - left,
3311              height = bottom - top,
3312              computedWidth,
3313              computedHeight,
3314              computedLeft,
3315              computedTop,
3316              node;
3317          if(autoSize)
3318          {
3319              if(autoSize === "sizeContentToGraphic")
3320              {
3321                  node = this._node;
3322                  computedWidth = parseFloat(Y.DOM.getComputedStyle(node, "width"));
3323                  computedHeight = parseFloat(Y.DOM.getComputedStyle(node, "height"));
3324                  computedLeft = computedTop = 0;
3325                  this._contentNode.setAttribute("preserveAspectRatio", preserveAspectRatio);
3326              }
3327              else
3328              {
3329                  computedWidth = width;
3330                  computedHeight = height;
3331                  computedLeft = left;
3332                  computedTop = top;
3333                  this._state.width = width;
3334                  this._state.height = height;
3335                  if(this._node)
3336                  {
3337                      this._node.style.width = width + "px";
3338                      this._node.style.height = height + "px";
3339                  }
3340              }
3341          }
3342          else
3343          {
3344                  computedWidth = width;
3345                  computedHeight = height;
3346                  computedLeft = left;
3347                  computedTop = top;
3348          }
3349          if(this._contentNode)
3350          {
3351              this._contentNode.style.left = computedLeft + "px";
3352              this._contentNode.style.top = computedTop + "px";
3353              this._contentNode.setAttribute("width", computedWidth);
3354              this._contentNode.setAttribute("height", computedHeight);
3355              this._contentNode.style.width = computedWidth + "px";
3356              this._contentNode.style.height = computedHeight + "px";
3357              this._contentNode.setAttribute("viewBox", "" + left + " " + top + " " + width + " " + height + "");
3358          }
3359          if(this._frag)
3360          {
3361              if(this._contentNode)
3362              {
3363                  this._contentNode.appendChild(this._frag);
3364              }
3365              this._frag = null;
3366          }
3367      },
3368  
3369      /**
3370       * Adds a shape to the redraw queue and calculates the contentBounds. Used internally
3371       * by `Shape` instances.
3372       *
3373       * @method addToRedrawQueue
3374       * @param shape {SVGShape}
3375       * @protected
3376       */
3377      addToRedrawQueue: function(shape)
3378      {
3379          var shapeBox,
3380              box;
3381          this._shapes[shape.get("id")] = shape;
3382          if(!this.get("resizeDown"))
3383          {
3384              shapeBox = shape.getBounds();
3385              box = this._contentBounds;
3386              box.left = box.left < shapeBox.left ? box.left : shapeBox.left;
3387              box.top = box.top < shapeBox.top ? box.top : shapeBox.top;
3388              box.right = box.right > shapeBox.right ? box.right : shapeBox.right;
3389              box.bottom = box.bottom > shapeBox.bottom ? box.bottom : shapeBox.bottom;
3390              box.width = box.right - box.left;
3391              box.height = box.bottom - box.top;
3392              this._contentBounds = box;
3393          }
3394          if(this.get("autoDraw"))
3395          {
3396              this._redraw();
3397          }
3398      },
3399  
3400      /**
3401       * Recalculates and returns the `contentBounds` for the `Graphic` instance.
3402       *
3403       * @method _getUpdatedContentBounds
3404       * @return {Object}
3405       * @private
3406       */
3407      _getUpdatedContentBounds: function()
3408      {
3409          var bounds,
3410              i,
3411              shape,
3412              queue = this._shapes,
3413              box = {};
3414          for(i in queue)
3415          {
3416              if(queue.hasOwnProperty(i))
3417              {
3418                  shape = queue[i];
3419                  bounds = shape.getBounds();
3420                  box.left = Y_LANG.isNumber(box.left) ? Math.min(box.left, bounds.left) : bounds.left;
3421                  box.top = Y_LANG.isNumber(box.top) ? Math.min(box.top, bounds.top) : bounds.top;
3422                  box.right = Y_LANG.isNumber(box.right) ? Math.max(box.right, bounds.right) : bounds.right;
3423                  box.bottom = Y_LANG.isNumber(box.bottom) ? Math.max(box.bottom, bounds.bottom) : bounds.bottom;
3424              }
3425          }
3426          box.left = Y_LANG.isNumber(box.left) ? box.left : 0;
3427          box.top = Y_LANG.isNumber(box.top) ? box.top : 0;
3428          box.right = Y_LANG.isNumber(box.right) ? box.right : 0;
3429          box.bottom = Y_LANG.isNumber(box.bottom) ? box.bottom : 0;
3430          this._contentBounds = box;
3431          return box;
3432      },
3433  
3434      /**
3435       * Creates a contentNode element
3436       *
3437       * @method _createGraphics
3438       * @private
3439       */
3440      _createGraphics: function() {
3441          var contentNode = this._createGraphicNode("svg"),
3442              pointerEvents = this.get("pointerEvents");
3443          contentNode.style.position = "absolute";
3444          contentNode.style.top = "0px";
3445          contentNode.style.left = "0px";
3446          contentNode.style.overflow = "auto";
3447          contentNode.setAttribute("overflow", "auto");
3448          contentNode.setAttribute("pointer-events", pointerEvents);
3449          return contentNode;
3450      },
3451  
3452      /**
3453       * Creates a graphic node
3454       *
3455       * @method _createGraphicNode
3456       * @param {String} type node type to create
3457       * @param {String} pe specified pointer-events value
3458       * @return HTMLElement
3459       * @private
3460       */
3461      _createGraphicNode: function(type, pe)
3462      {
3463          var node = DOCUMENT.createElementNS("http://www.w3.org/2000/svg", "svg:" + type),
3464              v = pe || "none";
3465          if(type !== "defs" && type !== "stop" && type !== "linearGradient" && type !== "radialGradient")
3466          {
3467              node.setAttribute("pointer-events", v);
3468          }
3469          return node;
3470      },
3471  
3472      /**
3473       * Returns a reference to a gradient definition based on an id and type.
3474       *
3475       * @method getGradientNode
3476       * @param {String} key id that references the gradient definition
3477       * @param {String} type description of the gradient type
3478       * @return HTMLElement
3479       * @protected
3480       */
3481      getGradientNode: function(key, type)
3482      {
3483          var gradients = this._gradients,
3484              gradient,
3485              nodeType = type + "Gradient";
3486          if(gradients.hasOwnProperty(key) && gradients[key].tagName.indexOf(type) > -1)
3487          {
3488              gradient = this._gradients[key];
3489          }
3490          else
3491          {
3492              gradient = this._createGraphicNode(nodeType);
3493              if(!this._defs)
3494              {
3495                  this._defs = this._createGraphicNode("defs");
3496                  this._contentNode.appendChild(this._defs);
3497              }
3498              this._defs.appendChild(gradient);
3499              key = key || "gradient" + Math.round(100000 * Math.random());
3500              gradient.setAttribute("id", key);
3501              if(gradients.hasOwnProperty(key))
3502              {
3503                  this._defs.removeChild(gradients[key]);
3504              }
3505              gradients[key] = gradient;
3506          }
3507          return gradient;
3508      },
3509  
3510      /**
3511       * Inserts shape on the top of the tree.
3512       *
3513       * @method _toFront
3514       * @param {SVGShape} Shape to add.
3515       * @private
3516       */
3517      _toFront: function(shape)
3518      {
3519          var contentNode = this._contentNode;
3520          if(shape instanceof Y.SVGShape)
3521          {
3522              shape = shape.get("node");
3523          }
3524          if(contentNode && shape)
3525          {
3526              contentNode.appendChild(shape);
3527          }
3528      },
3529  
3530      /**
3531       * Inserts shape as the first child of the content node.
3532       *
3533       * @method _toBack
3534       * @param {SVGShape} Shape to add.
3535       * @private
3536       */
3537      _toBack: function(shape)
3538      {
3539          var contentNode = this._contentNode,
3540              targetNode;
3541          if(shape instanceof Y.SVGShape)
3542          {
3543              shape = shape.get("node");
3544          }
3545          if(contentNode && shape)
3546          {
3547              targetNode = contentNode.firstChild;
3548              if(targetNode)
3549              {
3550                  contentNode.insertBefore(shape, targetNode);
3551              }
3552              else
3553              {
3554                  contentNode.appendChild(shape);
3555              }
3556          }
3557      }
3558  });
3559  
3560  Y.SVGGraphic = SVGGraphic;
3561  
3562  
3563  
3564  }, '3.17.2', {"requires": ["graphics"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1