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