3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
7 YUI.add('graphics-vml', function(Y) {
10 IS_NUM = Y_LANG.isNumber,
11 IS_ARRAY = Y_LANG.isArray,
13 Y_SELECTOR = Y.Selector,
14 DOCUMENT = Y.config.doc,
15 AttributeLite = Y.AttributeLite,
24 function VMLDrawing() {}
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.
36 VMLDrawing.prototype = {
38 * Current x position of the drqwing.
47 * Current y position of the drqwing.
56 * Draws a bezier curve.
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.
66 curveTo: function(cp1x, cp1y, cp2x, cp2y, x, y) {
73 this._path += ' c ' + Math.round(cp1x) + ", " + Math.round(cp1y) + ", " + Math.round(cp2x) + ", " + Math.round(cp2y) + ", " + x + ", " + 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);
85 * Draws a quadratic bezier curve.
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.
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);
107 * @param {Number} x x-coordinate
108 * @param {Number} y y-coordinate
109 * @param {Number} w width
110 * @param {Number} h height
112 drawRect: function(x, y, w, h) {
114 this.lineTo(x + w, y);
115 this.lineTo(x + w, y + h);
116 this.lineTo(x, y + h);
124 * Draws a rectangle with rounded corners.
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
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);
148 * Draws a circle. Used internally by `CanvasCircle` class.
151 * @param {Number} x y-coordinate
152 * @param {Number} y x-coordinate
153 * @param {Number} r radius
156 drawCircle: function(x, y, radius) {
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;
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
177 drawEllipse: function(x, y, w, h) {
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;
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
199 drawDiamond: function(x, y, width, height)
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);
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.
223 drawWedge: function(x, y, startAngle, arc, radius, yRadius)
225 var diameter = radius * 2;
228 yRadius = yRadius || radius;
229 radius = Math.round(radius);
230 yRadius = Math.round(yRadius);
231 if(Math.abs(arc) > 360)
235 startAngle *= -65535;
237 this._path += " m " + x + " " + y + " ae " + x + " " + y + " " + radius + " " + yRadius + " " + startAngle + " " + arc;
238 this._trackSize(diameter, diameter);
245 * Draws a line segment using the current line style from the current drawing position to the specified x and y coordinates.
248 * @param {Number} point1 x-coordinate for the end point.
249 * @param {Number} point2 y-coordinate for the end point.
251 lineTo: function(point1, point2, etc) {
252 var args = arguments,
255 if (typeof point1 === 'string' || typeof point1 === 'number') {
256 args = [[point1, point2]];
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];
274 * Moves the current drawing position to specified x and y coordinates.
277 * @param {Number} x x-coordinate for the end point.
278 * @param {Number} y y-coordinate for the end point.
280 moveTo: function(x, y) {
285 this._path += ' m ' + Math.round(x) + ', ' + Math.round(y);
286 this._trackSize(x, y);
297 _closePath: function()
299 var fill = this.get("fill"),
300 stroke = this.get("stroke"),
302 w = this.get("width"),
303 h = this.get("height"),
306 this._fillChangeHandler();
307 this._strokeChangeHandler();
310 if(fill && fill.color)
321 node.path = path + pathEnd;
323 if(!isNaN(w) && !isNaN(h))
325 node.coordSize = w + ', ' + h;
326 node.style.position = "absolute";
327 node.style.width = w + "px";
328 node.style.height = h + "px";
331 this._updateTransform();
335 * Completes a drawing operation.
345 * Ends a fill and stroke
349 closePath: function()
351 this._path += ' x e ';
371 * Updates the size of the graphics object
374 * @param {Number} w width
375 * @param {Number} h height
378 _trackSize: function(w, h) {
379 if (w > this._right) {
390 if (h > this._bottom)
394 this._width = this._right - this._left;
395 this._height = this._bottom - this._top;
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.
420 * @param {Object} cfg (optional) Attribute configs
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({
434 * Indicates the type of shape
443 * Init method, invoked during construction.
444 * Calls `initializer` method.
451 this.initializer.apply(this, arguments);
455 * Initializes the shape
458 * @method _initialize
460 initializer: function(cfg)
463 graphic = cfg.graphic;
467 this._setGraphic(graphic);
469 this._updateHandler();
473 * Set the Graphic instance for the shape.
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.
480 _setGraphic: function(render)
483 if(render instanceof Y.VMLGraphic)
485 this._graphic = render;
489 render = Y.one(render);
490 graphic = new Y.VMLGraphic({
493 graphic._appendShape(this);
494 this._graphic = graphic;
499 * Creates the dom node for the shape.
502 * @return HTMLElement
505 createNode: function()
510 w = this.get("width"),
511 h = this.get("height"),
515 visibility = this.get("visible") ? "visible" : "hidden",
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();
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)
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"';
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 + '"';
547 strokestring += ' endcap="' + endcap + '"';
551 strokestring += ' joinstyle="' + joinstyle + '"';
555 strokestring += ' miterlimit="' + miterlimit + '"';
559 strokestring += ' dashstyle="' + dashstyle + '"';
561 strokestring += '></stroke>';
562 this._strokeNode = DOCUMENT.createElement(strokestring);
563 nodestring += ' stroked="t"';
567 nodestring += ' stroked="f"';
573 fillstring = fill.node;
574 this._fillNode = DOCUMENT.createElement(fillstring);
578 nodestring += ' fillcolor="' + fill.color + '"';
580 nodestring += ' filled="' + fill.filled + '"';
585 nodestring += '</' + type + '>';
587 node = DOCUMENT.createElement(nodestring);
590 node.appendChild(this._strokeNode);
594 node.appendChild(this._fillNode);
598 this._strokeFlag = false;
599 this._fillFlag = false;
603 * Add a class name to each node.
606 * @param {String} className the class name to add to the node's class attribute
608 addClass: function(className)
610 var node = this.node;
611 Y_DOM.addClass(node, className);
615 * Removes a class name from each node.
617 * @method removeClass
618 * @param {String} className the class name to remove from the node's class attribute
620 removeClass: function(className)
622 var node = this.node;
623 Y_DOM.removeClass(node, className);
627 * Gets the current position of the node in page coordinates.
630 * @return Array The XY position of the shape.
634 var graphic = this._graphic,
635 parentXY = graphic.getXY(),
638 return [parentXY[0] + x, parentXY[1] + y];
642 * Set the position of the shape in page coordinates, regardless of how the node is positioned.
645 * @param {Array} Contains x & y values for new position (coordinates are page-based)
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]);
657 * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
660 * @param {VMLShape | HTMLElement} needle The possible node or descendent
661 * @return Boolean Whether or not this shape is the needle or its ancestor.
663 contains: function(needle)
665 return needle === Y.one(this.node);
669 * Compares nodes to determine if they match.
670 * Node instances can be compared to each other and/or HTMLElements.
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.
675 compareTo: function(refNode) {
676 var node = this.node;
678 return node === refNode;
682 * Test if the supplied node matches the supplied selector.
685 * @param {String} selector The CSS selector to test against.
686 * @return Boolean Wheter or not the shape matches the selector.
688 test: function(selector)
690 return Y_SELECTOR.test(this.node, selector);
694 * Calculates and returns properties for setting an initial stroke.
696 * @method _getStrokeProps
701 _getStrokeProps: function()
704 stroke = this.get("stroke"),
713 if(stroke && stroke.weight && stroke.weight > 0)
716 linecap = stroke.linecap || "flat";
717 linejoin = stroke.linejoin || "round";
718 if(linecap != "round" && linecap != "square")
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))
735 len = dashstyle.length;
736 for(i = 0; i < len; ++i)
739 dash[i] = val / stroke.weight;
742 if(linejoin == "round" || linejoin == "bevel")
744 props.joinstyle = linejoin;
748 linejoin = parseInt(linejoin, 10);
751 props.miterlimit = Math.max(linejoin, 1);
752 props.joinstyle = "miter";
755 props.dashstyle = dash;
761 * Adds a stroke to the shape node.
763 * @method _strokeChangeHandler
766 _strokeChangeHandler: function(e)
768 if(!this._strokeFlag)
772 var node = this.node,
773 stroke = this.get("stroke"),
782 if(stroke && stroke.weight && stroke.weight > 0)
784 linecap = stroke.linecap || "flat";
785 linejoin = stroke.linejoin || "round";
786 if(linecap != "round" && linecap != "square")
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;
796 node.strokeColor = stroke.color;
797 node.strokeWeight = stroke.weight + "px";
798 if(!this._strokeNode)
800 this._strokeNode = this._createGraphicNode("stroke");
801 node.appendChild(this._strokeNode);
803 this._strokeNode.endcap = linecap;
804 this._strokeNode.opacity = stroke.opacity;
805 if(IS_ARRAY(dashstyle))
808 len = dashstyle.length;
809 for(i = 0; i < len; ++i)
812 dash[i] = val / stroke.weight;
815 if(linejoin == "round" || linejoin == "bevel")
817 this._strokeNode.joinstyle = linejoin;
821 linejoin = parseInt(linejoin, 10);
824 this._strokeNode.miterlimit = Math.max(linejoin, 1);
825 this._strokeNode.joinstyle = "miter";
828 this._strokeNode.dashstyle = dash;
829 this._strokeNode.on = true;
835 this._strokeNode.on = false;
837 node.stroked = false;
839 this._strokeFlag = false;
843 * Calculates and returns properties for setting an initial fill.
845 * @method _getFillProps
850 _getFillProps: function()
852 var fill = this.get("fill"),
863 if(fill.type == "radial" || fill.type == "linear")
865 fillOpacity = parseFloat(fill.opacity);
866 fillOpacity = IS_NUM(fillOpacity) ? fillOpacity : 1;
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 + '"';
872 if(gradient.hasOwnProperty(i))
874 fillstring += ' ' + i + '="' + gradient[i] + '"';
878 props.node = fillstring;
882 fillOpacity = parseFloat(fill.opacity);
884 props.color = fill.color;
885 if(IS_NUM(fillOpacity))
887 fillOpacity = Math.max(Math.min(fillOpacity, 1), 0);
888 props.opacity = fillOpacity;
891 props.node = '<fill xmlns="urn:schemas-microsft.com:vml" class="vmlfill" style="behavior:url(#default#VML);display:inline-block;" type="solid" opacity="' + fillOpacity + '"/>';
895 props.filled = filled;
901 * Adds a fill to the shape node.
903 * @method _fillChangeHandler
906 _fillChangeHandler: function(e)
912 var node = this.node,
913 fill = this.get("fill"),
921 if(fill.type == "radial" || fill.type == "linear")
924 gradient = this._getGradientFill(fill);
929 if(gradient.hasOwnProperty(i))
933 this._fillNode.colors.value = gradient[i];
937 this._fillNode[i] = gradient[i];
944 fillstring = '<fill xmlns="urn:schemas-microsft.com:vml" class="vmlfill" style="behavior:url(#default#VML);display:inline-block;"';
947 if(gradient.hasOwnProperty(i))
949 fillstring += ' ' + i + '="' + gradient[i] + '"';
953 this._fillNode = DOCUMENT.createElement(fillstring);
954 node.appendChild(this._fillNode);
959 node.fillcolor = fill.color;
960 fillOpacity = parseFloat(fill.opacity);
962 if(IS_NUM(fillOpacity) && fillOpacity < 1)
964 fill.opacity = fillOpacity;
967 if(this._fillNode.getAttribute("type") != "solid")
969 this._fillNode.type = "solid";
971 this._fillNode.opacity = fillOpacity;
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);
980 else if(this._fillNode)
982 this._fillNode.opacity = 1;
983 this._fillNode.type = "solid";
987 node.filled = filled;
988 this._fillFlag = false;
991 //not used. remove next release.
992 _updateFillNode: function(node)
996 this._fillNode = this._createGraphicNode("fill");
997 node.appendChild(this._fillNode);
1002 * Calculates and returns an object containing gradient properties for a fill node.
1004 * @method _getGradientFill
1005 * @param {Object} fill Object containing fill properties.
1009 _getGradientFill: function(fill)
1011 var gradientProps = {},
1015 w = this.get("width"),
1016 h = this.get("height"),
1033 rotation = fill.rotation || 0;
1034 if(type === "linear")
1038 rotation = Math.abs(rotation - 270);
1040 else if(rotation < 360)
1042 rotation = 270 + (360 - rotation);
1048 gradientProps.type = "gradient";//"gradientunscaled";
1049 gradientProps.angle = rotation;
1051 else if(type === "radial")
1053 gradientBoxWidth = w * (r * 2);
1054 gradientBoxHeight = h * (r * 2);
1055 fx = r * 2 * (fx - 0.5);
1056 fy = r * 2 * (fy - 0.5);
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) + "%";
1065 for(;i < len; ++i) {
1068 opacity = stop.opacity;
1069 opacity = isNumber(opacity) ? opacity : 1;
1070 pct = stop.offset || i/(len-1);
1072 pct = Math.round(100 * pct) + "%";
1073 oi = i > 0 ? i + 1 : "";
1074 gradientProps["opacity" + oi] = opacity + "";
1075 colorstring += ", " + pct + " " + color;
1077 if(parseFloat(pct) < 100)
1079 colorstring += ", 100% " + color;
1081 gradientProps.colors = colorstring.substr(2);
1082 return gradientProps;
1086 * Adds a transform to the shape.
1088 * @method _addTransform
1089 * @param {String} type The transform being applied.
1090 * @param {Array} args The arguments for the transform.
1093 _addTransform: function(type, args)
1095 args = Y.Array(args);
1096 this._transform = Y_LANG.trim(this._transform + " " + type + "(" + args.join(", ") + ")");
1098 this._transforms.push(args);
1099 if(this.initialized)
1101 this._updateTransform();
1106 * Applies all transforms.
1108 * @method _updateTransform
1111 _updateTransform: function()
1113 var node = this.node,
1121 matrix = this.matrix,
1122 normalizedMatrix = this._normalizedMatrix,
1123 isPathShape = this instanceof Y.VMLPath,
1125 len = this._transforms.length;
1126 if(this._transforms && this._transforms.length > 0)
1128 transformOrigin = this.get("transformOrigin");
1132 normalizedMatrix.translate(this._left, this._top);
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;
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));
1144 key = this._transforms[i].shift();
1147 normalizedMatrix[key].apply(normalizedMatrix, this._transforms[i]);
1148 matrix[key].apply(matrix, this._transforms[i]);
1153 normalizedMatrix.translate(-this._left, -this._top);
1155 transform = normalizedMatrix.a + "," +
1156 normalizedMatrix.c + "," +
1157 normalizedMatrix.b + "," +
1158 normalizedMatrix.d + "," +
1162 this._graphic.addToRedrawQueue(this);
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);
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;
1176 if(this._type != "path")
1178 this._transforms = [];
1180 node.style.left = x + "px";
1181 node.style.top = y + "px";
1185 * Normalizes the skew offset values between -32767 and 32767.
1187 * @method _getSkewOffsetValue
1188 * @param {Number} val The value to normalize
1192 _getSkewOffsetValue: function(val)
1194 var sign = Y.MatrixUtil.sign(val),
1195 absVal = Math.abs(val);
1196 val = Math.min(absVal, 32767) * sign;
1201 * Storage for translateX
1203 * @property _translateX
1210 * Storage for translateY
1212 * @property _translateY
1219 * Storage for the transform attribute.
1221 * @property _transform
1228 * Specifies a 2d translation.
1231 * @param {Number} x The value to transate on the x-axis.
1232 * @param {Number} y The value to translate on the y-axis.
1234 translate: function(x, y)
1236 this._translateX += x;
1237 this._translateY += y;
1238 this._addTransform("translate", arguments);
1242 * Translates the shape along the x-axis. When translating x and y coordinates,
1243 * use the `translate` method.
1245 * @method translateX
1246 * @param {Number} x The value to translate.
1248 translateX: function(x)
1250 this._translateX += x;
1251 this._addTransform("translateX", arguments);
1255 * Performs a translate on the y-coordinate. When translating x and y coordinates,
1256 * use the `translate` method.
1258 * @method translateY
1259 * @param {Number} y The value to translate.
1261 translateY: function(y)
1263 this._translateY += y;
1264 this._addTransform("translateY", arguments);
1268 * Skews the shape around the x-axis and y-axis.
1271 * @param {Number} x The value to skew on the x-axis.
1272 * @param {Number} y The value to skew on the y-axis.
1274 skew: function(x, y)
1276 this._addTransform("skew", arguments);
1280 * Skews the shape around the x-axis.
1283 * @param {Number} x x-coordinate
1287 this._addTransform("skewX", arguments);
1291 * Skews the shape around the y-axis.
1294 * @param {Number} y y-coordinate
1298 this._addTransform("skewY", arguments);
1302 * Rotates the shape clockwise around it transformOrigin.
1305 * @param {Number} deg The degree of the rotation.
1307 rotate: function(deg)
1309 this._addTransform("rotate", arguments);
1313 * Specifies a 2d scaling operation.
1316 * @param {Number} val
1318 scale: function(x, y)
1320 this._addTransform("scale", arguments);
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.
1328 * @param {String} type event type
1329 * @param {Object} callback function
1332 on: function(type, fn)
1334 if(Y.Node.DOM_EVENTS[type])
1336 return Y.one("#" + this.get("id")).on(type, fn);
1338 return Y.on.apply(this, arguments);
1352 * Updates `Shape` based on attribute changes.
1354 * @method _updateHandler
1357 _updateHandler: function(e)
1361 host._fillChangeHandler();
1362 host._strokeChangeHandler();
1363 node.style.width = this.get("width") + "px";
1364 node.style.height = this.get("height") + "px";
1366 host._updateTransform();
1370 * Creates a graphic node
1372 * @method _createGraphicNode
1373 * @param {String} type node type to create
1374 * @return HTMLElement
1377 _createGraphicNode: function(type)
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 + '"/>');
1384 * Value function for fill attribute
1387 * @method _getDefaultFill
1390 _getDefaultFill: function() {
1402 * Value function for stroke attribute
1405 * @method _getDefaultStroke
1408 _getDefaultStroke: function()
1419 * Sets the value of an attribute.
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
1430 AttributeLite.prototype.set.apply(host, arguments);
1431 if(host.initialized)
1433 host._updateHandler();
1438 * Returns the bounds for a shape.
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.
1444 * @param {Matrix} [optional] cfg Reference to matrix instance
1447 getBounds: function(cfg)
1449 var stroke = this.get("stroke"),
1450 w = this.get("width"),
1451 h = this.get("height"),
1455 if(stroke && stroke.weight)
1459 w = (x + w + wt) - (x - wt);
1460 h = (y + h + wt) - (y - wt);
1463 return this._normalizedMatrix.getContentRect(w, h, x, y);
1473 var graphic = this.get("graphic");
1476 graphic.removeShape(this);
1485 * Implementation for shape destruction
1490 _destroy: function()
1496 this.node.removeChild(this._fillNode);
1497 this._fillNode = null;
1499 if(this._strokeNode)
1501 this.node.removeChild(this._strokeNode);
1502 this._strokeNode = null;
1504 Y.one(this.node).remove(true);
1507 }, Y.VMLDrawing.prototype));
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].
1514 * @config transformOrigin
1525 * <p>A string containing, in order, transform operations applied to the shape instance. The `transform` string can contain the following values:
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>
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({
1545 transform: "rotate(45)"
1547 * <p>The code below would apply `translate` and `rotate` to an existing shape.</p>
1549 myRect.set("transform", "translate(40, 50) rotate(45)");
1554 setter: function(val)
1560 this._normalizedMatrix.init();
1561 this._transforms = this.matrix.getTransformArray(val);
1562 len = this._transforms.length;
1565 transform = this._transforms[i];
1567 this._transform = val;
1573 return this._transform;
1578 * Indicates the x position of shape.
1588 * Indicates the y position of shape.
1598 * Unique id for class instance.
1609 setter: function(val)
1611 var node = this.node;
1614 node.setAttribute("id", val);
1637 * Indicates whether the shape is visible.
1645 setter: function(val){
1646 var node = this.node,
1647 visibility = val ? "visible" : "hidden";
1650 node.style.visibility = visibility;
1657 * Contains information about the fill of the shape.
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.
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>
1669 * <p>If a `linear` or `radial` is specified as the fill type. The following additional property is used:
1671 * <dt>stops</dt><dd>An array of objects containing the following properties:
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>
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>
1685 * <p>The corresponding `SVGShape` class implements the following additional properties.</p>
1688 * <p>The x-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
1691 * <p>The y-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
1694 * <p>These properties are not currently implemented in `CanvasShape` or `VMLShape`.</p>
1700 valueFn: "_getDefaultFill",
1702 setter: function(val)
1706 tmpl = this.get("fill") || this._getDefaultFill();
1710 //ensure, fill type is solid if color is explicitly passed.
1711 if(val.hasOwnProperty("color"))
1717 if(val.hasOwnProperty(i))
1724 if(fill && fill.color)
1726 if(fill.color === undefined || fill.color == "none")
1731 this._fillFlag = true;
1737 * Contains information about the stroke of the shape.
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:
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>
1751 * <dt>linejoin</dt><dd>Specifies a linejoin for the stroke. The following values can be specified:
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>
1765 valueFn: "_getDefaultStroke",
1767 setter: function(val)
1772 tmpl = this.get("stroke") || this._getDefaultStroke();
1775 if(val.hasOwnProperty("weight"))
1777 wt = parseInt(val.weight, 10);
1785 if(val.hasOwnProperty(i))
1792 this._strokeFlag = true;
1797 //Not used. Remove in future.
1802 // Only implemented in SVG
1803 // Determines whether the instance will receive mouse events.
1805 // @config pointerEvents
1809 value: "visiblePainted"
1813 * Dom node for the shape.
1829 * Reference to the container Graphic.
1839 return this._graphic;
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.
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, {
1863 * Indicates the width of the shape
1871 var val = Math.max(this._right - this._left, 0);
1877 * Indicates the height of the shape
1885 return Math.max(this._bottom - this._top, 0);
1890 * Indicates the path used for the node.
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.
1916 VMLRect = function()
1918 VMLRect.superclass.constructor.apply(this, arguments);
1920 VMLRect.NAME = "vmlRect";
1921 Y.extend(VMLRect, Y.VMLShape, {
1923 * Indicates the type of shape
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.
1943 VMLEllipse = function()
1945 VMLEllipse.superclass.constructor.apply(this, arguments);
1948 VMLEllipse.NAME = "vmlEllipse";
1950 Y.extend(VMLEllipse, Y.VMLShape, {
1952 * Indicates the type of shape
1960 VMLEllipse.ATTRS = Y.merge(Y.VMLShape.ATTRS, {
1962 // Horizontal radius for the ellipse. This attribute is not implemented in Canvas.
1963 // Will add in 3.4.1.
1974 var val = this.get("width");
1975 val = Math.round((val/2) * 100)/100;
1979 setter: function(val)
1982 this.set("width", w);
1988 // Vertical radius for the ellipse. This attribute is not implemented in Canvas.
1989 // Will add in 3.4.1.
2000 var val = this.get("height");
2001 val = Math.round((val/2) * 100)/100;
2005 setter: function(val)
2008 this.set("height", h);
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.
2024 VMLCircle = function(cfg)
2026 VMLCircle.superclass.constructor.apply(this, arguments);
2029 VMLCircle.NAME = "vmlCircle";
2031 Y.extend(VMLCircle, VMLShape, {
2033 * Indicates the type of shape
2042 VMLCircle.ATTRS = Y.merge(VMLShape.ATTRS, {
2044 * Radius for the circle.
2056 * Indicates the width of the shape
2062 setter: function(val)
2064 this.set("radius", val/2);
2070 var radius = this.get("radius"),
2071 val = radius && radius > 0 ? radius * 2 : 0;
2077 * Indicates the height of the shape
2083 setter: function(val)
2085 this.set("radius", val/2);
2091 var radius = this.get("radius"),
2092 val = radius && radius > 0 ? radius * 2 : 0;
2097 Y.VMLCircle = VMLCircle;
2102 * @class VMLPieSlice
2105 VMLPieSlice = function()
2107 VMLPieSlice.superclass.constructor.apply(this, arguments);
2109 VMLPieSlice.NAME = "vmlPieSlice";
2110 Y.extend(VMLPieSlice, Y.VMLShape, Y.mix({
2112 * Indicates the type of shape
2121 * Change event listener
2124 * @method _updateHandler
2128 var x = this.get("cx"),
2130 startAngle = this.get("startAngle"),
2131 arc = this.get("arc"),
2132 radius = this.get("radius");
2134 this.drawWedge(x, y, startAngle, arc, radius);
2137 }, Y.VMLDrawing.prototype));
2138 VMLPieSlice.ATTRS = Y.mix({
2147 * Starting angle in relation to a circle in which to begin the pie slice drawing.
2149 * @config startAngle
2167 * Radius of the circle in which the pie slice is drawn
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.
2187 VMLGraphic = function() {
2188 VMLGraphic.superclass.constructor.apply(this, arguments);
2191 VMLGraphic.NAME = "vmlGraphic";
2193 VMLGraphic.ATTRS = {
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.
2198 * @type Node | String
2203 * Unique id for class instance.
2214 setter: function(val)
2216 var node = this._node;
2219 node.setAttribute("id", val);
2226 * Key value pairs in which a shape instance is associated with its id.
2237 return this._shapes;
2242 * Object containing size and coordinate data for the content of a Graphic in relation to the coordSpace node.
2244 * @config contentBounds
2252 return this._contentBounds;
2257 * The html element that represents to coordinate system of the Graphic instance.
2272 * Indicates the width of the `Graphic`.
2278 setter: function(val)
2282 this._node.style.width = val + "px";
2289 * Indicates the height of the `Graphic`.
2295 setter: function(val)
2299 this._node.style.height = val + "px";
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.
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.
2321 * @config resizeDown
2327 return this._resizeDown;
2330 setter: function(val)
2332 this._resizeDown = val;
2342 * Indicates the x-coordinate for the instance.
2353 setter: function(val)
2358 this._node.style.left = val + "px";
2365 * Indicates the y-coordinate for the instance.
2376 setter: function(val)
2381 this._node.style.top = val + "px";
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.
2403 setter: function(val)
2405 this._toggleVisible(val);
2411 Y.extend(VMLGraphic, Y.GraphicBase, {
2413 * Storage for `x` attribute.
2422 * Storage for `y` attribute.
2431 * Gets the current position of the graphic instance in page coordinates.
2434 * @return Array The XY position of the shape.
2438 var node = Y.one(this._node),
2449 * @property _resizeDown
2455 * Initializes the class.
2457 * @method initializer
2460 initializer: function(config) {
2461 var render = this.get("render");
2463 this._contentBounds = {
2469 this._node = this._createGraphic();
2470 this._node.setAttribute("id", this.get("id"));
2473 this.render(render);
2478 * Adds the graphics node to the dom.
2481 * @param {HTMLElement} parentNode node in which to render the graphics node into.
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);
2490 this.parentNode = parentNode;
2491 this.set("width", w);
2492 this.set("height", h);
2497 * Removes all nodes.
2504 Y.one(this._node).remove(true);
2508 * Generates a shape instance by type.
2511 * @param {Object} cfg attributes for the shape
2514 addShape: function(cfg)
2517 var shapeClass = this._getShapeClass(cfg.type),
2518 shape = new shapeClass(cfg);
2519 this._appendShape(shape);
2524 * Adds a shape instance to the graphic instance.
2526 * @method _appendShape
2527 * @param {Shape} shape The shape instance to be added to the graphic.
2530 _appendShape: function(shape)
2532 var node = shape.node,
2533 parentNode = this._frag || this._node;
2534 if(this.get("autoDraw"))
2536 parentNode.appendChild(node);
2540 this._getDocFrag().appendChild(node);
2545 * Removes a shape instance from from the graphic instance.
2547 * @method removeShape
2548 * @param {Shape|String} shape The instance or id of the shape to be removed.
2550 removeShape: function(shape)
2552 if(!shape instanceof VMLShape)
2554 if(Y_LANG.isString(shape))
2556 shape = this._shapes[shape];
2559 if(shape && shape instanceof VMLShape)
2562 this._shapes[shape.get("id")] = null;
2563 delete this._shapes[shape.get("id")];
2565 if(this.get("autoDraw"))
2572 * Removes all shape instances from the dom.
2574 * @method removeAllShapes
2576 removeAllShapes: function()
2578 var shapes = this._shapes,
2582 if(shapes.hasOwnProperty(i))
2584 shapes[i].destroy();
2591 * Removes all child nodes.
2593 * @method _removeChildren
2597 _removeChildren: function(node)
2599 if(node.hasChildNodes())
2602 while(node.firstChild)
2604 child = node.firstChild;
2605 this._removeChildren(child);
2606 node.removeChild(child);
2612 * Clears the graphics object.
2617 this.removeAllShapes();
2618 this._removeChildren(this._node);
2622 * Toggles visibility
2624 * @method _toggleVisible
2625 * @param {Boolean} val indicates visibilitye
2628 _toggleVisible: function(val)
2631 shapes = this._shapes,
2632 visibility = val ? "visible" : "hidden";
2637 if(shapes.hasOwnProperty(i))
2639 shapes[i].set("visible", val);
2643 this._node.style.visibility = visibility;
2647 * Sets the size of the graphics object.
2650 * @param w {Number} width to set for the instance.
2651 * @param h {Number} height to set for the instance.
2653 setSize: function(w, h) {
2656 this._node.style.width = w + 'px';
2657 this._node.style.height = h + 'px';
2658 this._node.coordSize = w + ' ' + h;
2662 * Sets the positon of the graphics object.
2664 * @method setPosition
2665 * @param {Number} x x-coordinate for the object.
2666 * @param {Number} y y-coordinate for the object.
2668 setPosition: function(x, y)
2672 this._node.style.left = x + "px";
2673 this._node.style.top = y + "px";
2677 * Creates a group element
2679 * @method _createGraphic
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';
2690 * Creates a graphic node
2692 * @method _createGraphicNode
2693 * @param {String} type node type to create
2694 * @param {String} pe specified pointer-events value
2695 * @return HTMLElement
2698 _createGraphicNode: function(type)
2700 return DOCUMENT.createElement('<' + type + ' xmlns="urn:schemas-microsft.com:vml" style="behavior:url(#default#VML);display:inline-block;zoom:1;" />');
2705 * Returns a shape based on the id of its dom node.
2707 * @method getShapeById
2708 * @param {String} id Dom id of the shape's node attribute.
2711 getShapeById: function(id)
2713 return this._shapes[id];
2717 * Returns a shape class. Used by `addShape`.
2719 * @method _getShapeClass
2720 * @param {Shape | String} val Indicates which shape class.
2724 _getShapeClass: function(val)
2726 var shape = this._shapeClass[val];
2735 * Look up for shape classes. Used by `addShape` to retrieve a class for instantiation.
2737 * @property _shapeClass
2742 circle: Y.VMLCircle,
2745 ellipse: Y.VMLEllipse,
2746 pieslice: Y.VMLPieSlice
2750 * Allows for creating multiple shapes in order to batch appending and redraw operations.
2753 * @param {Function} method Method to execute.
2755 batch: function(method)
2757 var autoDraw = this.get("autoDraw");
2758 this.set("autoDraw", false);
2761 this.set("autoDraw", autoDraw);
2765 * Returns a document fragment to for attaching shapes.
2767 * @method _getDocFrag
2768 * @return DocumentFragment
2771 _getDocFrag: function()
2775 this._frag = DOCUMENT.createDocumentFragment();
2781 * Adds a shape to the redraw queue and calculates the contentBounds.
2783 * @method addToRedrawQueue
2784 * @param shape {VMLShape}
2787 addToRedrawQueue: function(shape)
2791 this._shapes[shape.get("id")] = shape;
2792 if(!this._resizeDown)
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;
2804 if(this.get("autoDraw"))
2811 * Redraws all shapes.
2818 var box = this._resizeDown ? this._getUpdatedContentBounds() : this._contentBounds;
2819 if(this.get("autoSize"))
2821 this.setSize(box.right, box.bottom);
2825 this._node.appendChild(this._frag);
2831 * Recalculates and returns the `contentBounds` for the `Graphic` instance.
2833 * @method _getUpdatedContentBounds
2837 _getUpdatedContentBounds: function()
2842 queue = this._shapes,
2851 if(queue.hasOwnProperty(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);
2861 box.width = box.right - box.left;
2862 box.height = box.bottom - box.top;
2863 this._contentBounds = box;
2867 Y.VMLGraphic = VMLGraphic;
2871 }, '3.5.1' ,{skinnable:false, requires:['graphics']});