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