MDL-32843 import YUI 3.5.1
[moodle.git] / lib / yui / 3.5.1 / build / graphics-vml / graphics-vml.js
blob7c32244db61461dc5dd4215a2f2a11909cbf5fb8
1 /*
2 YUI 3.5.1 (build 22)
3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
7 YUI.add('graphics-vml', function(Y) {
9 var Y_LANG = Y.Lang,
10     IS_NUM = Y_LANG.isNumber,
11     IS_ARRAY = Y_LANG.isArray,
12     Y_DOM = Y.DOM,
13     Y_SELECTOR = Y.Selector,
14     DOCUMENT = Y.config.doc,
15     AttributeLite = Y.AttributeLite,
16         VMLShape,
17         VMLCircle,
18         VMLPath,
19         VMLRect,
20         VMLEllipse,
21         VMLGraphic,
22     VMLPieSlice;
24 function VMLDrawing() {}
26 /**
27  * <a href="http://www.w3.org/TR/NOTE-VML">VML</a> implementation of the <a href="Drawing.html">`Drawing`</a> class. 
28  * `VMLDrawing` is not intended to be used directly. Instead, use the <a href="Drawing.html">`Drawing`</a> class. 
29  * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> and <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> 
30  * capabilities, the <a href="Drawing.html">`Drawing`</a> class will point to the `VMLDrawing` class.
31  *
32  * @module graphics
33  * @class VMLDrawing
34  * @constructor
35  */
36 VMLDrawing.prototype = {
37     /**
38      * Current x position of the drqwing.
39      *
40      * @property _currentX
41      * @type Number
42      * @private
43      */
44     _currentX: 0,
46     /**
47      * Current y position of the drqwing.
48      *
49      * @property _currentY
50      * @type Number
51      * @private
52      */
53     _currentY: 0,
55     /**
56      * Draws a bezier curve.
57      *
58      * @method curveTo
59      * @param {Number} cp1x x-coordinate for the first control point.
60      * @param {Number} cp1y y-coordinate for the first control point.
61      * @param {Number} cp2x x-coordinate for the second control point.
62      * @param {Number} cp2y y-coordinate for the second control point.
63      * @param {Number} x x-coordinate for the end point.
64      * @param {Number} y y-coordinate for the end point.
65      */
66     curveTo: function(cp1x, cp1y, cp2x, cp2y, x, y) {
67         var hiX,
68             loX,
69             hiY,
70             loY;
71         x = Math.round(x);
72         y = Math.round(y);
73         this._path += ' c ' + Math.round(cp1x) + ", " + Math.round(cp1y) + ", " + Math.round(cp2x) + ", " + Math.round(cp2y) + ", " + x + ", " + y;
74         this._currentX = x;
75         this._currentY = y;
76         hiX = Math.max(x, Math.max(cp1x, cp2x));
77         hiY = Math.max(y, Math.max(cp1y, cp2y));
78         loX = Math.min(x, Math.min(cp1x, cp2x));
79         loY = Math.min(y, Math.min(cp1y, cp2y));
80         this._trackSize(hiX, hiY);
81         this._trackSize(loX, loY);
82     },
84     /**
85      * Draws a quadratic bezier curve.
86      *
87      * @method quadraticCurveTo
88      * @param {Number} cpx x-coordinate for the control point.
89      * @param {Number} cpy y-coordinate for the control point.
90      * @param {Number} x x-coordinate for the end point.
91      * @param {Number} y y-coordinate for the end point.
92      */
93     quadraticCurveTo: function(cpx, cpy, x, y) {
94         var currentX = this._currentX,
95             currentY = this._currentY,
96             cp1x = currentX + 0.67*(cpx - currentX),
97             cp1y = currentY + 0.67*(cpy - currentY),
98             cp2x = cp1x + (x - currentX) * 0.34,
99             cp2y = cp1y + (y - currentY) * 0.34;
100         this.curveTo(cp1x, cp1y, cp2x, cp2y, x, y);
101     },
103     /**
104      * Draws a rectangle.
105      *
106      * @method drawRect
107      * @param {Number} x x-coordinate
108      * @param {Number} y y-coordinate
109      * @param {Number} w width
110      * @param {Number} h height
111      */
112     drawRect: function(x, y, w, h) {
113         this.moveTo(x, y);
114         this.lineTo(x + w, y);
115         this.lineTo(x + w, y + h);
116         this.lineTo(x, y + h);
117         this.lineTo(x, y);
118         this._currentX = x;
119         this._currentY = y;
120         return this;
121     },
123     /**
124      * Draws a rectangle with rounded corners.
125      * 
126      * @method drawRect
127      * @param {Number} x x-coordinate
128      * @param {Number} y y-coordinate
129      * @param {Number} w width
130      * @param {Number} h height
131      * @param {Number} ew width of the ellipse used to draw the rounded corners
132      * @param {Number} eh height of the ellipse used to draw the rounded corners
133      */
134     drawRoundRect: function(x, y, w, h, ew, eh) {
135         this.moveTo(x, y + eh);
136         this.lineTo(x, y + h - eh);
137         this.quadraticCurveTo(x, y + h, x + ew, y + h);
138         this.lineTo(x + w - ew, y + h);
139         this.quadraticCurveTo(x + w, y + h, x + w, y + h - eh);
140         this.lineTo(x + w, y + eh);
141         this.quadraticCurveTo(x + w, y, x + w - ew, y);
142         this.lineTo(x + ew, y);
143         this.quadraticCurveTo(x, y, x, y + eh);
144         return this;
145     },
147     /**
148      * Draws a circle. Used internally by `CanvasCircle` class.
149      *
150      * @method drawCircle
151      * @param {Number} x y-coordinate
152      * @param {Number} y x-coordinate
153      * @param {Number} r radius
154      * @protected
155      */
156         drawCircle: function(x, y, radius) {
157         var startAngle = 0,
158             endAngle = 360,
159             circum = radius * 2;
160         endAngle *= 65535;
161         this._drawingComplete = false;
162         this._trackSize(x + circum, y + circum);
163         this._path += " m " + (x + circum) + " " + (y + radius) + " ae " + (x + radius) + " " + (y + radius) + " " + radius + " " + radius + " " + startAngle + " " + endAngle;
164         return this;
165     },
166     
167     /**
168      * Draws an ellipse.
169      *
170      * @method drawEllipse
171      * @param {Number} x x-coordinate
172      * @param {Number} y y-coordinate
173      * @param {Number} w width
174      * @param {Number} h height
175      * @protected
176      */
177         drawEllipse: function(x, y, w, h) {
178         var startAngle = 0,
179             endAngle = 360,
180             radius = w * 0.5,
181             yRadius = h * 0.5;
182         endAngle *= 65535;
183         this._drawingComplete = false;
184         this._trackSize(x + w, y + h);
185         this._path += " m " + (x + w) + " " + (y + yRadius) + " ae " + (x + radius) + " " + (y + yRadius) + " " + radius + " " + yRadius + " " + startAngle + " " + endAngle;
186         return this;
187     },
188     
189     /**
190      * Draws a diamond.     
191      * 
192      * @method drawDiamond
193      * @param {Number} x y-coordinate
194      * @param {Number} y x-coordinate
195      * @param {Number} width width
196      * @param {Number} height height
197      * @protected
198      */
199     drawDiamond: function(x, y, width, height)
200     {
201         var midWidth = width * 0.5,
202             midHeight = height * 0.5;
203         this.moveTo(x + midWidth, y);
204         this.lineTo(x + width, y + midHeight);
205         this.lineTo(x + midWidth, y + height);
206         this.lineTo(x, y + midHeight);
207         this.lineTo(x + midWidth, y);
208         return this;
209     },
211     /**
212      * Draws a wedge.
213      *
214      * @method drawWedge
215      * @param {Number} x x-coordinate of the wedge's center point
216      * @param {Number} y y-coordinate of the wedge's center point
217      * @param {Number} startAngle starting angle in degrees
218      * @param {Number} arc sweep of the wedge. Negative values draw clockwise.
219      * @param {Number} radius radius of wedge. If [optional] yRadius is defined, then radius is the x radius.
220      * @param {Number} yRadius [optional] y radius for wedge.
221      * @private
222      */
223     drawWedge: function(x, y, startAngle, arc, radius, yRadius)
224     {
225         var diameter = radius * 2;
226         x = Math.round(x);
227         y = Math.round(y);
228         yRadius = yRadius || radius;
229         radius = Math.round(radius);
230         yRadius = Math.round(yRadius);
231         if(Math.abs(arc) > 360)
232         {
233             arc = 360;
234         }
235         startAngle *= -65535;
236         arc *= 65536;
237         this._path += " m " + x + " " + y + " ae " + x + " " + y + " " + radius + " " + yRadius + " " + startAngle + " " + arc;
238         this._trackSize(diameter, diameter); 
239         this._currentX = x;
240         this._currentY = y;
241         return this;
242     },
244     /**
245      * Draws a line segment using the current line style from the current drawing position to the specified x and y coordinates.
246      * 
247      * @method lineTo
248      * @param {Number} point1 x-coordinate for the end point.
249      * @param {Number} point2 y-coordinate for the end point.
250      */
251     lineTo: function(point1, point2, etc) {
252         var args = arguments,
253             i,
254             len;
255         if (typeof point1 === 'string' || typeof point1 === 'number') {
256             args = [[point1, point2]];
257         }
258         len = args.length;
259         if(!this._path)
260         {
261             this._path = "";
262         }
263         this._path += ' l ';
264         for (i = 0; i < len; ++i) {
265             this._path += ' ' + Math.round(args[i][0]) + ', ' + Math.round(args[i][1]);
266             this._trackSize.apply(this, args[i]);
267             this._currentX = args[i][0];
268             this._currentY = args[i][1];
269         }
270         return this;
271     },
273     /**
274      * Moves the current drawing position to specified x and y coordinates.
275      *
276      * @method moveTo
277      * @param {Number} x x-coordinate for the end point.
278      * @param {Number} y y-coordinate for the end point.
279      */
280     moveTo: function(x, y) {
281         if(!this._path)
282         {
283             this._path = "";
284         }
285         this._path += ' m ' + Math.round(x) + ', ' + Math.round(y);
286         this._trackSize(x, y);
287         this._currentX = x;
288         this._currentY = y;
289     },
291     /**
292      * Draws the graphic.
293      *
294      * @method _draw
295      * @private
296      */
297     _closePath: function()
298     {
299         var fill = this.get("fill"),
300             stroke = this.get("stroke"),
301             node = this.node,
302             w = this.get("width"),
303             h = this.get("height"),
304             path = this._path,
305             pathEnd = "";
306         this._fillChangeHandler();
307         this._strokeChangeHandler();
308         if(path)
309         {
310             if(fill && fill.color)
311             {
312                 pathEnd += ' x';
313             }
314             if(stroke)
315             {
316                 pathEnd += ' e';
317             }
318         }
319         if(path)
320         {
321             node.path = path + pathEnd;
322         }
323         if(!isNaN(w) && !isNaN(h))
324         {
325             node.coordSize =  w + ', ' + h;
326             node.style.position = "absolute";
327             node.style.width = w + "px";
328             node.style.height = h + "px";
329         }
330         this._path = path;
331         this._updateTransform();
332     },
334     /**
335      * Completes a drawing operation. 
336      *
337      * @method end
338      */
339     end: function()
340     {
341         this._closePath();
342     },
344     /**
345      * Ends a fill and stroke
346      *
347      * @method closePath
348      */
349     closePath: function()
350     {
351         this._path += ' x e ';
352     },
354     /**
355      * Clears the path.
356      *
357      * @method clear
358      */
359     clear: function()
360     {
361                 this._right = 0;
362         this._bottom = 0;
363         this._width = 0;
364         this._height = 0;
365         this._left = 0;
366         this._top = 0;
367         this._path = "";
368     },
370     /**
371      * Updates the size of the graphics object
372      *
373      * @method _trackSize
374      * @param {Number} w width
375      * @param {Number} h height
376      * @private
377      */
378     _trackSize: function(w, h) {
379         if (w > this._right) {
380             this._right = w;
381         }
382         if(w < this._left)
383         {
384             this._left = w;    
385         }
386         if (h < this._top)
387         {
388             this._top = h;
389         }
390         if (h > this._bottom) 
391         {
392             this._bottom = h;
393         }
394         this._width = this._right - this._left;
395         this._height = this._bottom - this._top;
396     },
398     _left: 0,
400     _right: 0,
402     _top: 0,
404     _bottom: 0,
406     _width: 0,
408     _height: 0
410 Y.VMLDrawing = VMLDrawing;
412  * <a href="http://www.w3.org/TR/NOTE-VML">VML</a> implementation of the <a href="Shape.html">`Shape`</a> class. 
413  * `VMLShape` is not intended to be used directly. Instead, use the <a href="Shape.html">`Shape`</a> class. 
414  * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> and <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> 
415  * capabilities, the <a href="Shape.html">`Shape`</a> class will point to the `VMLShape` class.
417  * @module graphics
418  * @class VMLShape
419  * @constructor
420  * @param {Object} cfg (optional) Attribute configs
421  */
422 VMLShape = function() 
424     this._transforms = [];
425     this.matrix = new Y.Matrix();
426     this._normalizedMatrix = new Y.Matrix();
427     VMLShape.superclass.constructor.apply(this, arguments);
430 VMLShape.NAME = "vmlShape";
432 Y.extend(VMLShape, Y.GraphicBase, Y.mix({
433         /**
434          * Indicates the type of shape
435          *
436          * @property _type
437          * @type String
438      * @private
439          */
440         _type: "shape",
441     
442     /**
443      * Init method, invoked during construction.
444      * Calls `initializer` method.
445      *
446      * @method init
447      * @protected
448      */
449         init: function()
450         {
451                 this.initializer.apply(this, arguments);
452         },
454         /**
455          * Initializes the shape
456          *
457          * @private
458          * @method _initialize
459          */
460         initializer: function(cfg)
461         {
462                 var host = this,
463             graphic = cfg.graphic;
464                 host.createNode();
465         if(graphic)
466         {
467             this._setGraphic(graphic);
468         }
469         this._updateHandler();
470         },
472     /**
473      * Set the Graphic instance for the shape.
474      *
475      * @method _setGraphic
476      * @param {Graphic | Node | HTMLElement | String} render This param is used to determine the graphic instance. If it is a `Graphic` instance, it will be assigned
477      * to the `graphic` attribute. Otherwise, a new Graphic instance will be created and rendered into the dom element that the render represents.
478      * @private
479      */
480     _setGraphic: function(render)
481     {
482         var graphic;
483         if(render instanceof Y.VMLGraphic)
484         {
485                     this._graphic = render;
486         }
487         else
488         {
489             render = Y.one(render);
490             graphic = new Y.VMLGraphic({
491                 render: render
492             });
493             graphic._appendShape(this);
494             this._graphic = graphic;
495         }
496     },
498         /**
499          * Creates the dom node for the shape.
500          *
501      * @method createNode
502          * @return HTMLElement
503          * @private
504          */
505         createNode: function()
506         {
507         var node,
508                         x = this.get("x"),
509                         y = this.get("y"),
510             w = this.get("width"),
511             h = this.get("height"),
512                         id,
513                         type,
514                         nodestring,
515             visibility = this.get("visible") ? "visible" : "hidden",
516                         strokestring,
517                         classString,
518                         stroke,
519                         endcap,
520                         opacity,
521                         joinstyle,
522                         miterlimit,
523                         dashstyle,
524                         fill,
525                         fillstring;
526                         id = this.get("id");
527                         type = this._type == "path" ? "shape" : this._type;
528                         classString = 'vml' + type + ' yui3-vmlShape yui3-' + this.constructor.NAME; 
529                         stroke = this._getStrokeProps();
530                         fill = this._getFillProps();
531                         
532                         nodestring  = '<' + type + '  xmlns="urn:schemas-microsft.com:vml" id="' + id + '" class="' + classString + '" style="behavior:url(#default#VML);display:inline-block;position:absolute;left:' + x + 'px;top:' + y + 'px;width:' + w + 'px;height:' + h + 'px;visibility:' + visibility + '"';
534                     if(stroke && stroke.weight && stroke.weight > 0)
535                         {
536                                 endcap = stroke.endcap;
537                                 opacity = parseFloat(stroke.opacity);
538                                 joinstyle = stroke.joinstyle;
539                                 miterlimit = stroke.miterlimit;
540                                 dashstyle = stroke.dashstyle;
541                                 nodestring += ' stroked="t" strokecolor="' + stroke.color + '" strokeWeight="' + stroke.weight + 'px"';
542                                 
543                                 strokestring = '<stroke class="vmlstroke" xmlns="urn:schemas-microsft.com:vml" on="t" style="behavior:url(#default#VML);display:inline-block;"';
544                                 strokestring += ' opacity="' + opacity + '"';
545                                 if(endcap)
546                                 {
547                                         strokestring += ' endcap="' + endcap + '"';
548                                 }
549                                 if(joinstyle)
550                                 {
551                                         strokestring += ' joinstyle="' + joinstyle + '"';
552                                 }
553                                 if(miterlimit)
554                                 {
555                                         strokestring += ' miterlimit="' + miterlimit + '"';
556                                 }
557                                 if(dashstyle)
558                                 {
559                                         strokestring += ' dashstyle="' + dashstyle + '"';
560                                 }
561                                 strokestring += '></stroke>';
562                                 this._strokeNode = DOCUMENT.createElement(strokestring);
563                                 nodestring += ' stroked="t"';
564                         }
565                         else
566                         {
567                                 nodestring += ' stroked="f"';
568                         }
569                         if(fill)
570                         {
571                                 if(fill.node)
572                                 {
573                                         fillstring = fill.node;
574                                         this._fillNode = DOCUMENT.createElement(fillstring);
575                                 }
576                                 if(fill.color)
577                                 {
578                                         nodestring += ' fillcolor="' + fill.color + '"';
579                                 }
580                                 nodestring += ' filled="' + fill.filled + '"';
581                         }
582                         
583                         
584                         nodestring += '>';
585                         nodestring += '</' + type + '>';
586                         
587                         node = DOCUMENT.createElement(nodestring);
588                         if(this._strokeNode)
589                         {
590                                 node.appendChild(this._strokeNode);
591                         }
592                         if(this._fillNode)
593                         {
594                                 node.appendChild(this._fillNode);
595                         }
597             this.node = node;
598             this._strokeFlag = false;
599             this._fillFlag = false;
600         },
602         /**
603          * Add a class name to each node.
604          *
605          * @method addClass
606          * @param {String} className the class name to add to the node's class attribute 
607          */
608         addClass: function(className)
609         {
610                 var node = this.node;
611                 Y_DOM.addClass(node, className);
612         },
614         /**
615          * Removes a class name from each node.
616          *
617          * @method removeClass
618          * @param {String} className the class name to remove from the node's class attribute
619          */
620         removeClass: function(className)
621         {
622                 var node = this.node;
623                 Y_DOM.removeClass(node, className);
624         },
626         /**
627          * Gets the current position of the node in page coordinates.
628          *
629          * @method getXY
630          * @return Array The XY position of the shape.
631          */
632         getXY: function()
633         {
634                 var graphic = this._graphic,
635                         parentXY = graphic.getXY(),
636                         x = this.get("x"),
637                         y = this.get("y");
638                 return [parentXY[0] + x, parentXY[1] + y];
639         },
641         /**
642          * Set the position of the shape in page coordinates, regardless of how the node is positioned.
643          *
644          * @method setXY
645          * @param {Array} Contains x & y values for new position (coordinates are page-based)
646      *
647          */
648         setXY: function(xy)
649         {
650                 var graphic = this._graphic,
651                         parentXY = graphic.getXY();
652                 this.set("x", xy[0] - parentXY[0]);
653                 this.set("y", xy[1] - parentXY[1]);
654         },
656         /**
657          * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy. 
658          *
659          * @method contains
660          * @param {VMLShape | HTMLElement} needle The possible node or descendent
661          * @return Boolean Whether or not this shape is the needle or its ancestor.
662          */
663         contains: function(needle)
664         {
665                 return needle === Y.one(this.node);
666         },
668         /**
669          * Compares nodes to determine if they match.
670          * Node instances can be compared to each other and/or HTMLElements.
671          * @method compareTo
672          * @param {HTMLElement | Node} refNode The reference node to compare to the node.
673          * @return {Boolean} True if the nodes match, false if they do not.
674          */
675         compareTo: function(refNode) {
676                 var node = this.node;
678                 return node === refNode;
679         },
681         /**
682          * Test if the supplied node matches the supplied selector.
683          *
684          * @method test
685          * @param {String} selector The CSS selector to test against.
686          * @return Boolean Wheter or not the shape matches the selector.
687          */
688         test: function(selector)
689         {
690                 return Y_SELECTOR.test(this.node, selector);
691         },
693         /**
694      * Calculates and returns properties for setting an initial stroke.
695      *
696      * @method _getStrokeProps
697      * @return Object
698      *
699          * @private
700          */
701          _getStrokeProps: function()
702          {
703                 var props,
704                         stroke = this.get("stroke"),
705                         strokeOpacity,
706                         dashstyle,
707                         dash = "",
708                         val,
709                         i = 0,
710                         len,
711                         linecap,
712                         linejoin;
713         if(stroke && stroke.weight && stroke.weight > 0)
714                 {
715                         props = {};
716                         linecap = stroke.linecap || "flat";
717                         linejoin = stroke.linejoin || "round";
718                         if(linecap != "round" && linecap != "square")
719                         {
720                                 linecap = "flat";
721                         }
722                         strokeOpacity = parseFloat(stroke.opacity);
723                         dashstyle = stroke.dashstyle || "none";
724                         stroke.color = stroke.color || "#000000";
725                         stroke.weight = stroke.weight || 1;
726                         stroke.opacity = IS_NUM(strokeOpacity) ? strokeOpacity : 1;
727                         props.stroked = true;
728                         props.color = stroke.color;
729                         props.weight = stroke.weight;
730                         props.endcap = linecap;
731                         props.opacity = stroke.opacity;
732                         if(IS_ARRAY(dashstyle))
733                         {
734                                 dash = [];
735                                 len = dashstyle.length;
736                                 for(i = 0; i < len; ++i)
737                                 {
738                                         val = dashstyle[i];
739                                         dash[i] = val / stroke.weight;
740                                 }
741                         }
742                         if(linejoin == "round" || linejoin == "bevel")
743                         {
744                                 props.joinstyle = linejoin;
745                         }
746                         else
747                         {
748                                 linejoin = parseInt(linejoin, 10);
749                                 if(IS_NUM(linejoin))
750                                 {
751                                         props.miterlimit = Math.max(linejoin, 1);
752                                         props.joinstyle = "miter";
753                                 }
754                         }
755                         props.dashstyle = dash;
756                 }
757                 return props;
758          },
760         /**
761          * Adds a stroke to the shape node.
762          *
763          * @method _strokeChangeHandler
764          * @private
765          */
766         _strokeChangeHandler: function(e)
767         {
768         if(!this._strokeFlag)
769         {
770             return;
771         }
772                 var node = this.node,
773                         stroke = this.get("stroke"),
774                         strokeOpacity,
775                         dashstyle,
776                         dash = "",
777                         val,
778                         i = 0,
779                         len,
780                         linecap,
781                         linejoin;
782                 if(stroke && stroke.weight && stroke.weight > 0)
783                 {
784                         linecap = stroke.linecap || "flat";
785                         linejoin = stroke.linejoin || "round";
786                         if(linecap != "round" && linecap != "square")
787                         {
788                                 linecap = "flat";
789                         }
790                         strokeOpacity = parseFloat(stroke.opacity);
791                         dashstyle = stroke.dashstyle || "none";
792                         stroke.color = stroke.color || "#000000";
793                         stroke.weight = stroke.weight || 1;
794                         stroke.opacity = IS_NUM(strokeOpacity) ? strokeOpacity : 1;
795                         node.stroked = true;
796                         node.strokeColor = stroke.color;
797                         node.strokeWeight = stroke.weight + "px";
798                         if(!this._strokeNode)
799                         {
800                                 this._strokeNode = this._createGraphicNode("stroke");
801                                 node.appendChild(this._strokeNode);
802                         }
803                         this._strokeNode.endcap = linecap;
804                         this._strokeNode.opacity = stroke.opacity;
805                         if(IS_ARRAY(dashstyle))
806                         {
807                                 dash = [];
808                                 len = dashstyle.length;
809                                 for(i = 0; i < len; ++i)
810                                 {
811                                         val = dashstyle[i];
812                                         dash[i] = val / stroke.weight;
813                                 }
814                         }
815                         if(linejoin == "round" || linejoin == "bevel")
816                         {
817                                 this._strokeNode.joinstyle = linejoin;
818                         }
819                         else
820                         {
821                                 linejoin = parseInt(linejoin, 10);
822                                 if(IS_NUM(linejoin))
823                                 {
824                                         this._strokeNode.miterlimit = Math.max(linejoin, 1);
825                                         this._strokeNode.joinstyle = "miter";
826                                 }
827                         }
828                         this._strokeNode.dashstyle = dash;
829             this._strokeNode.on = true;
830                 }
831                 else
832                 {
833             if(this._strokeNode)
834             {
835                 this._strokeNode.on = false;
836             }
837                         node.stroked = false;
838                 }
839         this._strokeFlag = false;
840         },
842         /**
843      * Calculates and returns properties for setting an initial fill.
844      *
845      * @method _getFillProps
846      * @return Object
847      *
848          * @private
849          */
850         _getFillProps: function()
851         {
852                 var fill = this.get("fill"),
853                         fillOpacity,
854                         props,
855                         gradient,
856                         i,
857                         fillstring,
858                         filled = false;
859                 if(fill)
860                 {
861                         props = {};
862                         
863                         if(fill.type == "radial" || fill.type == "linear")
864                         {
865                                 fillOpacity = parseFloat(fill.opacity);
866                                 fillOpacity = IS_NUM(fillOpacity) ? fillOpacity : 1;
867                                 filled = true;
868                                 gradient = this._getGradientFill(fill);
869                                 fillstring = '<fill xmlns="urn:schemas-microsft.com:vml" class="vmlfill" style="behavior:url(#default#VML);display:inline-block;" opacity="' + fillOpacity + '"';
870                                 for(i in gradient)
871                                 {
872                                         if(gradient.hasOwnProperty(i))
873                                         {
874                                                 fillstring += ' ' + i + '="' + gradient[i] + '"';
875                                         }
876                                 }
877                                 fillstring += ' />';
878                                 props.node = fillstring;
879                         }
880                         else if(fill.color)
881                         {
882                                 fillOpacity = parseFloat(fill.opacity);
883                                 filled = true;
884                 props.color = fill.color;
885                                 if(IS_NUM(fillOpacity))
886                                 {
887                                         fillOpacity = Math.max(Math.min(fillOpacity, 1), 0);
888                     props.opacity = fillOpacity;    
889                                     if(fillOpacity < 1)
890                     {
891                         props.node = '<fill xmlns="urn:schemas-microsft.com:vml" class="vmlfill" style="behavior:url(#default#VML);display:inline-block;" type="solid" opacity="' + fillOpacity + '"/>';
892                                     }
893                 }
894                         }
895                         props.filled = filled;
896                 }
897                 return props;
898         },
900         /**
901          * Adds a fill to the shape node.
902          *
903          * @method _fillChangeHandler
904          * @private
905          */
906         _fillChangeHandler: function(e)
907         {
908         if(!this._fillFlag)
909         {
910             return;
911         }
912                 var node = this.node,
913                         fill = this.get("fill"),
914                         fillOpacity,
915                         fillstring,
916                         filled = false,
917             i,
918             gradient;
919                 if(fill)
920                 {
921                         if(fill.type == "radial" || fill.type == "linear")
922                         {
923                                 filled = true;
924                                 gradient = this._getGradientFill(fill);
925                 if(this._fillNode)
926                 {
927                     for(i in gradient)
928                     {
929                         if(gradient.hasOwnProperty(i))
930                         {
931                             if(i == "colors")
932                             {
933                                 this._fillNode.colors.value = gradient[i];
934                             }
935                             else
936                             {
937                                 this._fillNode[i] = gradient[i];
938                             }
939                         }
940                     }
941                 }
942                 else
943                 {
944                     fillstring = '<fill xmlns="urn:schemas-microsft.com:vml" class="vmlfill" style="behavior:url(#default#VML);display:inline-block;"';
945                     for(i in gradient)
946                     {
947                         if(gradient.hasOwnProperty(i))
948                         {
949                             fillstring += ' ' + i + '="' + gradient[i] + '"';
950                         }
951                     }
952                     fillstring += ' />';
953                     this._fillNode = DOCUMENT.createElement(fillstring);
954                     node.appendChild(this._fillNode);
955                 }
956                         }
957                         else if(fill.color)
958                         {
959                 node.fillcolor = fill.color;
960                                 fillOpacity = parseFloat(fill.opacity);
961                                 filled = true;
962                                 if(IS_NUM(fillOpacity) && fillOpacity < 1)
963                                 {
964                                         fill.opacity = fillOpacity;
965                     if(this._fillNode)
966                                         {
967                         if(this._fillNode.getAttribute("type") != "solid")
968                         {
969                             this._fillNode.type = "solid";
970                         }
971                                                 this._fillNode.opacity = fillOpacity;
972                                         }
973                                         else
974                                         {     
975                         fillstring = '<fill xmlns="urn:schemas-microsft.com:vml" class="vmlfill" style="behavior:url(#default#VML);display:inline-block;" type="solid" opacity="' + fillOpacity + '"/>';
976                         this._fillNode = DOCUMENT.createElement(fillstring);
977                         node.appendChild(this._fillNode);
978                                         }
979                                 }
980                                 else if(this._fillNode)
981                 {   
982                     this._fillNode.opacity = 1;
983                     this._fillNode.type = "solid";
984                                 }
985                         }
986                 }
987                 node.filled = filled;
988         this._fillFlag = false;
989         },
991         //not used. remove next release.
992     _updateFillNode: function(node)
993         {
994                 if(!this._fillNode)
995                 {
996                         this._fillNode = this._createGraphicNode("fill");
997                         node.appendChild(this._fillNode);
998                 }
999         },
1001     /**
1002      * Calculates and returns an object containing gradient properties for a fill node. 
1003      *
1004      * @method _getGradientFill
1005      * @param {Object} fill Object containing fill properties.
1006      * @return Object
1007      * @private
1008      */
1009         _getGradientFill: function(fill)
1010         {
1011                 var gradientProps = {},
1012                         gradientBoxWidth,
1013                         gradientBoxHeight,
1014                         type = fill.type,
1015                         w = this.get("width"),
1016                         h = this.get("height"),
1017                         isNumber = IS_NUM,
1018                         stop,
1019                         stops = fill.stops,
1020                         len = stops.length,
1021                         opacity,
1022                         color,
1023                         i = 0,
1024                         oi,
1025                         colorstring = "",
1026                         cx = fill.cx,
1027                         cy = fill.cy,
1028                         fx = fill.fx,
1029                         fy = fill.fy,
1030                         r = fill.r,
1031                         actualPct,
1032             pct,
1033                         rotation = fill.rotation || 0;
1034                 if(type === "linear")
1035                 {
1036             if(rotation <= 270)
1037             {
1038                 rotation = Math.abs(rotation - 270);
1039             }
1040                         else if(rotation < 360)
1041             {
1042                 rotation = 270 + (360 - rotation);
1043             }
1044             else
1045             {
1046                 rotation = 270;
1047             }
1048             gradientProps.type = "gradient";//"gradientunscaled";
1049                         gradientProps.angle = rotation;
1050                 }
1051                 else if(type === "radial")
1052                 {
1053                         gradientBoxWidth = w * (r * 2);
1054                         gradientBoxHeight = h * (r * 2);
1055                         fx = r * 2 * (fx - 0.5);
1056                         fy = r * 2 * (fy - 0.5);
1057                         fx += cx;
1058                         fy += cy;
1059                         gradientProps.focussize = (gradientBoxWidth/w)/10 + "% " + (gradientBoxHeight/h)/10 + "%";
1060                         gradientProps.alignshape = false;
1061                         gradientProps.type = "gradientradial";
1062                         gradientProps.focus = "100%";
1063                         gradientProps.focusposition = Math.round(fx * 100) + "% " + Math.round(fy * 100) + "%";
1064                 }
1065                 for(;i < len; ++i) {
1066                         stop = stops[i];
1067                         color = stop.color;
1068                         opacity = stop.opacity;
1069                         opacity = isNumber(opacity) ? opacity : 1;
1070                         pct = stop.offset || i/(len-1);
1071                         pct *= (r * 2);
1072             pct = Math.round(100 * pct) + "%";
1073             oi = i > 0 ? i + 1 : "";
1074             gradientProps["opacity" + oi] = opacity + "";
1075             colorstring += ", " + pct + " " + color;
1076                 }
1077                 if(parseFloat(pct) < 100)
1078                 {
1079                         colorstring += ", 100% " + color;
1080                 }
1081                 gradientProps.colors = colorstring.substr(2);
1082                 return gradientProps;
1083         },
1085     /**
1086      * Adds a transform to the shape.
1087      *
1088      * @method _addTransform
1089      * @param {String} type The transform being applied.
1090      * @param {Array} args The arguments for the transform.
1091          * @private
1092          */
1093         _addTransform: function(type, args)
1094         {
1095         args = Y.Array(args);
1096         this._transform = Y_LANG.trim(this._transform + " " + type + "(" + args.join(", ") + ")");
1097         args.unshift(type);
1098         this._transforms.push(args);
1099         if(this.initialized)
1100         {
1101             this._updateTransform();
1102         }
1103         },
1104         
1105         /**
1106      * Applies all transforms.
1107      *
1108      * @method _updateTransform
1109          * @private
1110          */
1111         _updateTransform: function()
1112         {
1113                 var node = this.node,
1114             key,
1115                         transform,
1116                         transformOrigin,
1117             x = this.get("x"),
1118             y = this.get("y"),
1119             tx,
1120             ty,
1121             matrix = this.matrix,
1122             normalizedMatrix = this._normalizedMatrix,
1123             isPathShape = this instanceof Y.VMLPath,
1124             i = 0,
1125             len = this._transforms.length;
1126         if(this._transforms && this._transforms.length > 0)
1127                 {
1128             transformOrigin = this.get("transformOrigin");
1129        
1130             if(isPathShape)
1131             {
1132                 normalizedMatrix.translate(this._left, this._top);
1133             }
1134             //vml skew matrix transformOrigin ranges from -0.5 to 0.5.
1135             //subtract 0.5 from values
1136             tx = transformOrigin[0] - 0.5;
1137             ty = transformOrigin[1] - 0.5;
1138             
1139             //ensure the values are within the appropriate range to avoid errors
1140             tx = Math.max(-0.5, Math.min(0.5, tx));
1141             ty = Math.max(-0.5, Math.min(0.5, ty));
1142             for(; i < len; ++i)
1143             {
1144                 key = this._transforms[i].shift();
1145                 if(key)
1146                 {
1147                     normalizedMatrix[key].apply(normalizedMatrix, this._transforms[i]); 
1148                     matrix[key].apply(matrix, this._transforms[i]); 
1149                 }
1150                         }
1151             if(isPathShape)
1152             {
1153                 normalizedMatrix.translate(-this._left, -this._top);
1154             }
1155             transform = normalizedMatrix.a + "," + 
1156                         normalizedMatrix.c + "," + 
1157                         normalizedMatrix.b + "," + 
1158                         normalizedMatrix.d + "," + 
1159                         0 + "," +
1160                         0;
1161                 }
1162         this._graphic.addToRedrawQueue(this);    
1163         if(transform)
1164         {
1165             if(!this._skew)
1166             {
1167                 this._skew = DOCUMENT.createElement( '<skew class="vmlskew" xmlns="urn:schemas-microsft.com:vml" on="false" style="behavior:url(#default#VML);display:inline-block;" />');
1168                 this.node.appendChild(this._skew); 
1169             }
1170             this._skew.matrix = transform;
1171             this._skew.on = true;
1172             //use offset for translate
1173             this._skew.offset = this._getSkewOffsetValue(normalizedMatrix.dx) + "px, " + this._getSkewOffsetValue(normalizedMatrix.dy) + "px";
1174             this._skew.origin = tx + ", " + ty;
1175         }
1176         if(this._type != "path")
1177         {
1178             this._transforms = [];
1179         }
1180         node.style.left = x + "px";
1181         node.style.top =  y + "px";
1182     },
1183     
1184     /**
1185      * Normalizes the skew offset values between -32767 and 32767.
1186      *
1187      * @method _getSkewOffsetValue
1188      * @param {Number} val The value to normalize
1189      * @return Number
1190      * @private
1191      */
1192     _getSkewOffsetValue: function(val)
1193     {
1194         var sign = Y.MatrixUtil.sign(val),
1195             absVal = Math.abs(val);
1196         val = Math.min(absVal, 32767) * sign;
1197         return val;
1198     },
1199         
1200         /**
1201          * Storage for translateX
1202          *
1203      * @property _translateX
1204      * @type Number
1205          * @private
1206          */
1207         _translateX: 0,
1209         /**
1210          * Storage for translateY
1211          *
1212      * @property _translateY
1213      * @type Number
1214          * @private
1215          */
1216         _translateY: 0,
1217     
1218     /**
1219      * Storage for the transform attribute.
1220      *
1221      * @property _transform
1222      * @type String
1223      * @private
1224      */
1225     _transform: "",
1226         
1227     /**
1228          * Specifies a 2d translation.
1229          *
1230          * @method translate
1231          * @param {Number} x The value to transate on the x-axis.
1232          * @param {Number} y The value to translate on the y-axis.
1233          */
1234         translate: function(x, y)
1235         {
1236                 this._translateX += x;
1237                 this._translateY += y;
1238                 this._addTransform("translate", arguments);
1239         },
1241         /**
1242          * Translates the shape along the x-axis. When translating x and y coordinates,
1243          * use the `translate` method.
1244          *
1245          * @method translateX
1246          * @param {Number} x The value to translate.
1247          */
1248         translateX: function(x)
1249     {
1250         this._translateX += x;
1251         this._addTransform("translateX", arguments);
1252     },
1254         /**
1255          * Performs a translate on the y-coordinate. When translating x and y coordinates,
1256          * use the `translate` method.
1257          *
1258          * @method translateY
1259          * @param {Number} y The value to translate.
1260          */
1261         translateY: function(y)
1262     {
1263         this._translateY += y;
1264         this._addTransform("translateY", arguments);
1265     },
1267     /**
1268      * Skews the shape around the x-axis and y-axis.
1269      *
1270      * @method skew
1271      * @param {Number} x The value to skew on the x-axis.
1272      * @param {Number} y The value to skew on the y-axis.
1273      */
1274     skew: function(x, y)
1275     {
1276         this._addTransform("skew", arguments);
1277     },
1279         /**
1280          * Skews the shape around the x-axis.
1281          *
1282          * @method skewX
1283          * @param {Number} x x-coordinate
1284          */
1285          skewX: function(x)
1286          {
1287                 this._addTransform("skewX", arguments);
1288          },
1290         /**
1291          * Skews the shape around the y-axis.
1292          *
1293          * @method skewY
1294          * @param {Number} y y-coordinate
1295          */
1296          skewY: function(y)
1297          {
1298                 this._addTransform("skewY", arguments);
1299          },
1301         /**
1302          * Rotates the shape clockwise around it transformOrigin.
1303          *
1304          * @method rotate
1305          * @param {Number} deg The degree of the rotation.
1306          */
1307          rotate: function(deg)
1308          {
1309                 this._addTransform("rotate", arguments);
1310          },
1312         /**
1313          * Specifies a 2d scaling operation.
1314          *
1315          * @method scale
1316          * @param {Number} val
1317          */
1318         scale: function(x, y)
1319         {
1320                 this._addTransform("scale", arguments);
1321         },
1323         /**
1324      * Overrides default `on` method. Checks to see if its a dom interaction event. If so, 
1325      * return an event attached to the `node` element. If not, return the normal functionality.
1326      *
1327      * @method on
1328      * @param {String} type event type
1329      * @param {Object} callback function
1330          * @private
1331          */
1332         on: function(type, fn)
1333         {
1334                 if(Y.Node.DOM_EVENTS[type])
1335                 {
1336                         return Y.one("#" +  this.get("id")).on(type, fn);
1337                 }
1338                 return Y.on.apply(this, arguments);
1339         },
1341         /**
1342          * Draws the shape.
1343          *
1344          * @method _draw
1345          * @private
1346          */
1347         _draw: function()
1348         {
1349         },
1351         /**
1352      * Updates `Shape` based on attribute changes.
1353      *
1354      * @method _updateHandler
1355          * @private
1356          */
1357         _updateHandler: function(e)
1358         {
1359                 var host = this,
1360             node = host.node;
1361         host._fillChangeHandler();
1362         host._strokeChangeHandler();
1363         node.style.width = this.get("width") + "px";
1364         node.style.height = this.get("height") + "px"; 
1365         this._draw();
1366                 host._updateTransform();
1367         },
1369         /**
1370          * Creates a graphic node
1371          *
1372          * @method _createGraphicNode
1373          * @param {String} type node type to create
1374          * @return HTMLElement
1375          * @private
1376          */
1377         _createGraphicNode: function(type)
1378         {
1379                 type = type || this._type;
1380                 return DOCUMENT.createElement('<' + type + ' xmlns="urn:schemas-microsft.com:vml" style="behavior:url(#default#VML);display:inline-block;" class="vml' + type + '"/>');
1381         },
1383         /**
1384          * Value function for fill attribute
1385          *
1386          * @private
1387          * @method _getDefaultFill
1388          * @return Object
1389          */
1390         _getDefaultFill: function() {
1391                 return {
1392                         type: "solid",
1393                         cx: 0.5,
1394                         cy: 0.5,
1395                         fx: 0.5,
1396                         fy: 0.5,
1397                         r: 0.5
1398                 };
1399         },
1401         /**
1402          * Value function for stroke attribute
1403          *
1404          * @private
1405          * @method _getDefaultStroke
1406          * @return Object
1407          */
1408         _getDefaultStroke: function() 
1409         {
1410                 return {
1411                         weight: 1,
1412                         dashstyle: "none",
1413                         color: "#000",
1414                         opacity: 1.0
1415                 };
1416         },
1418     /**
1419      * Sets the value of an attribute.
1420      *
1421      * @method set
1422      * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can 
1423      * be passed in to set multiple attributes at once.
1424      * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as 
1425      * the name param.
1426      */
1427         set: function() 
1428         {
1429                 var host = this;
1430                 AttributeLite.prototype.set.apply(host, arguments);
1431                 if(host.initialized)
1432                 {
1433                         host._updateHandler();
1434                 }
1435         },
1437         /**
1438          * Returns the bounds for a shape.
1439          *
1440      * Calculates the a new bounding box from the original corner coordinates (base on size and position) and the transform matrix.
1441      * The calculated bounding box is used by the graphic instance to calculate its viewBox. 
1442      *
1443          * @method getBounds
1444      * @param {Matrix} [optional] cfg Reference to matrix instance
1445          * @return Object
1446          */
1447         getBounds: function(cfg)
1448         {
1449                 var stroke = this.get("stroke"),
1450                         w = this.get("width"),
1451                         h = this.get("height"),
1452                         x = this.get("x"),
1453                         y = this.get("y"),
1454             wt = 0;
1455                 if(stroke && stroke.weight)
1456                 {
1457                         wt = stroke.weight;
1458                 }
1459         w = (x + w + wt) - (x - wt); 
1460         h = (y + h + wt) - (y - wt);
1461         x -= wt;
1462         y -= wt;
1463                 return this._normalizedMatrix.getContentRect(w, h, x, y);
1464         },
1465         
1466     /**
1467      *  Destroys shape
1468      *
1469      *  @method destroy
1470      */
1471     destroy: function()
1472     {
1473         var graphic = this.get("graphic");
1474         if(graphic)
1475         {
1476             graphic.removeShape(this);
1477         }
1478         else
1479         {
1480             this._destroy();
1481         }
1482     },
1484     /**
1485      *  Implementation for shape destruction
1486      *
1487      *  @method destroy
1488      *  @protected
1489      */
1490     _destroy: function()
1491     {
1492         if(this.node)
1493         {   
1494             if(this._fillNode)
1495             {
1496                 this.node.removeChild(this._fillNode);
1497                 this._fillNode = null;
1498             }
1499             if(this._strokeNode)
1500             {
1501                 this.node.removeChild(this._strokeNode);
1502                 this._strokeNode = null;
1503             }
1504             Y.one(this.node).remove(true);
1505         }
1506     }
1507 }, Y.VMLDrawing.prototype));
1509 VMLShape.ATTRS = {
1510         /**
1511          * 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 
1512          * fraction of the shape's corresponding bounding box dimension. The default value is [0.5, 0.5].
1513          *
1514          * @config transformOrigin
1515          * @type Array
1516          */
1517         transformOrigin: {
1518                 valueFn: function()
1519                 {
1520                         return [0.5, 0.5];
1521                 }
1522         },
1523         
1524     /**
1525      * <p>A string containing, in order, transform operations applied to the shape instance. The `transform` string can contain the following values:
1526      *     
1527      *    <dl>
1528      *        <dt>rotate</dt><dd>Rotates the shape clockwise around it transformOrigin.</dd>
1529      *        <dt>translate</dt><dd>Specifies a 2d translation.</dd>
1530      *        <dt>skew</dt><dd>Skews the shape around the x-axis and y-axis.</dd>
1531      *        <dt>scale</dt><dd>Specifies a 2d scaling operation.</dd>
1532      *        <dt>translateX</dt><dd>Translates the shape along the x-axis.</dd>
1533      *        <dt>translateY</dt><dd>Translates the shape along the y-axis.</dd>
1534      *        <dt>skewX</dt><dd>Skews the shape around the x-axis.</dd>
1535      *        <dt>skewY</dt><dd>Skews the shape around the y-axis.</dd>
1536      *        <dt>matrix</dt><dd>Specifies a 2D transformation matrix comprised of the specified six values.</dd>      
1537      *    </dl>
1538      * </p>
1539      * <p>Applying transforms through the transform attribute will reset the transform matrix and apply a new transform. The shape class also contains corresponding methods for each transform
1540      * that will apply the transform to the current matrix. The below code illustrates how you might use the `transform` attribute to instantiate a recangle with a rotation of 45 degrees.</p>
1541             var myRect = new Y.Rect({
1542                 type:"rect",
1543                 width: 50,
1544                 height: 40,
1545                 transform: "rotate(45)"
1546             };
1547      * <p>The code below would apply `translate` and `rotate` to an existing shape.</p>
1548     
1549         myRect.set("transform", "translate(40, 50) rotate(45)");
1550          * @config transform
1551      * @type String  
1552          */
1553         transform: {
1554                 setter: function(val)
1555                 {
1556             var i = 0,
1557                 len,
1558                 transform;
1559             this.matrix.init(); 
1560             this._normalizedMatrix.init();      
1561             this._transforms = this.matrix.getTransformArray(val);
1562             len = this._transforms.length;
1563             for(;i < len; ++i)
1564             {
1565                 transform = this._transforms[i];
1566             }
1567             this._transform = val;
1568             return val;
1569                 },
1571         getter: function()
1572         {
1573             return this._transform;
1574         }
1575         },
1577         /**
1578          * Indicates the x position of shape.
1579          *
1580          * @config x
1581          * @type Number
1582          */
1583         x: {
1584                 value: 0
1585         },
1587         /**
1588          * Indicates the y position of shape.
1589          *
1590          * @config y
1591          * @type Number
1592          */
1593         y: {
1594                 value: 0
1595         },
1597         /**
1598          * Unique id for class instance.
1599          *
1600          * @config id
1601          * @type String
1602          */
1603         id: {
1604                 valueFn: function()
1605                 {
1606                         return Y.guid();
1607                 },
1609                 setter: function(val)
1610                 {
1611                         var node = this.node;
1612                         if(node)
1613                         {
1614                                 node.setAttribute("id", val);
1615                         }
1616                         return val;
1617                 }
1618         },
1619         
1620         /**
1621          * 
1622          * @config width
1623          */
1624         width: {
1625                 value: 0
1626         },
1628         /**
1629          * 
1630          * @config height
1631          */
1632         height: {
1633                 value: 0
1634         },
1636         /**
1637          * Indicates whether the shape is visible.
1638          *
1639          * @config visible
1640          * @type Boolean
1641          */
1642         visible: {
1643                 value: true,
1645                 setter: function(val){
1646                         var node = this.node,
1647                                 visibility = val ? "visible" : "hidden";
1648                         if(node)
1649                         {
1650                                 node.style.visibility = visibility;
1651                         }
1652                         return val;
1653                 }
1654         },
1656         /**
1657          * Contains information about the fill of the shape. 
1658      *  <dl>
1659      *      <dt>color</dt><dd>The color of the fill.</dd>
1660      *      <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the fill. The default value is 1.</dd>
1661      *      <dt>type</dt><dd>Type of fill.
1662      *          <dl>
1663      *              <dt>solid</dt><dd>Solid single color fill. (default)</dd>
1664      *              <dt>linear</dt><dd>Linear gradient fill.</dd>
1665      *              <dt>radial</dt><dd>Radial gradient fill.</dd>
1666      *          </dl>
1667      *      </dd>
1668      *  </dl>
1669      *  <p>If a `linear` or `radial` is specified as the fill type. The following additional property is used:
1670      *  <dl>
1671      *      <dt>stops</dt><dd>An array of objects containing the following properties:
1672      *          <dl>
1673      *              <dt>color</dt><dd>The color of the stop.</dd>
1674      *              <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the stop. The default value is 1. Note: No effect for IE 6 - 8</dd>
1675      *              <dt>offset</dt><dd>Number between 0 and 1 indicating where the color stop is positioned.</dd> 
1676      *          </dl>
1677      *      </dd>
1678      *      <p>Linear gradients also have the following property:</p>
1679      *      <dt>rotation</dt><dd>Linear gradients flow left to right by default. The rotation property allows you to change the flow by rotation. (e.g. A rotation of 180 would make the gradient pain from right to left.)</dd>
1680      *      <p>Radial gradients have the following additional properties:</p>
1681      *      <dt>r</dt><dd>Radius of the gradient circle.</dd>
1682      *      <dt>fx</dt><dd>Focal point x-coordinate of the gradient.</dd>
1683      *      <dt>fy</dt><dd>Focal point y-coordinate of the gradient.</dd>
1684      *  </dl>
1685      *  <p>The corresponding `SVGShape` class implements the following additional properties.</p>
1686      *  <dl>
1687      *      <dt>cx</dt><dd>
1688      *          <p>The x-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
1689      *      </dd>
1690      *      <dt>cy</dt><dd>
1691      *          <p>The y-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
1692      *      </dd>
1693      *  </dl>
1694      *  <p>These properties are not currently implemented in `CanvasShape` or `VMLShape`.</p> 
1695          *
1696          * @config fill
1697          * @type Object 
1698          */
1699         fill: {
1700                 valueFn: "_getDefaultFill",
1701                 
1702                 setter: function(val)
1703                 {
1704                         var i,
1705                                 fill,
1706                                 tmpl = this.get("fill") || this._getDefaultFill();
1707                         
1708                         if(val)
1709                         {
1710                                 //ensure, fill type is solid if color is explicitly passed.
1711                                 if(val.hasOwnProperty("color"))
1712                                 {
1713                                         val.type = "solid";
1714                                 }
1715                                 for(i in val)
1716                                 {
1717                                         if(val.hasOwnProperty(i))
1718                                         {   
1719                                                 tmpl[i] = val[i];
1720                                         }
1721                                 }
1722                         }
1723                         fill = tmpl;
1724                         if(fill && fill.color)
1725                         {
1726                                 if(fill.color === undefined || fill.color == "none")
1727                                 {
1728                                         fill.color = null;
1729                                 }
1730                         }
1731                         this._fillFlag = true;
1732             return fill;
1733                 }
1734         },
1736         /**
1737          * Contains information about the stroke of the shape.
1738      *  <dl>
1739      *      <dt>color</dt><dd>The color of the stroke.</dd>
1740      *      <dt>weight</dt><dd>Number that indicates the width of the stroke.</dd>
1741      *      <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the stroke. The default value is 1.</dd>
1742      *      <dt>dashstyle</dt>Indicates whether to draw a dashed stroke. When set to "none", a solid stroke is drawn. When set to an array, the first index indicates the
1743      *  length of the dash. The second index indicates the length of gap.
1744      *      <dt>linecap</dt><dd>Specifies the linecap for the stroke. The following values can be specified:
1745      *          <dl>
1746      *              <dt>butt (default)</dt><dd>Specifies a butt linecap.</dd>
1747      *              <dt>square</dt><dd>Specifies a sqare linecap.</dd>
1748      *              <dt>round</dt><dd>Specifies a round linecap.</dd>
1749      *          </dl>
1750      *      </dd>
1751      *      <dt>linejoin</dt><dd>Specifies a linejoin for the stroke. The following values can be specified:
1752      *          <dl>
1753      *              <dt>round (default)</dt><dd>Specifies that the linejoin will be round.</dd>
1754      *              <dt>bevel</dt><dd>Specifies a bevel for the linejoin.</dd>
1755      *              <dt>miter limit</dt><dd>An integer specifying the miter limit of a miter linejoin. If you want to specify a linejoin of miter, you simply specify the limit as opposed to having
1756      *  separate miter and miter limit values.</dd>
1757      *          </dl>
1758      *      </dd>
1759      *  </dl>
1760          *
1761          * @config stroke
1762          * @type Object
1763          */
1764         stroke: {
1765                 valueFn: "_getDefaultStroke",
1766                 
1767                 setter: function(val)
1768                 {
1769                         var i,
1770                                 stroke,
1771                 wt,
1772                                 tmpl = this.get("stroke") || this._getDefaultStroke();
1773                         if(val)
1774                         {
1775                 if(val.hasOwnProperty("weight"))
1776                 {
1777                     wt = parseInt(val.weight, 10);
1778                     if(!isNaN(wt))
1779                     {
1780                         val.weight = wt;
1781                     }
1782                 }
1783                                 for(i in val)
1784                                 {
1785                                         if(val.hasOwnProperty(i))
1786                                         {   
1787                                                 tmpl[i] = val[i];
1788                                         }
1789                                 }
1790                         }
1791                         stroke = tmpl;
1792             this._strokeFlag = true;
1793                         return stroke;
1794                 }
1795         },
1796         
1797         //Not used. Remove in future.
1798     autoSize: {
1799                 value: false
1800         },
1802         // Only implemented in SVG
1803         // Determines whether the instance will receive mouse events.
1804         // 
1805         // @config pointerEvents
1806         // @type string
1807         //
1808         pointerEvents: {
1809                 value: "visiblePainted"
1810         },
1812         /**
1813          * Dom node for the shape.
1814          *
1815          * @config node
1816          * @type HTMLElement
1817          * @readOnly
1818          */
1819         node: {
1820                 readOnly: true,
1822                 getter: function()
1823                 {
1824                         return this.node;
1825                 }
1826         },
1828         /**
1829          * Reference to the container Graphic.
1830          *
1831          * @config graphic
1832          * @type Graphic
1833          */
1834         graphic: {
1835                 readOnly: true,
1837                 getter: function()
1838                 {
1839                         return this._graphic;
1840                 }
1841         }
1843 Y.VMLShape = VMLShape;
1845  * <a href="http://www.w3.org/TR/NOTE-VML">VML</a> implementation of the <a href="Path.html">`Path`</a> class. 
1846  * `VMLPath` is not intended to be used directly. Instead, use the <a href="Path.html">`Path`</a> class. 
1847  * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> and <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> 
1848  * capabilities, the <a href="Path.html">`Path`</a> class will point to the `VMLPath` class.
1850  * @module graphics
1851  * @class VMLPath
1852  * @extends VMLShape
1853  */
1854 VMLPath = function()
1856         VMLPath.superclass.constructor.apply(this, arguments);
1859 VMLPath.NAME = "vmlPath";
1860 Y.extend(VMLPath, Y.VMLShape);
1861 VMLPath.ATTRS = Y.merge(Y.VMLShape.ATTRS, {
1862         /**
1863          * Indicates the width of the shape
1864          * 
1865          * @config width
1866          * @type Number
1867          */
1868         width: {
1869                 getter: function()
1870                 {
1871                         var val = Math.max(this._right - this._left, 0);
1872                         return val;
1873                 }
1874         },
1876         /**
1877          * Indicates the height of the shape
1878          * 
1879          * @config height
1880          * @type Number
1881          */
1882         height: {
1883                 getter: function()
1884                 {
1885                         return Math.max(this._bottom - this._top, 0);
1886                 }
1887         },
1888         
1889         /**
1890          * Indicates the path used for the node.
1891          *
1892          * @config path
1893          * @type String
1894      * @readOnly
1895          */
1896         path: {
1897                 readOnly: true,
1899                 getter: function()
1900                 {
1901                         return this._path;
1902                 }
1903         }
1905 Y.VMLPath = VMLPath;
1907  * <a href="http://www.w3.org/TR/NOTE-VML">VML</a> implementation of the <a href="Rect.html">`Rect`</a> class. 
1908  * `VMLRect` is not intended to be used directly. Instead, use the <a href="Rect.html">`Rect`</a> class. 
1909  * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> and <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> 
1910  * capabilities, the <a href="Rect.html">`Rect`</a> class will point to the `VMLRect` class.
1912  * @module graphics
1913  * @class VMLRect
1914  * @constructor
1915  */
1916 VMLRect = function()
1918         VMLRect.superclass.constructor.apply(this, arguments);
1920 VMLRect.NAME = "vmlRect"; 
1921 Y.extend(VMLRect, Y.VMLShape, {
1922         /**
1923          * Indicates the type of shape
1924          *
1925          * @property _type
1926          * @type String
1927      * @private
1928          */
1929         _type: "rect"
1931 VMLRect.ATTRS = Y.VMLShape.ATTRS;
1932 Y.VMLRect = VMLRect;
1934  * <a href="http://www.w3.org/TR/NOTE-VML">VML</a> implementation of the <a href="Ellipse.html">`Ellipse`</a> class. 
1935  * `VMLEllipse` is not intended to be used directly. Instead, use the <a href="Ellipse.html">`Ellipse`</a> class. 
1936  * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> and <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> 
1937  * capabilities, the <a href="Ellipse.html">`Ellipse`</a> class will point to the `VMLEllipse` class.
1939  * @module graphics
1940  * @class VMLEllipse
1941  * @constructor
1942  */
1943 VMLEllipse = function()
1945         VMLEllipse.superclass.constructor.apply(this, arguments);
1948 VMLEllipse.NAME = "vmlEllipse";
1950 Y.extend(VMLEllipse, Y.VMLShape, {
1951         /**
1952          * Indicates the type of shape
1953          *
1954          * @property _type
1955          * @type String
1956      * @private
1957          */
1958         _type: "oval"
1960 VMLEllipse.ATTRS = Y.merge(Y.VMLShape.ATTRS, {
1961         //
1962         // Horizontal radius for the ellipse. This attribute is not implemented in Canvas.
1963     // Will add in 3.4.1.
1964         //
1965         // @config xRadius
1966         // @type Number
1967         // @readOnly
1968         //
1969         xRadius: {
1970                 lazyAdd: false,
1972                 getter: function()
1973                 {
1974                         var val = this.get("width");
1975                         val = Math.round((val/2) * 100)/100;
1976                         return val;
1977                 },
1978                 
1979                 setter: function(val)
1980                 {
1981                         var w = val * 2; 
1982                         this.set("width", w);
1983                         return val;
1984                 }
1985         },
1987         //
1988         // Vertical radius for the ellipse. This attribute is not implemented in Canvas. 
1989     // Will add in 3.4.1.
1990         //
1991         // @config yRadius
1992         // @type Number
1993         // @readOnly
1994         //
1995         yRadius: {
1996                 lazyAdd: false,
1997                 
1998                 getter: function()
1999                 {
2000                         var val = this.get("height");
2001                         val = Math.round((val/2) * 100)/100;
2002                         return val;
2003                 },
2005                 setter: function(val)
2006                 {
2007                         var h = val * 2;
2008                         this.set("height", h);
2009                         return val;
2010                 }
2011         }
2013 Y.VMLEllipse = VMLEllipse;
2015  * <a href="http://www.w3.org/TR/NOTE-VML">VML</a> implementation of the <a href="Circle.html">`Circle`</a> class. 
2016  * `VMLCircle` is not intended to be used directly. Instead, use the <a href="Circle.html">`Circle`</a> class. 
2017  * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> and <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> 
2018  * capabilities, the <a href="Circle.html">`Circle`</a> class will point to the `VMLCircle` class.
2020  * @module graphics
2021  * @class VMLCircle
2022  * @constructor
2023  */
2024 VMLCircle = function(cfg)
2026         VMLCircle.superclass.constructor.apply(this, arguments);
2029 VMLCircle.NAME = "vmlCircle";
2031 Y.extend(VMLCircle, VMLShape, {
2032         /**
2033          * Indicates the type of shape
2034          *
2035          * @property _type
2036          * @type String
2037      * @private
2038          */
2039         _type: "oval"
2042 VMLCircle.ATTRS = Y.merge(VMLShape.ATTRS, {
2043         /**
2044          * Radius for the circle.
2045          *
2046          * @config radius
2047          * @type Number
2048          */
2049         radius: {
2050                 lazyAdd: false,
2052                 value: 0
2053         },
2055         /**
2056          * Indicates the width of the shape
2057          *
2058          * @config width
2059          * @type Number
2060          */
2061         width: {
2062         setter: function(val)
2063         {
2064             this.set("radius", val/2);
2065             return val;
2066         },
2068                 getter: function()
2069                 {   
2070                         var radius = this.get("radius"),
2071                         val = radius && radius > 0 ? radius * 2 : 0;
2072                         return val;
2073                 }
2074         },
2076         /**
2077          * Indicates the height of the shape
2078          *
2079          * @config height
2080          * @type Number
2081          */
2082         height: {
2083         setter: function(val)
2084         {
2085             this.set("radius", val/2);
2086             return val;
2087         },
2089                 getter: function()
2090                 {   
2091                         var radius = this.get("radius"),
2092                         val = radius && radius > 0 ? radius * 2 : 0;
2093                         return val;
2094                 }
2095         }
2097 Y.VMLCircle = VMLCircle;
2099  * Draws pie slices
2101  * @module graphics
2102  * @class VMLPieSlice
2103  * @constructor
2104  */
2105 VMLPieSlice = function()
2107         VMLPieSlice.superclass.constructor.apply(this, arguments);
2109 VMLPieSlice.NAME = "vmlPieSlice";
2110 Y.extend(VMLPieSlice, Y.VMLShape, Y.mix({
2111     /**
2112      * Indicates the type of shape
2113      *
2114      * @property _type
2115      * @type String
2116      * @private
2117      */
2118     _type: "shape",
2120         /**
2121          * Change event listener
2122          *
2123          * @private
2124          * @method _updateHandler
2125          */
2126         _draw: function(e)
2127         {
2128         var x = this.get("cx"),
2129             y = this.get("cy"),
2130             startAngle = this.get("startAngle"),
2131             arc = this.get("arc"),
2132             radius = this.get("radius");
2133         this.clear();
2134         this.drawWedge(x, y, startAngle, arc, radius);
2135                 this.end();
2136         }
2137  }, Y.VMLDrawing.prototype));
2138 VMLPieSlice.ATTRS = Y.mix({
2139     cx: {
2140         value: 0
2141     },
2143     cy: {
2144         value: 0
2145     },
2146     /**
2147      * Starting angle in relation to a circle in which to begin the pie slice drawing.
2148      *
2149      * @config startAngle
2150      * @type Number
2151      */
2152     startAngle: {
2153         value: 0
2154     },
2156     /**
2157      * Arc of the slice.
2158      *
2159      * @config arc
2160      * @type Number
2161      */
2162     arc: {
2163         value: 0
2164     },
2166     /**
2167      * Radius of the circle in which the pie slice is drawn
2168      *
2169      * @config radius
2170      * @type Number
2171      */
2172     radius: {
2173         value: 0
2174     }
2175 }, Y.VMLShape.ATTRS);
2176 Y.VMLPieSlice = VMLPieSlice;
2178  * <a href="http://www.w3.org/TR/NOTE-VML">VML</a> implementation of the <a href="Graphic.html">`Graphic`</a> class. 
2179  * `VMLGraphic` is not intended to be used directly. Instead, use the <a href="Graphic.html">`Graphic`</a> class. 
2180  * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> and <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> 
2181  * capabilities, the <a href="Graphic.html">`Graphic`</a> class will point to the `VMLGraphic` class.
2183  * @module graphics
2184  * @class VMLGraphic
2185  * @constructor
2186  */
2187 VMLGraphic = function() {
2188     VMLGraphic.superclass.constructor.apply(this, arguments);    
2191 VMLGraphic.NAME = "vmlGraphic";
2193 VMLGraphic.ATTRS = {
2194     /**
2195      * Whether or not to render the `Graphic` automatically after to a specified parent node after init. This can be a Node instance or a CSS selector string.
2196      * 
2197      * @config render
2198      * @type Node | String 
2199      */
2200     render: {},
2201         
2202     /**
2203          * Unique id for class instance.
2204          *
2205          * @config id
2206          * @type String
2207          */
2208         id: {
2209                 valueFn: function()
2210                 {
2211                         return Y.guid();
2212                 },
2214                 setter: function(val)
2215                 {
2216                         var node = this._node;
2217                         if(node)
2218                         {
2219                                 node.setAttribute("id", val);
2220                         }
2221                         return val;
2222                 }
2223         },
2225     /**
2226      * Key value pairs in which a shape instance is associated with its id.
2227      *
2228      *  @config shapes
2229      *  @type Object
2230      *  @readOnly
2231      */
2232     shapes: {
2233         readOnly: true,
2235         getter: function()
2236         {
2237             return this._shapes;
2238         }
2239     },
2241     /**
2242      *  Object containing size and coordinate data for the content of a Graphic in relation to the coordSpace node.
2243      *
2244      *  @config contentBounds
2245      *  @type Object
2246      */
2247     contentBounds: {
2248         readOnly: true,
2250         getter: function()
2251         {
2252             return this._contentBounds;
2253         }
2254     },
2256     /**
2257      *  The html element that represents to coordinate system of the Graphic instance.
2258      *
2259      *  @config node
2260      *  @type HTMLElement
2261      */
2262     node: {
2263         readOnly: true,
2265         getter: function()
2266         {
2267             return this._node;
2268         }
2269     },
2271         /**
2272          * Indicates the width of the `Graphic`. 
2273          *
2274          * @config width
2275          * @type Number
2276          */
2277     width: {
2278         setter: function(val)
2279         {
2280             if(this._node)
2281             {
2282                 this._node.style.width = val + "px";
2283             }
2284             return val;
2285         }
2286     },
2288         /**
2289          * Indicates the height of the `Graphic`. 
2290          *
2291          * @config height 
2292          * @type Number
2293          */
2294     height: {
2295         setter: function(val)
2296         {
2297             if(this._node)
2298             {
2299                 this._node.style.height = val + "px";
2300             }
2301             return val;
2302         }
2303     },
2305     /**
2306      *  Determines how the size of instance is calculated. If true, the width and height are determined by the size of the contents.
2307      *  If false, the width and height values are either explicitly set or determined by the size of the parent node's dimensions.
2308      *
2309      *  @config autoSize
2310      *  @type Boolean
2311      *  @default false
2312      */
2313     autoSize: {
2314         value: false
2315     },
2317     /**
2318      * The contentBounds will resize to greater values but not values. (for performance)
2319      * When resizing the contentBounds down is desirable, set the resizeDown value to true.
2320      *
2321      * @config resizeDown 
2322      * @type Boolean
2323      */
2324     resizeDown: {
2325         getter: function()
2326         {
2327             return this._resizeDown;
2328         },
2330         setter: function(val)
2331         {
2332             this._resizeDown = val;
2333             if(this._node)
2334             {
2335                 this._redraw();
2336             }
2337             return val;
2338         }
2339     },
2341         /**
2342          * Indicates the x-coordinate for the instance.
2343          *
2344          * @config x
2345          * @type Number
2346          */
2347     x: {
2348         getter: function()
2349         {
2350             return this._x;
2351         },
2353         setter: function(val)
2354         {
2355             this._x = val;
2356             if(this._node)
2357             {
2358                 this._node.style.left = val + "px";
2359             }
2360             return val;
2361         }
2362     },
2364         /**
2365          * Indicates the y-coordinate for the instance.
2366          *
2367          * @config y
2368          * @type Number
2369          */
2370     y: {
2371         getter: function()
2372         {
2373             return this._y;
2374         },
2376         setter: function(val)
2377         {
2378             this._y = val;
2379             if(this._node)
2380             {
2381                 this._node.style.top = val + "px";
2382             }
2383             return val;
2384         }
2385     },
2387     /**
2388      * Indicates whether or not the instance will automatically redraw after a change is made to a shape.
2389      * This property will get set to false when batching operations.
2390      *
2391      * @config autoDraw
2392      * @type Boolean
2393      * @default true
2394      * @private
2395      */
2396     autoDraw: {
2397         value: true
2398     },
2400     visible: {
2401         value: true,
2403         setter: function(val)
2404         {
2405             this._toggleVisible(val);
2406             return val;
2407         }
2408     }
2411 Y.extend(VMLGraphic, Y.GraphicBase, {
2412     /**
2413      * Storage for `x` attribute.
2414      *
2415      * @property _x
2416      * @type Number
2417      * @private
2418      */
2419     _x: 0,
2421     /**
2422      * Storage for `y` attribute.
2423      *
2424      * @property _y
2425      * @type Number
2426      * @private
2427      */
2428     _y: 0,
2430     /**
2431      * Gets the current position of the graphic instance in page coordinates.
2432      *
2433      * @method getXY
2434      * @return Array The XY position of the shape.
2435      */
2436     getXY: function()
2437     {
2438         var node = Y.one(this._node),
2439             xy;
2440         if(node)
2441         {
2442             xy = node.getXY();
2443         }
2444         return xy;
2445     },
2447     /**
2448      * @private
2449      * @property _resizeDown 
2450      * @type Boolean
2451      */
2452     _resizeDown: false,
2454     /**
2455      * Initializes the class.
2456      *
2457      * @method initializer
2458      * @private
2459      */
2460     initializer: function(config) {
2461         var render = this.get("render");
2462         this._shapes = {};
2463                 this._contentBounds = {
2464             left: 0,
2465             top: 0,
2466             right: 0,
2467             bottom: 0
2468         };
2469         this._node = this._createGraphic();
2470         this._node.setAttribute("id", this.get("id"));
2471         if(render)
2472         {
2473             this.render(render);
2474         }
2475     },
2476     
2477     /**
2478      * Adds the graphics node to the dom.
2479      * 
2480      * @method render
2481      * @param {HTMLElement} parentNode node in which to render the graphics node into.
2482      */
2483     render: function(render) {
2484         var parentNode = Y.one(render),
2485             w = this.get("width") || parseInt(parentNode.getComputedStyle("width"), 10),
2486             h = this.get("height") || parseInt(parentNode.getComputedStyle("height"), 10);
2487         parentNode = parentNode || DOCUMENT.body;
2488         parentNode.appendChild(this._node);
2489         this.setSize(w, h);
2490         this.parentNode = parentNode;
2491         this.set("width", w);
2492         this.set("height", h);
2493         return this;
2494     },
2496     /**
2497      * Removes all nodes.
2498      *
2499      * @method destroy
2500      */
2501     destroy: function()
2502     {
2503         this.clear();
2504         Y.one(this._node).remove(true);
2505     },
2507     /**
2508      * Generates a shape instance by type.
2509      *
2510      * @method addShape
2511      * @param {Object} cfg attributes for the shape
2512      * @return Shape
2513      */
2514     addShape: function(cfg)
2515     {
2516         cfg.graphic = this;
2517         var shapeClass = this._getShapeClass(cfg.type),
2518             shape = new shapeClass(cfg);
2519         this._appendShape(shape);
2520         return shape;
2521     },
2523     /**
2524      * Adds a shape instance to the graphic instance.
2525      *
2526      * @method _appendShape
2527      * @param {Shape} shape The shape instance to be added to the graphic.
2528      * @private
2529      */
2530     _appendShape: function(shape)
2531     {
2532         var node = shape.node,
2533             parentNode = this._frag || this._node;
2534         if(this.get("autoDraw")) 
2535         {
2536             parentNode.appendChild(node);
2537         }
2538         else
2539         {
2540             this._getDocFrag().appendChild(node);
2541         }
2542     },
2544     /**
2545      * Removes a shape instance from from the graphic instance.
2546      *
2547      * @method removeShape
2548      * @param {Shape|String} shape The instance or id of the shape to be removed.
2549      */
2550     removeShape: function(shape)
2551     {
2552         if(!shape instanceof VMLShape)
2553         {
2554             if(Y_LANG.isString(shape))
2555             {
2556                 shape = this._shapes[shape];
2557             }
2558         }
2559         if(shape && shape instanceof VMLShape)
2560         {
2561             shape._destroy();
2562             this._shapes[shape.get("id")] = null;
2563             delete this._shapes[shape.get("id")];
2564         }
2565         if(this.get("autoDraw"))
2566         {
2567             this._redraw();
2568         }
2569     },
2571     /**
2572      * Removes all shape instances from the dom.
2573      *
2574      * @method removeAllShapes
2575      */
2576     removeAllShapes: function()
2577     {
2578         var shapes = this._shapes,
2579             i;
2580         for(i in shapes)
2581         {
2582             if(shapes.hasOwnProperty(i))
2583             {
2584                 shapes[i].destroy();
2585             }
2586         }
2587         this._shapes = {};
2588     },
2590     /**
2591      * Removes all child nodes.
2592      *
2593      * @method _removeChildren
2594      * @param node
2595      * @private
2596      */
2597     _removeChildren: function(node)
2598     {
2599         if(node.hasChildNodes())
2600         {
2601             var child;
2602             while(node.firstChild)
2603             {
2604                 child = node.firstChild;
2605                 this._removeChildren(child);
2606                 node.removeChild(child);
2607             }
2608         }
2609     },
2611     /**
2612      * Clears the graphics object.
2613      *
2614      * @method clear
2615      */
2616     clear: function() {
2617         this.removeAllShapes();
2618         this._removeChildren(this._node);
2619     },
2621     /**
2622      * Toggles visibility
2623      *
2624      * @method _toggleVisible
2625      * @param {Boolean} val indicates visibilitye
2626      * @private
2627      */
2628     _toggleVisible: function(val)
2629     {
2630         var i,
2631             shapes = this._shapes,
2632             visibility = val ? "visible" : "hidden";
2633         if(shapes)
2634         {
2635             for(i in shapes)
2636             {
2637                 if(shapes.hasOwnProperty(i))
2638                 {
2639                     shapes[i].set("visible", val);
2640                 }
2641             }
2642         }
2643         this._node.style.visibility = visibility;
2644     },
2646     /**
2647      * Sets the size of the graphics object.
2648      * 
2649      * @method setSize
2650      * @param w {Number} width to set for the instance.
2651      * @param h {Number} height to set for the instance.
2652      */
2653     setSize: function(w, h) {
2654         w = Math.round(w);
2655         h = Math.round(h);
2656         this._node.style.width = w + 'px';
2657         this._node.style.height = h + 'px';
2658         this._node.coordSize = w + ' ' + h;
2659     },
2661     /**
2662      * Sets the positon of the graphics object.
2663      *
2664      * @method setPosition
2665      * @param {Number} x x-coordinate for the object.
2666      * @param {Number} y y-coordinate for the object.
2667      */
2668     setPosition: function(x, y)
2669     {
2670         x = Math.round(x);
2671         y = Math.round(y);
2672         this._node.style.left = x + "px";
2673         this._node.style.top = y + "px";
2674     },
2676     /**
2677      * Creates a group element
2678      *
2679      * @method _createGraphic
2680      * @private
2681      */
2682     _createGraphic: function() {
2683         var group = DOCUMENT.createElement('<group xmlns="urn:schemas-microsft.com:vml" style="behavior:url(#default#VML);display:block;zoom:1;" />');
2684                 group.style.display = "block";
2685         group.style.position = 'absolute';
2686         return group;
2687     },
2689     /**
2690      * Creates a graphic node
2691      *
2692      * @method _createGraphicNode
2693      * @param {String} type node type to create
2694      * @param {String} pe specified pointer-events value
2695      * @return HTMLElement
2696      * @private
2697      */
2698     _createGraphicNode: function(type)
2699     {
2700         return DOCUMENT.createElement('<' + type + ' xmlns="urn:schemas-microsft.com:vml" style="behavior:url(#default#VML);display:inline-block;zoom:1;" />');
2701     
2702     },
2704     /**
2705      * Returns a shape based on the id of its dom node.
2706      *
2707      * @method getShapeById
2708      * @param {String} id Dom id of the shape's node attribute.
2709      * @return Shape
2710      */
2711     getShapeById: function(id)
2712     {
2713         return this._shapes[id];
2714     },
2716     /**
2717      * Returns a shape class. Used by `addShape`. 
2718      *
2719      * @method _getShapeClass
2720      * @param {Shape | String} val Indicates which shape class. 
2721      * @return Function 
2722      * @private
2723      */
2724     _getShapeClass: function(val)
2725     {
2726         var shape = this._shapeClass[val];
2727         if(shape)
2728         {
2729             return shape;
2730         }
2731         return val;
2732     },
2734     /**
2735      * Look up for shape classes. Used by `addShape` to retrieve a class for instantiation.
2736      *
2737      * @property _shapeClass
2738      * @type Object
2739      * @private
2740      */
2741     _shapeClass: {
2742         circle: Y.VMLCircle,
2743         rect: Y.VMLRect,
2744         path: Y.VMLPath,
2745         ellipse: Y.VMLEllipse,
2746         pieslice: Y.VMLPieSlice
2747     },
2749         /**
2750          * Allows for creating multiple shapes in order to batch appending and redraw operations.
2751          *
2752          * @method batch
2753          * @param {Function} method Method to execute.
2754          */
2755     batch: function(method)
2756     {
2757         var autoDraw = this.get("autoDraw");
2758         this.set("autoDraw", false);
2759         method.apply();
2760         this._redraw();
2761         this.set("autoDraw", autoDraw);
2762     },
2763     
2764     /**
2765      * Returns a document fragment to for attaching shapes.
2766      *
2767      * @method _getDocFrag
2768      * @return DocumentFragment
2769      * @private
2770      */
2771     _getDocFrag: function()
2772     {
2773         if(!this._frag)
2774         {
2775             this._frag = DOCUMENT.createDocumentFragment();
2776         }
2777         return this._frag;
2778     },
2780     /**
2781      * Adds a shape to the redraw queue and calculates the contentBounds. 
2782      *
2783      * @method addToRedrawQueue
2784      * @param shape {VMLShape}
2785      * @protected
2786      */
2787     addToRedrawQueue: function(shape)
2788     {
2789         var shapeBox,
2790             box;
2791         this._shapes[shape.get("id")] = shape;
2792         if(!this._resizeDown)
2793         {
2794             shapeBox = shape.getBounds();
2795             box = this._contentBounds;
2796             box.left = box.left < shapeBox.left ? box.left : shapeBox.left;
2797             box.top = box.top < shapeBox.top ? box.top : shapeBox.top;
2798             box.right = box.right > shapeBox.right ? box.right : shapeBox.right;
2799             box.bottom = box.bottom > shapeBox.bottom ? box.bottom : shapeBox.bottom;
2800             box.width = box.right - box.left;
2801             box.height = box.bottom - box.top;
2802             this._contentBounds = box;
2803         }
2804         if(this.get("autoDraw")) 
2805         {
2806             this._redraw();
2807         }
2808     },
2810     /**
2811      * Redraws all shapes.
2812      *
2813      * @method _redraw
2814      * @private
2815      */
2816     _redraw: function()
2817     {
2818         var box = this._resizeDown ? this._getUpdatedContentBounds() : this._contentBounds;
2819         if(this.get("autoSize"))
2820         {
2821             this.setSize(box.right, box.bottom);
2822         }
2823         if(this._frag)
2824         {
2825             this._node.appendChild(this._frag);
2826             this._frag = null;
2827         }
2828     },
2829     
2830     /**
2831      * Recalculates and returns the `contentBounds` for the `Graphic` instance.
2832      *
2833      * @method _getUpdatedContentBounds
2834      * @return {Object} 
2835      * @private
2836      */
2837     _getUpdatedContentBounds: function()
2838     {
2839         var bounds,
2840             i,
2841             shape,
2842             queue = this._shapes,
2843             box = {
2844                 left: 0,
2845                 top: 0,
2846                 right: 0,
2847                 bottom: 0
2848             };
2849         for(i in queue)
2850         {
2851             if(queue.hasOwnProperty(i))
2852             {
2853                 shape = queue[i];
2854                 bounds = shape.getBounds();
2855                 box.left = Math.min(box.left, bounds.left);
2856                 box.top = Math.min(box.top, bounds.top);
2857                 box.right = Math.max(box.right, bounds.right);
2858                 box.bottom = Math.max(box.bottom, bounds.bottom);
2859             }
2860         }
2861         box.width = box.right - box.left;
2862         box.height = box.bottom - box.top;
2863         this._contentBounds = box;
2864         return box;
2865     }
2867 Y.VMLGraphic = VMLGraphic;
2871 }, '3.5.1' ,{skinnable:false, requires:['graphics']});