diff -r 322d0feea350 -r 89ef5ed3c48b src/cm/media/js/lib/yui/yui_3.10.3/build/graphics-vml/graphics-vml-debug.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui_3.10.3/build/graphics-vml/graphics-vml-debug.js Tue Jul 16 14:29:46 2013 +0200 @@ -0,0 +1,3724 @@ +/* +YUI 3.10.3 (build 2fb5187) +Copyright 2013 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +http://yuilibrary.com/license/ +*/ + +YUI.add('graphics-vml', function (Y, NAME) { + +var IMPLEMENTATION = "vml", + SHAPE = "shape", + SPLITPATHPATTERN = /[a-z][^a-z]*/ig, + SPLITARGSPATTERN = /[\-]?[0-9]*[0-9|\.][0-9]*/g, + Y_LANG = Y.Lang, + IS_NUM = Y_LANG.isNumber, + IS_ARRAY = Y_LANG.isArray, + Y_DOM = Y.DOM, + Y_SELECTOR = Y.Selector, + DOCUMENT = Y.config.doc, + AttributeLite = Y.AttributeLite, + VMLShape, + VMLCircle, + VMLPath, + VMLRect, + VMLEllipse, + VMLGraphic, + VMLPieSlice, + _getClassName = Y.ClassNameManager.getClassName; + +function VMLDrawing() {} + +/** + * VML implementation of the `Drawing` class. + * `VMLDrawing` is not intended to be used directly. Instead, use the `Drawing` class. + * If the browser lacks SVG and Canvas + * capabilities, the `Drawing` class will point to the `VMLDrawing` class. + * + * @module graphics + * @class VMLDrawing + * @constructor + */ +VMLDrawing.prototype = { + /** + * Maps path to methods + * + * @property _pathSymbolToMethod + * @type Object + * @private + */ + _pathSymbolToMethod: { + M: "moveTo", + m: "relativeMoveTo", + L: "lineTo", + l: "relativeLineTo", + C: "curveTo", + c: "relativeCurveTo", + Q: "quadraticCurveTo", + q: "relativeQuadraticCurveTo", + z: "closePath", + Z: "closePath" + }, + + /** + * Value for rounding up to coordsize + * + * @property _coordSpaceMultiplier + * @type Number + * @private + */ + _coordSpaceMultiplier: 100, + + /** + * Rounds dimensions and position values based on the coordinate space. + * + * @method _round + * @param {Number} The value for rounding + * @return Number + * @private + */ + _round:function(val) + { + return Math.round(val * this._coordSpaceMultiplier); + }, + + /** + * Concatanates the path. + * + * @method _addToPath + * @param {String} val The value to add to the path string. + * @private + */ + _addToPath: function(val) + { + this._path = this._path || ""; + if(this._movePath) + { + this._path += this._movePath; + this._movePath = null; + } + this._path += val; + }, + + /** + * Current x position of the drawing. + * + * @property _currentX + * @type Number + * @private + */ + _currentX: 0, + + /** + * Current y position of the drqwing. + * + * @property _currentY + * @type Number + * @private + */ + _currentY: 0, + + /** + * Draws a bezier curve. + * + * @method curveTo + * @param {Number} cp1x x-coordinate for the first control point. + * @param {Number} cp1y y-coordinate for the first control point. + * @param {Number} cp2x x-coordinate for the second control point. + * @param {Number} cp2y y-coordinate for the second control point. + * @param {Number} x x-coordinate for the end point. + * @param {Number} y y-coordinate for the end point. + * @chainable + */ + curveTo: function() { + this._curveTo.apply(this, [Y.Array(arguments), false]); + return this; + }, + + /** + * Draws a bezier curve. + * + * @method relativeCurveTo + * @param {Number} cp1x x-coordinate for the first control point. + * @param {Number} cp1y y-coordinate for the first control point. + * @param {Number} cp2x x-coordinate for the second control point. + * @param {Number} cp2y y-coordinate for the second control point. + * @param {Number} x x-coordinate for the end point. + * @param {Number} y y-coordinate for the end point. + * @chainable + */ + relativeCurveTo: function() { + this._curveTo.apply(this, [Y.Array(arguments), true]); + return this; + }, + + /** + * Implements curveTo methods. + * + * @method _curveTo + * @param {Array} args The arguments to be used. + * @param {Boolean} relative Indicates whether or not to use relative coordinates. + * @private + */ + _curveTo: function(args, relative) { + var w, + h, + x, + y, + cp1x, + cp1y, + cp2x, + cp2y, + pts, + right, + left, + bottom, + top, + i, + len, + path, + command = relative ? " v " : " c ", + relativeX = relative ? parseFloat(this._currentX) : 0, + relativeY = relative ? parseFloat(this._currentY) : 0; + len = args.length - 5; + path = command; + for(i = 0; i < len; i = i + 6) + { + cp1x = parseFloat(args[i]); + cp1y = parseFloat(args[i + 1]); + cp2x = parseFloat(args[i + 2]); + cp2y = parseFloat(args[i + 3]); + x = parseFloat(args[i + 4]); + y = parseFloat(args[i + 5]); + if(i > 0) + { + path = path + ", "; + } + path = path + + this._round(cp1x) + + ", " + + this._round(cp1y) + + ", " + + this._round(cp2x) + + ", " + + this._round(cp2y) + + ", " + + this._round(x) + + ", " + + this._round(y); + cp1x = cp1x + relativeX; + cp1y = cp1y + relativeY; + cp2x = cp2x + relativeX; + cp2y = cp2y + relativeY; + x = x + relativeX; + y = y + relativeY; + right = Math.max(x, Math.max(cp1x, cp2x)); + bottom = Math.max(y, Math.max(cp1y, cp2y)); + left = Math.min(x, Math.min(cp1x, cp2x)); + top = Math.min(y, Math.min(cp1y, cp2y)); + w = Math.abs(right - left); + h = Math.abs(bottom - top); + pts = [[this._currentX, this._currentY] , [cp1x, cp1y], [cp2x, cp2y], [x, y]]; + this._setCurveBoundingBox(pts, w, h); + this._currentX = x; + this._currentY = y; + } + this._addToPath(path); + }, + + /** + * Draws a quadratic bezier curve. + * + * @method quadraticCurveTo + * @param {Number} cpx x-coordinate for the control point. + * @param {Number} cpy y-coordinate for the control point. + * @param {Number} x x-coordinate for the end point. + * @param {Number} y y-coordinate for the end point. + * @chainable + */ + quadraticCurveTo: function() { + this._quadraticCurveTo.apply(this, [Y.Array(arguments), false]); + return this; + }, + + /** + * Draws a quadratic bezier curve relative to the current position. + * + * @method relativeQuadraticCurveTo + * @param {Number} cpx x-coordinate for the control point. + * @param {Number} cpy y-coordinate for the control point. + * @param {Number} x x-coordinate for the end point. + * @param {Number} y y-coordinate for the end point. + * @chainable + */ + relativeQuadraticCurveTo: function() { + this._quadraticCurveTo.apply(this, [Y.Array(arguments), true]); + return this; + }, + + /** + * Implements quadraticCurveTo methods. + * + * @method _quadraticCurveTo + * @param {Array} args The arguments to be used. + * @param {Boolean} relative Indicates whether or not to use relative coordinates. + * @private + */ + _quadraticCurveTo: function(args, relative) { + var cpx, + cpy, + cp1x, + cp1y, + cp2x, + cp2y, + x, + y, + currentX = this._currentX, + currentY = this._currentY, + i, + len = args.length - 3, + bezierArgs = [], + relativeX = relative ? parseFloat(this._currentX) : 0, + relativeY = relative ? parseFloat(this._currentY) : 0; + for(i = 0; i < len; i = i + 4) + { + cpx = parseFloat(args[i]) + relativeX; + cpy = parseFloat(args[i + 1]) + relativeY; + x = parseFloat(args[i + 2]) + relativeX; + y = parseFloat(args[i + 3]) + relativeY; + cp1x = currentX + 0.67*(cpx - currentX); + cp1y = currentY + 0.67*(cpy - currentY); + cp2x = cp1x + (x - currentX) * 0.34; + cp2y = cp1y + (y - currentY) * 0.34; + bezierArgs.push(cp1x); + bezierArgs.push(cp1y); + bezierArgs.push(cp2x); + bezierArgs.push(cp2y); + bezierArgs.push(x); + bezierArgs.push(y); + } + this._curveTo.apply(this, [bezierArgs, false]); + }, + + /** + * Draws a rectangle. + * + * @method drawRect + * @param {Number} x x-coordinate + * @param {Number} y y-coordinate + * @param {Number} w width + * @param {Number} h height + * @chainable + */ + drawRect: function(x, y, w, h) { + this.moveTo(x, y); + this.lineTo(x + w, y); + this.lineTo(x + w, y + h); + this.lineTo(x, y + h); + this.lineTo(x, y); + this._currentX = x; + this._currentY = y; + return this; + }, + + /** + * Draws a rectangle with rounded corners. + * + * @method drawRect + * @param {Number} x x-coordinate + * @param {Number} y y-coordinate + * @param {Number} w width + * @param {Number} h height + * @param {Number} ew width of the ellipse used to draw the rounded corners + * @param {Number} eh height of the ellipse used to draw the rounded corners + * @chainable + */ + drawRoundRect: function(x, y, w, h, ew, eh) { + this.moveTo(x, y + eh); + this.lineTo(x, y + h - eh); + this.quadraticCurveTo(x, y + h, x + ew, y + h); + this.lineTo(x + w - ew, y + h); + this.quadraticCurveTo(x + w, y + h, x + w, y + h - eh); + this.lineTo(x + w, y + eh); + this.quadraticCurveTo(x + w, y, x + w - ew, y); + this.lineTo(x + ew, y); + this.quadraticCurveTo(x, y, x, y + eh); + return this; + }, + + /** + * Draws a circle. Used internally by `CanvasCircle` class. + * + * @method drawCircle + * @param {Number} x y-coordinate + * @param {Number} y x-coordinate + * @param {Number} r radius + * @chainable + * @protected + */ + drawCircle: function(x, y, radius) { + var startAngle = 0, + endAngle = 360, + circum = radius * 2; + + endAngle *= 65535; + this._drawingComplete = false; + this._trackSize(x + circum, y + circum); + this.moveTo((x + circum), (y + radius)); + this._addToPath( + " ae " + + this._round(x + radius) + + ", " + + this._round(y + radius) + + ", " + + this._round(radius) + + ", " + + this._round(radius) + + ", " + + startAngle + + ", " + + endAngle + ); + return this; + }, + + /** + * Draws an ellipse. + * + * @method drawEllipse + * @param {Number} x x-coordinate + * @param {Number} y y-coordinate + * @param {Number} w width + * @param {Number} h height + * @chainable + * @protected + */ + drawEllipse: function(x, y, w, h) { + var startAngle = 0, + endAngle = 360, + radius = w * 0.5, + yRadius = h * 0.5; + endAngle *= 65535; + this._drawingComplete = false; + this._trackSize(x + w, y + h); + this.moveTo((x + w), (y + yRadius)); + this._addToPath( + " ae " + + this._round(x + radius) + + ", " + + this._round(x + radius) + + ", " + + this._round(y + yRadius) + + ", " + + this._round(radius) + + ", " + + this._round(yRadius) + + ", " + + startAngle + + ", " + + endAngle + ); + return this; + }, + + /** + * Draws a diamond. + * + * @method drawDiamond + * @param {Number} x y-coordinate + * @param {Number} y x-coordinate + * @param {Number} width width + * @param {Number} height height + * @chainable + * @protected + */ + drawDiamond: function(x, y, width, height) + { + var midWidth = width * 0.5, + midHeight = height * 0.5; + this.moveTo(x + midWidth, y); + this.lineTo(x + width, y + midHeight); + this.lineTo(x + midWidth, y + height); + this.lineTo(x, y + midHeight); + this.lineTo(x + midWidth, y); + return this; + }, + + /** + * Draws a wedge. + * + * @method drawWedge + * @param {Number} x x-coordinate of the wedge's center point + * @param {Number} y y-coordinate of the wedge's center point + * @param {Number} startAngle starting angle in degrees + * @param {Number} arc sweep of the wedge. Negative values draw clockwise. + * @param {Number} radius radius of wedge. If [optional] yRadius is defined, then radius is the x radius. + * @param {Number} yRadius [optional] y radius for wedge. + * @chainable + * @private + */ + drawWedge: function(x, y, startAngle, arc, radius) + { + var diameter = radius * 2; + if(Math.abs(arc) > 360) + { + arc = 360; + } + this._currentX = x; + this._currentY = y; + startAngle *= -65535; + arc *= 65536; + startAngle = Math.round(startAngle); + arc = Math.round(arc); + this.moveTo(x, y); + this._addToPath( + " ae " + + this._round(x) + + ", " + + this._round(y) + + ", " + + this._round(radius) + + " " + + this._round(radius) + + ", " + + startAngle + + ", " + + arc + ); + this._trackSize(diameter, diameter); + return this; + }, + + /** + * Draws a line segment from the current drawing position to the specified x and y coordinates. + * + * @method lineTo + * @param {Number} point1 x-coordinate for the end point. + * @param {Number} point2 y-coordinate for the end point. + * @chainable + */ + lineTo: function() + { + this._lineTo.apply(this, [Y.Array(arguments), false]); + return this; + }, + + /** + * Draws a line segment using the current line style from the current drawing position to the relative x and y coordinates. + * + * @method relativeLineTo + * @param {Number} point1 x-coordinate for the end point. + * @param {Number} point2 y-coordinate for the end point. + * @chainable + */ + relativeLineTo: function() + { + this._lineTo.apply(this, [Y.Array(arguments), true]); + return this; + }, + + /** + * Implements lineTo methods. + * + * @method _lineTo + * @param {Array} args The arguments to be used. + * @param {Boolean} relative Indicates whether or not to use relative coordinates. + * @private + */ + _lineTo: function(args, relative) { + var point1 = args[0], + i, + len, + x, + y, + path = relative ? " r " : " l ", + relativeX = relative ? parseFloat(this._currentX) : 0, + relativeY = relative ? parseFloat(this._currentY) : 0; + if (typeof point1 === "string" || typeof point1 === "number") { + len = args.length - 1; + for (i = 0; i < len; i = i + 2) { + x = parseFloat(args[i]); + y = parseFloat(args[i + 1]); + path += ' ' + this._round(x) + ', ' + this._round(y); + x = x + relativeX; + y = y + relativeY; + this._currentX = x; + this._currentY = y; + this._trackSize.apply(this, [x, y]); + } + } + else + { + len = args.length; + for (i = 0; i < len; i = i + 1) { + x = parseFloat(args[i][0]); + y = parseFloat(args[i][1]); + path += ' ' + this._round(x) + ', ' + this._round(y); + x = x + relativeX; + y = y + relativeY; + this._currentX = x; + this._currentY = y; + this._trackSize.apply(this, [x, y]); + } + } + this._addToPath(path); + return this; + }, + + /** + * Moves the current drawing position to specified x and y coordinates. + * + * @method moveTo + * @param {Number} x x-coordinate for the end point. + * @param {Number} y y-coordinate for the end point. + * @chainable + */ + moveTo: function() + { + this._moveTo.apply(this, [Y.Array(arguments), false]); + return this; + }, + + /** + * Moves the current drawing position relative to specified x and y coordinates. + * + * @method relativeMoveTo + * @param {Number} x x-coordinate for the end point. + * @param {Number} y y-coordinate for the end point. + * @chainable + */ + relativeMoveTo: function() + { + this._moveTo.apply(this, [Y.Array(arguments), true]); + return this; + }, + + /** + * Implements moveTo methods. + * + * @method _moveTo + * @param {Array} args The arguments to be used. + * @param {Boolean} relative Indicates whether or not to use relative coordinates. + * @private + */ + _moveTo: function(args, relative) { + var x = parseFloat(args[0]), + y = parseFloat(args[1]), + command = relative ? " t " : " m ", + relativeX = relative ? parseFloat(this._currentX) : 0, + relativeY = relative ? parseFloat(this._currentY) : 0; + this._movePath = command + this._round(x) + ", " + this._round(y); + x = x + relativeX; + y = y + relativeY; + this._trackSize(x, y); + this._currentX = x; + this._currentY = y; + }, + + /** + * Draws the graphic. + * + * @method _draw + * @private + */ + _closePath: function() + { + var fill = this.get("fill"), + stroke = this.get("stroke"), + node = this.node, + w = this.get("width"), + h = this.get("height"), + path = this._path, + pathEnd = "", + multiplier = this._coordSpaceMultiplier; + this._fillChangeHandler(); + this._strokeChangeHandler(); + if(path) + { + if(fill && fill.color) + { + pathEnd += ' x'; + } + if(stroke) + { + pathEnd += ' e'; + } + } + if(path) + { + node.path = path + pathEnd; + } + if(!isNaN(w) && !isNaN(h)) + { + node.coordOrigin = this._left + ", " + this._top; + node.coordSize = (w * multiplier) + ", " + (h * multiplier); + node.style.position = "absolute"; + node.style.width = w + "px"; + node.style.height = h + "px"; + } + this._path = path; + this._movePath = null; + this._updateTransform(); + }, + + /** + * Completes a drawing operation. + * + * @method end + * @chainable + */ + end: function() + { + this._closePath(); + return this; + }, + + /** + * Ends a fill and stroke + * + * @method closePath + * @chainable + */ + closePath: function() + { + this._addToPath(" x e"); + return this; + }, + + /** + * Clears the path. + * + * @method clear + * @chainable + */ + clear: function() + { + this._right = 0; + this._bottom = 0; + this._width = 0; + this._height = 0; + this._left = 0; + this._top = 0; + this._path = ""; + this._movePath = null; + return this; + }, + + /** + * Returns the points on a curve + * + * @method getBezierData + * @param Array points Array containing the begin, end and control points of a curve. + * @param Number t The value for incrementing the next set of points. + * @return Array + * @private + */ + getBezierData: function(points, t) { + var n = points.length, + tmp = [], + i, + j; + + for (i = 0; i < n; ++i){ + tmp[i] = [points[i][0], points[i][1]]; // save input + } + + for (j = 1; j < n; ++j) { + for (i = 0; i < n - j; ++i) { + tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0]; + tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1]; + } + } + return [ tmp[0][0], tmp[0][1] ]; + }, + + /** + * Calculates the bounding box for a curve + * + * @method _setCurveBoundingBox + * @param Array pts Array containing points for start, end and control points of a curve. + * @param Number w Width used to calculate the number of points to describe the curve. + * @param Number h Height used to calculate the number of points to describe the curve. + * @private + */ + _setCurveBoundingBox: function(pts, w, h) + { + var i, + left = this._currentX, + right = left, + top = this._currentY, + bottom = top, + len = Math.round(Math.sqrt((w * w) + (h * h))), + t = 1/len, + xy; + for(i = 0; i < len; ++i) + { + xy = this.getBezierData(pts, t * i); + left = isNaN(left) ? xy[0] : Math.min(xy[0], left); + right = isNaN(right) ? xy[0] : Math.max(xy[0], right); + top = isNaN(top) ? xy[1] : Math.min(xy[1], top); + bottom = isNaN(bottom) ? xy[1] : Math.max(xy[1], bottom); + } + left = Math.round(left * 10)/10; + right = Math.round(right * 10)/10; + top = Math.round(top * 10)/10; + bottom = Math.round(bottom * 10)/10; + this._trackSize(right, bottom); + this._trackSize(left, top); + }, + + /** + * Updates the size of the graphics object + * + * @method _trackSize + * @param {Number} w width + * @param {Number} h height + * @private + */ + _trackSize: function(w, h) { + if (w > this._right) { + this._right = w; + } + if(w < this._left) + { + this._left = w; + } + if (h < this._top) + { + this._top = h; + } + if (h > this._bottom) + { + this._bottom = h; + } + this._width = this._right - this._left; + this._height = this._bottom - this._top; + }, + + _left: 0, + + _right: 0, + + _top: 0, + + _bottom: 0, + + _width: 0, + + _height: 0 +}; +Y.VMLDrawing = VMLDrawing; +/** + * VML implementation of the `Shape` class. + * `VMLShape` is not intended to be used directly. Instead, use the `Shape` class. + * If the browser lacks SVG and Canvas + * capabilities, the `Shape` class will point to the `VMLShape` class. + * + * @module graphics + * @class VMLShape + * @constructor + * @param {Object} cfg (optional) Attribute configs + */ +VMLShape = function() +{ + this._transforms = []; + this.matrix = new Y.Matrix(); + this._normalizedMatrix = new Y.Matrix(); + VMLShape.superclass.constructor.apply(this, arguments); +}; + +VMLShape.NAME = "shape"; + +Y.extend(VMLShape, Y.GraphicBase, Y.mix({ + /** + * Indicates the type of shape + * + * @property _type + * @type String + * @private + */ + _type: "shape", + + /** + * Init method, invoked during construction. + * Calls `initializer` method. + * + * @method init + * @protected + */ + init: function() + { + this.initializer.apply(this, arguments); + }, + + /** + * Initializes the shape + * + * @private + * @method _initialize + */ + initializer: function(cfg) + { + var host = this, + graphic = cfg.graphic, + data = this.get("data"); + host.createNode(); + if(graphic) + { + this._setGraphic(graphic); + } + if(data) + { + host._parsePathData(data); + } + this._updateHandler(); + }, + + /** + * Set the Graphic instance for the shape. + * + * @method _setGraphic + * @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 to the `graphic` attribute. Otherwise, a new Graphic instance will be created + * and rendered into the dom element that the render represents. + * @private + */ + _setGraphic: function(render) + { + var graphic; + if(render instanceof Y.VMLGraphic) + { + this._graphic = render; + } + else + { + render = Y.one(render); + graphic = new Y.VMLGraphic({ + render: render + }); + graphic._appendShape(this); + this._graphic = graphic; + this._appendStrokeAndFill(); + } + }, + + /** + * Appends fill and stroke nodes to the shape. + * + * @method _appendStrokeAndFill + * @private + */ + _appendStrokeAndFill: function() + { + if(this._strokeNode) + { + this.node.appendChild(this._strokeNode); + } + if(this._fillNode) + { + this.node.appendChild(this._fillNode); + } + }, + + /** + * Creates the dom node for the shape. + * + * @method createNode + * @return HTMLElement + * @private + */ + createNode: function() + { + var node, + concat = this._camelCaseConcat, + x = this.get("x"), + y = this.get("y"), + w = this.get("width"), + h = this.get("height"), + id, + type, + name = this.name, + nodestring, + visibility = this.get("visible") ? "visible" : "hidden", + strokestring, + classString, + stroke, + endcap, + opacity, + joinstyle, + miterlimit, + dashstyle, + fill, + fillstring; + id = this.get("id"); + type = this._type === "path" ? "shape" : this._type; + classString = _getClassName(SHAPE) + + " " + + _getClassName(concat(IMPLEMENTATION, SHAPE)) + + " " + + _getClassName(name) + + " " + + _getClassName(concat(IMPLEMENTATION, name)) + + " " + + IMPLEMENTATION + + type; + stroke = this._getStrokeProps(); + fill = this._getFillProps(); + + 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 + + '"'; + + if(stroke && stroke.weight && stroke.weight > 0) + { + endcap = stroke.endcap; + opacity = parseFloat(stroke.opacity); + joinstyle = stroke.joinstyle; + miterlimit = stroke.miterlimit; + dashstyle = stroke.dashstyle; + nodestring += ' stroked="t" strokecolor="' + stroke.color + '" strokeWeight="' + stroke.weight + 'px"'; + + strokestring = ''; + + node = DOCUMENT.createElement(nodestring); + + this.node = node; + this._strokeFlag = false; + this._fillFlag = false; + }, + + /** + * Add a class name to each node. + * + * @method addClass + * @param {String} className the class name to add to the node's class attribute + */ + addClass: function(className) + { + var node = this.node; + Y_DOM.addClass(node, className); + }, + + /** + * Removes a class name from each node. + * + * @method removeClass + * @param {String} className the class name to remove from the node's class attribute + */ + removeClass: function(className) + { + var node = this.node; + Y_DOM.removeClass(node, className); + }, + + /** + * Gets the current position of the node in page coordinates. + * + * @method getXY + * @return Array The XY position of the shape. + */ + getXY: function() + { + var graphic = this._graphic, + parentXY = graphic.getXY(), + x = this.get("x"), + y = this.get("y"); + return [parentXY[0] + x, parentXY[1] + y]; + }, + + /** + * Set the position of the shape in page coordinates, regardless of how the node is positioned. + * + * @method setXY + * @param {Array} Contains x & y values for new position (coordinates are page-based) + * + */ + setXY: function(xy) + { + var graphic = this._graphic, + parentXY = graphic.getXY(); + this.set("x", xy[0] - parentXY[0]); + this.set("y", xy[1] - parentXY[1]); + }, + + /** + * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy. + * + * @method contains + * @param {VMLShape | HTMLElement} needle The possible node or descendent + * @return Boolean Whether or not this shape is the needle or its ancestor. + */ + contains: function(needle) + { + return needle === Y.one(this.node); + }, + + /** + * Compares nodes to determine if they match. + * Node instances can be compared to each other and/or HTMLElements. + * @method compareTo + * @param {HTMLElement | Node} refNode The reference node to compare to the node. + * @return {Boolean} True if the nodes match, false if they do not. + */ + compareTo: function(refNode) { + var node = this.node; + return node === refNode; + }, + + /** + * Test if the supplied node matches the supplied selector. + * + * @method test + * @param {String} selector The CSS selector to test against. + * @return Boolean Wheter or not the shape matches the selector. + */ + test: function(selector) + { + return Y_SELECTOR.test(this.node, selector); + }, + + /** + * Calculates and returns properties for setting an initial stroke. + * + * @method _getStrokeProps + * @return Object + * + * @private + */ + _getStrokeProps: function() + { + var props, + stroke = this.get("stroke"), + strokeOpacity, + dashstyle, + dash = "", + val, + i = 0, + len, + linecap, + linejoin; + if(stroke && stroke.weight && stroke.weight > 0) + { + props = {}; + linecap = stroke.linecap || "flat"; + linejoin = stroke.linejoin || "round"; + if(linecap !== "round" && linecap !== "square") + { + linecap = "flat"; + } + strokeOpacity = parseFloat(stroke.opacity); + dashstyle = stroke.dashstyle || "none"; + stroke.color = stroke.color || "#000000"; + stroke.weight = stroke.weight || 1; + stroke.opacity = IS_NUM(strokeOpacity) ? strokeOpacity : 1; + props.stroked = true; + props.color = stroke.color; + props.weight = stroke.weight; + props.endcap = linecap; + props.opacity = stroke.opacity; + if(IS_ARRAY(dashstyle)) + { + dash = []; + len = dashstyle.length; + for(i = 0; i < len; ++i) + { + val = dashstyle[i]; + dash[i] = val / stroke.weight; + } + } + if(linejoin === "round" || linejoin === "bevel") + { + props.joinstyle = linejoin; + } + else + { + linejoin = parseInt(linejoin, 10); + if(IS_NUM(linejoin)) + { + props.miterlimit = Math.max(linejoin, 1); + props.joinstyle = "miter"; + } + } + props.dashstyle = dash; + } + return props; + }, + + /** + * Adds a stroke to the shape node. + * + * @method _strokeChangeHandler + * @private + */ + _strokeChangeHandler: function() + { + if(!this._strokeFlag) + { + return; + } + var node = this.node, + stroke = this.get("stroke"), + strokeOpacity, + dashstyle, + dash = "", + val, + i = 0, + len, + linecap, + linejoin; + if(stroke && stroke.weight && stroke.weight > 0) + { + linecap = stroke.linecap || "flat"; + linejoin = stroke.linejoin || "round"; + if(linecap !== "round" && linecap !== "square") + { + linecap = "flat"; + } + strokeOpacity = parseFloat(stroke.opacity); + dashstyle = stroke.dashstyle || "none"; + stroke.color = stroke.color || "#000000"; + stroke.weight = stroke.weight || 1; + stroke.opacity = IS_NUM(strokeOpacity) ? strokeOpacity : 1; + node.stroked = true; + node.strokeColor = stroke.color; + node.strokeWeight = stroke.weight + "px"; + if(!this._strokeNode) + { + this._strokeNode = this._createGraphicNode("stroke"); + node.appendChild(this._strokeNode); + } + this._strokeNode.endcap = linecap; + this._strokeNode.opacity = stroke.opacity; + if(IS_ARRAY(dashstyle)) + { + dash = []; + len = dashstyle.length; + for(i = 0; i < len; ++i) + { + val = dashstyle[i]; + dash[i] = val / stroke.weight; + } + } + if(linejoin === "round" || linejoin === "bevel") + { + this._strokeNode.joinstyle = linejoin; + } + else + { + linejoin = parseInt(linejoin, 10); + if(IS_NUM(linejoin)) + { + this._strokeNode.miterlimit = Math.max(linejoin, 1); + this._strokeNode.joinstyle = "miter"; + } + } + this._strokeNode.dashstyle = dash; + this._strokeNode.on = true; + } + else + { + if(this._strokeNode) + { + this._strokeNode.on = false; + } + node.stroked = false; + } + this._strokeFlag = false; + }, + + /** + * Calculates and returns properties for setting an initial fill. + * + * @method _getFillProps + * @return Object + * + * @private + */ + _getFillProps: function() + { + var fill = this.get("fill"), + fillOpacity, + props, + gradient, + i, + fillstring, + filled = false; + if(fill) + { + props = {}; + + if(fill.type === "radial" || fill.type === "linear") + { + fillOpacity = parseFloat(fill.opacity); + fillOpacity = IS_NUM(fillOpacity) ? fillOpacity : 1; + filled = true; + gradient = this._getGradientFill(fill); + fillstring = ''; + } + } + } + props.filled = filled; + } + return props; + }, + + /** + * Adds a fill to the shape node. + * + * @method _fillChangeHandler + * @private + */ + _fillChangeHandler: function() + { + if(!this._fillFlag) + { + return; + } + var node = this.node, + fill = this.get("fill"), + fillOpacity, + fillstring, + filled = false, + i, + gradient; + if(fill) + { + if(fill.type === "radial" || fill.type === "linear") + { + filled = true; + gradient = this._getGradientFill(fill); + if(this._fillNode) + { + for(i in gradient) + { + if(gradient.hasOwnProperty(i)) + { + if(i === "colors") + { + this._fillNode.colors.value = gradient[i]; + } + else + { + this._fillNode[i] = gradient[i]; + } + } + } + } + else + { + fillstring = ''; + this._fillNode = DOCUMENT.createElement(fillstring); + node.appendChild(this._fillNode); + } + } + else if(this._fillNode) + { + this._fillNode.opacity = 1; + this._fillNode.type = "solid"; + } + } + } + node.filled = filled; + this._fillFlag = false; + }, + + //not used. remove next release. + _updateFillNode: function(node) + { + if(!this._fillNode) + { + this._fillNode = this._createGraphicNode("fill"); + node.appendChild(this._fillNode); + } + }, + + /** + * Calculates and returns an object containing gradient properties for a fill node. + * + * @method _getGradientFill + * @param {Object} fill Object containing fill properties. + * @return Object + * @private + */ + _getGradientFill: function(fill) + { + var gradientProps = {}, + gradientBoxWidth, + gradientBoxHeight, + type = fill.type, + w = this.get("width"), + h = this.get("height"), + isNumber = IS_NUM, + stop, + stops = fill.stops, + len = stops.length, + opacity, + color, + i, + oi, + colorstring = "", + cx = fill.cx, + cy = fill.cy, + fx = fill.fx, + fy = fill.fy, + r = fill.r, + pct, + rotation = fill.rotation || 0; + if(type === "linear") + { + if(rotation <= 270) + { + rotation = Math.abs(rotation - 270); + } + else if(rotation < 360) + { + rotation = 270 + (360 - rotation); + } + else + { + rotation = 270; + } + gradientProps.type = "gradient";//"gradientunscaled"; + gradientProps.angle = rotation; + } + else if(type === "radial") + { + gradientBoxWidth = w * (r * 2); + gradientBoxHeight = h * (r * 2); + fx = r * 2 * (fx - 0.5); + fy = r * 2 * (fy - 0.5); + fx += cx; + fy += cy; + gradientProps.focussize = (gradientBoxWidth/w)/10 + "% " + (gradientBoxHeight/h)/10 + "%"; + gradientProps.alignshape = false; + gradientProps.type = "gradientradial"; + gradientProps.focus = "100%"; + gradientProps.focusposition = Math.round(fx * 100) + "% " + Math.round(fy * 100) + "%"; + } + for(i = 0;i < len; ++i) { + stop = stops[i]; + color = stop.color; + opacity = stop.opacity; + opacity = isNumber(opacity) ? opacity : 1; + pct = stop.offset || i/(len-1); + pct *= (r * 2); + pct = Math.round(100 * pct) + "%"; + oi = i > 0 ? i + 1 : ""; + gradientProps["opacity" + oi] = opacity + ""; + colorstring += ", " + pct + " " + color; + } + if(parseFloat(pct) < 100) + { + colorstring += ", 100% " + color; + } + gradientProps.colors = colorstring.substr(2); + return gradientProps; + }, + + /** + * Adds a transform to the shape. + * + * @method _addTransform + * @param {String} type The transform being applied. + * @param {Array} args The arguments for the transform. + * @private + */ + _addTransform: function(type, args) + { + args = Y.Array(args); + this._transform = Y_LANG.trim(this._transform + " " + type + "(" + args.join(", ") + ")"); + args.unshift(type); + this._transforms.push(args); + if(this.initialized) + { + this._updateTransform(); + } + }, + + /** + * Applies all transforms. + * + * @method _updateTransform + * @private + */ + _updateTransform: function() + { + var node = this.node, + key, + transform, + transformOrigin, + x = this.get("x"), + y = this.get("y"), + tx, + ty, + matrix = this.matrix, + normalizedMatrix = this._normalizedMatrix, + isPathShape = this instanceof Y.VMLPath, + i, + len = this._transforms.length; + if(this._transforms && this._transforms.length > 0) + { + transformOrigin = this.get("transformOrigin"); + + if(isPathShape) + { + normalizedMatrix.translate(this._left, this._top); + } + //vml skew matrix transformOrigin ranges from -0.5 to 0.5. + //subtract 0.5 from values + tx = transformOrigin[0] - 0.5; + ty = transformOrigin[1] - 0.5; + + //ensure the values are within the appropriate range to avoid errors + tx = Math.max(-0.5, Math.min(0.5, tx)); + ty = Math.max(-0.5, Math.min(0.5, ty)); + for(i = 0; i < len; ++i) + { + key = this._transforms[i].shift(); + if(key) + { + normalizedMatrix[key].apply(normalizedMatrix, this._transforms[i]); + matrix[key].apply(matrix, this._transforms[i]); + } + } + if(isPathShape) + { + normalizedMatrix.translate(-this._left, -this._top); + } + transform = normalizedMatrix.a + "," + + normalizedMatrix.c + "," + + normalizedMatrix.b + "," + + normalizedMatrix.d + "," + + 0 + "," + + 0; + } + this._graphic.addToRedrawQueue(this); + if(transform) + { + if(!this._skew) + { + this._skew = DOCUMENT.createElement( + '' + ); + this.node.appendChild(this._skew); + } + this._skew.matrix = transform; + this._skew.on = true; + //this._skew.offset = this._getSkewOffsetValue(normalizedMatrix.dx) + "px, " + this._getSkewOffsetValue(normalizedMatrix.dy) + "px"; + this._skew.origin = tx + ", " + ty; + } + if(this._type !== "path") + { + this._transforms = []; + } + //add the translate to the x and y coordinates + node.style.left = (x + this._getSkewOffsetValue(normalizedMatrix.dx)) + "px"; + node.style.top = (y + this._getSkewOffsetValue(normalizedMatrix.dy)) + "px"; + }, + + /** + * Normalizes the skew offset values between -32767 and 32767. + * + * @method _getSkewOffsetValue + * @param {Number} val The value to normalize + * @return Number + * @private + */ + _getSkewOffsetValue: function(val) + { + var sign = Y.MatrixUtil.sign(val), + absVal = Math.abs(val); + val = Math.min(absVal, 32767) * sign; + return val; + }, + + /** + * Storage for translateX + * + * @property _translateX + * @type Number + * @private + */ + _translateX: 0, + + /** + * Storage for translateY + * + * @property _translateY + * @type Number + * @private + */ + _translateY: 0, + + /** + * Storage for the transform attribute. + * + * @property _transform + * @type String + * @private + */ + _transform: "", + + /** + * Specifies a 2d translation. + * + * @method translate + * @param {Number} x The value to translate on the x-axis. + * @param {Number} y The value to translate on the y-axis. + */ + translate: function(x, y) + { + this._translateX += x; + this._translateY += y; + this._addTransform("translate", arguments); + }, + + /** + * Translates the shape along the x-axis. When translating x and y coordinates, + * use the `translate` method. + * + * @method translateX + * @param {Number} x The value to translate. + */ + translateX: function(x) + { + this._translateX += x; + this._addTransform("translateX", arguments); + }, + + /** + * Performs a translate on the y-coordinate. When translating x and y coordinates, + * use the `translate` method. + * + * @method translateY + * @param {Number} y The value to translate. + */ + translateY: function(y) + { + this._translateY += y; + this._addTransform("translateY", arguments); + }, + + /** + * Skews the shape around the x-axis and y-axis. + * + * @method skew + * @param {Number} x The value to skew on the x-axis. + * @param {Number} y The value to skew on the y-axis. + */ + skew: function() + { + this._addTransform("skew", arguments); + }, + + /** + * Skews the shape around the x-axis. + * + * @method skewX + * @param {Number} x x-coordinate + */ + skewX: function() + { + this._addTransform("skewX", arguments); + }, + + /** + * Skews the shape around the y-axis. + * + * @method skewY + * @param {Number} y y-coordinate + */ + skewY: function() + { + this._addTransform("skewY", arguments); + }, + + /** + * Rotates the shape clockwise around it transformOrigin. + * + * @method rotate + * @param {Number} deg The degree of the rotation. + */ + rotate: function() + { + this._addTransform("rotate", arguments); + }, + + /** + * Specifies a 2d scaling operation. + * + * @method scale + * @param {Number} val + */ + scale: function() + { + this._addTransform("scale", arguments); + }, + + /** + * Overrides default `on` method. Checks to see if its a dom interaction event. If so, + * return an event attached to the `node` element. If not, return the normal functionality. + * + * @method on + * @param {String} type event type + * @param {Object} callback function + * @private + */ + on: function(type, fn) + { + if(Y.Node.DOM_EVENTS[type]) + { + return Y.one("#" + this.get("id")).on(type, fn); + } + return Y.on.apply(this, arguments); + }, + + /** + * Draws the shape. + * + * @method _draw + * @private + */ + _draw: function() + { + }, + + /** + * Updates `Shape` based on attribute changes. + * + * @method _updateHandler + * @private + */ + _updateHandler: function() + { + var host = this, + node = host.node; + host._fillChangeHandler(); + host._strokeChangeHandler(); + node.style.width = this.get("width") + "px"; + node.style.height = this.get("height") + "px"; + this._draw(); + host._updateTransform(); + }, + + /** + * Creates a graphic node + * + * @method _createGraphicNode + * @param {String} type node type to create + * @return HTMLElement + * @private + */ + _createGraphicNode: function(type) + { + type = type || this._type; + return DOCUMENT.createElement( + '<' + type + + ' xmlns="urn:schemas-microsft.com:vml"' + + ' style="behavior:url(#default#VML);display:inline-block;"' + + ' class="vml' + type + '"' + + '/>' + ); + }, + + /** + * Value function for fill attribute + * + * @private + * @method _getDefaultFill + * @return Object + */ + _getDefaultFill: function() { + return { + type: "solid", + opacity: 1, + cx: 0.5, + cy: 0.5, + fx: 0.5, + fy: 0.5, + r: 0.5 + }; + }, + + /** + * Value function for stroke attribute + * + * @private + * @method _getDefaultStroke + * @return Object + */ + _getDefaultStroke: function() + { + return { + weight: 1, + dashstyle: "none", + color: "#000", + opacity: 1.0 + }; + }, + + /** + * Sets the value of an attribute. + * + * @method set + * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can + * be passed in to set multiple attributes at once. + * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as + * the name param. + */ + set: function() + { + var host = this; + AttributeLite.prototype.set.apply(host, arguments); + if(host.initialized) + { + host._updateHandler(); + } + }, + + /** + * Returns the bounds for a shape. + * + * Calculates the a new bounding box from the original corner coordinates (base on size and position) and the transform matrix. + * The calculated bounding box is used by the graphic instance to calculate its viewBox. + * + * @method getBounds + * @return Object + */ + getBounds: function() + { + var isPathShape = this instanceof Y.VMLPath, + w = this.get("width"), + h = this.get("height"), + x = this.get("x"), + y = this.get("y"); + if(isPathShape) + { + x = x + this._left; + y = y + this._top; + w = this._right - this._left; + h = this._bottom - this._top; + } + return this._getContentRect(w, h, x, y); + }, + + /** + * Calculates the bounding box for the shape. + * + * @method _getContentRect + * @param {Number} w width of the shape + * @param {Number} h height of the shape + * @param {Number} x x-coordinate of the shape + * @param {Number} y y-coordinate of the shape + * @private + */ + _getContentRect: function(w, h, x, y) + { + var transformOrigin = this.get("transformOrigin"), + transformX = transformOrigin[0] * w, + transformY = transformOrigin[1] * h, + transforms = this.matrix.getTransformArray(this.get("transform")), + matrix = new Y.Matrix(), + i, + len = transforms.length, + transform, + key, + contentRect, + isPathShape = this instanceof Y.VMLPath; + if(isPathShape) + { + matrix.translate(this._left, this._top); + } + transformX = !isNaN(transformX) ? transformX : 0; + transformY = !isNaN(transformY) ? transformY : 0; + matrix.translate(transformX, transformY); + for(i = 0; i < len; i = i + 1) + { + transform = transforms[i]; + key = transform.shift(); + if(key) + { + matrix[key].apply(matrix, transform); + } + } + matrix.translate(-transformX, -transformY); + if(isPathShape) + { + matrix.translate(-this._left, -this._top); + } + contentRect = matrix.getContentRect(w, h, x, y); + return contentRect; + }, + + /** + * Places the shape above all other shapes. + * + * @method toFront + */ + toFront: function() + { + var graphic = this.get("graphic"); + if(graphic) + { + graphic._toFront(this); + } + }, + + /** + * Places the shape underneath all other shapes. + * + * @method toFront + */ + toBack: function() + { + var graphic = this.get("graphic"); + if(graphic) + { + graphic._toBack(this); + } + }, + + /** + * Parses path data string and call mapped methods. + * + * @method _parsePathData + * @param {String} val The path data + * @private + */ + _parsePathData: function(val) + { + var method, + methodSymbol, + args, + commandArray = Y.Lang.trim(val.match(SPLITPATHPATTERN)), + i, + len, + str, + symbolToMethod = this._pathSymbolToMethod; + if(commandArray) + { + this.clear(); + len = commandArray.length || 0; + for(i = 0; i < len; i = i + 1) + { + str = commandArray[i]; + methodSymbol = str.substr(0, 1); + args = str.substr(1).match(SPLITARGSPATTERN); + method = symbolToMethod[methodSymbol]; + if(method) + { + if(args) + { + this[method].apply(this, args); + } + else + { + this[method].apply(this); + } + } + } + this.end(); + } + }, + + /** + * Destroys shape + * + * @method destroy + */ + destroy: function() + { + var graphic = this.get("graphic"); + if(graphic) + { + graphic.removeShape(this); + } + else + { + this._destroy(); + } + }, + + /** + * Implementation for shape destruction + * + * @method destroy + * @protected + */ + _destroy: function() + { + if(this.node) + { + if(this._fillNode) + { + this.node.removeChild(this._fillNode); + this._fillNode = null; + } + if(this._strokeNode) + { + this.node.removeChild(this._strokeNode); + this._strokeNode = null; + } + Y.one(this.node).remove(true); + } + } +}, Y.VMLDrawing.prototype)); + +VMLShape.ATTRS = { + /** + * 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 + * fraction of the shape's corresponding bounding box dimension. The default value is [0.5, 0.5]. + * + * @config transformOrigin + * @type Array + */ + transformOrigin: { + valueFn: function() + { + return [0.5, 0.5]; + } + }, + + /** + *

A string containing, in order, transform operations applied to the shape instance. The `transform` string can contain the following values: + * + *

+ *
rotate
Rotates the shape clockwise around it transformOrigin.
+ *
translate
Specifies a 2d translation.
+ *
skew
Skews the shape around the x-axis and y-axis.
+ *
scale
Specifies a 2d scaling operation.
+ *
translateX
Translates the shape along the x-axis.
+ *
translateY
Translates the shape along the y-axis.
+ *
skewX
Skews the shape around the x-axis.
+ *
skewY
Skews the shape around the y-axis.
+ *
matrix
Specifies a 2D transformation matrix comprised of the specified six values.
+ *
+ *

+ *

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 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.

+ var myRect = new Y.Rect({ + type:"rect", + width: 50, + height: 40, + transform: "rotate(45)" + }; + *

The code below would apply `translate` and `rotate` to an existing shape.

+ + myRect.set("transform", "translate(40, 50) rotate(45)"); + * @config transform + * @type String + */ + transform: { + setter: function(val) + { + var i, + len, + transform; + this.matrix.init(); + this._normalizedMatrix.init(); + this._transforms = this.matrix.getTransformArray(val); + len = this._transforms.length; + for(i = 0;i < len; ++i) + { + transform = this._transforms[i]; + } + this._transform = val; + return val; + }, + + getter: function() + { + return this._transform; + } + }, + + /** + * Indicates the x position of shape. + * + * @config x + * @type Number + */ + x: { + value: 0 + }, + + /** + * Indicates the y position of shape. + * + * @config y + * @type Number + */ + y: { + value: 0 + }, + + /** + * Unique id for class instance. + * + * @config id + * @type String + */ + id: { + valueFn: function() + { + return Y.guid(); + }, + + setter: function(val) + { + var node = this.node; + if(node) + { + node.setAttribute("id", val); + } + return val; + } + }, + + /** + * + * @config width + */ + width: { + value: 0 + }, + + /** + * + * @config height + */ + height: { + value: 0 + }, + + /** + * Indicates whether the shape is visible. + * + * @config visible + * @type Boolean + */ + visible: { + value: true, + + setter: function(val){ + var node = this.node, + visibility = val ? "visible" : "hidden"; + if(node) + { + node.style.visibility = visibility; + } + return val; + } + }, + + /** + * Contains information about the fill of the shape. + *
+ *
color
The color of the fill.
+ *
opacity
Number between 0 and 1 that indicates the opacity of the fill. The default value is 1.
+ *
type
Type of fill. + *
+ *
solid
Solid single color fill. (default)
+ *
linear
Linear gradient fill.
+ *
radial
Radial gradient fill.
+ *
+ *
+ *
+ *

If a `linear` or `radial` is specified as the fill type. The following additional property is used: + *

+ *
stops
An array of objects containing the following properties: + *
+ *
color
The color of the stop.
+ *
opacity
Number between 0 and 1 that indicates the opacity of the stop. The default value is 1. + * Note: No effect for IE 6 - 8
+ *
offset
Number between 0 and 1 indicating where the color stop is positioned.
+ *
+ *
+ *

Linear gradients also have the following property:

+ *
rotation
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.)
+ *

Radial gradients have the following additional properties:

+ *
r
Radius of the gradient circle.
+ *
fx
Focal point x-coordinate of the gradient.
+ *
fy
Focal point y-coordinate of the gradient.
+ *
+ *

The corresponding `SVGShape` class implements the following additional properties.

+ *
+ *
cx
+ *

The x-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.

+ *

Note: Currently, this property is not implemented for corresponding `CanvasShape` and + * `VMLShape` classes which are used on Android or IE 6 - 8.

+ *
+ *
cy
+ *

The y-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.

+ *

Note: Currently, this property is not implemented for corresponding `CanvasShape` and `VMLShape` + * classes which are used on Android or IE 6 - 8.

+ *
+ *
+ *

These properties are not currently implemented in `CanvasShape` or `VMLShape`.

+ * + * @config fill + * @type Object + */ + fill: { + valueFn: "_getDefaultFill", + + setter: function(val) + { + var i, + fill, + tmpl = this.get("fill") || this._getDefaultFill(); + + if(val) + { + //ensure, fill type is solid if color is explicitly passed. + if(val.hasOwnProperty("color")) + { + val.type = "solid"; + } + for(i in val) + { + if(val.hasOwnProperty(i)) + { + tmpl[i] = val[i]; + } + } + } + fill = tmpl; + if(fill && fill.color) + { + if(fill.color === undefined || fill.color === "none") + { + fill.color = null; + } + } + this._fillFlag = true; + return fill; + } + }, + + /** + * Contains information about the stroke of the shape. + *
+ *
color
The color of the stroke.
+ *
weight
Number that indicates the width of the stroke.
+ *
opacity
Number between 0 and 1 that indicates the opacity of the stroke. The default value is 1.
+ *
dashstyle
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 length of the dash. The second index indicates the length of gap. + *
linecap
Specifies the linecap for the stroke. The following values can be specified: + *
+ *
butt (default)
Specifies a butt linecap.
+ *
square
Specifies a sqare linecap.
+ *
round
Specifies a round linecap.
+ *
+ *
+ *
linejoin
Specifies a linejoin for the stroke. The following values can be specified: + *
+ *
round (default)
Specifies that the linejoin will be round.
+ *
bevel
Specifies a bevel for the linejoin.
+ *
miter limit
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 separate miter and miter limit values.
+ *
+ *
+ *
+ * + * @config stroke + * @type Object + */ + stroke: { + valueFn: "_getDefaultStroke", + + setter: function(val) + { + var i, + stroke, + wt, + tmpl = this.get("stroke") || this._getDefaultStroke(); + if(val) + { + if(val.hasOwnProperty("weight")) + { + wt = parseInt(val.weight, 10); + if(!isNaN(wt)) + { + val.weight = wt; + } + } + for(i in val) + { + if(val.hasOwnProperty(i)) + { + tmpl[i] = val[i]; + } + } + } + stroke = tmpl; + this._strokeFlag = true; + return stroke; + } + }, + + //Not used. Remove in future. + autoSize: { + value: false + }, + + // Only implemented in SVG + // Determines whether the instance will receive mouse events. + // + // @config pointerEvents + // @type string + // + pointerEvents: { + value: "visiblePainted" + }, + + /** + * Dom node for the shape. + * + * @config node + * @type HTMLElement + * @readOnly + */ + node: { + readOnly: true, + + getter: function() + { + return this.node; + } + }, + + /** + * Represents an SVG Path string. This will be parsed and added to shape's API to represent the SVG data across all + * implementations. Note that when using VML or SVG implementations, part of this content will be added to the DOM using + * respective VML/SVG attributes. If your content comes from an untrusted source, you will need to ensure that no + * malicious code is included in that content. + * + * @config data + * @type String + */ + data: { + setter: function(val) + { + if(this.get("node")) + { + this._parsePathData(val); + } + return val; + } + }, + + /** + * Reference to the container Graphic. + * + * @config graphic + * @type Graphic + */ + graphic: { + readOnly: true, + + getter: function() + { + return this._graphic; + } + } +}; +Y.VMLShape = VMLShape; +/** + * VML implementation of the `Path` class. + * `VMLPath` is not intended to be used directly. Instead, use the `Path` class. + * If the browser lacks SVG and Canvas + * capabilities, the `Path` class will point to the `VMLPath` class. + * + * @module graphics + * @class VMLPath + * @extends VMLShape + */ +VMLPath = function() +{ + VMLPath.superclass.constructor.apply(this, arguments); +}; + +VMLPath.NAME = "path"; +Y.extend(VMLPath, Y.VMLShape); +VMLPath.ATTRS = Y.merge(Y.VMLShape.ATTRS, { + /** + * Indicates the width of the shape + * + * @config width + * @type Number + */ + width: { + getter: function() + { + var val = Math.max(this._right - this._left, 0); + return val; + } + }, + + /** + * Indicates the height of the shape + * + * @config height + * @type Number + */ + height: { + getter: function() + { + return Math.max(this._bottom - this._top, 0); + } + }, + + /** + * Indicates the path used for the node. + * + * @config path + * @type String + * @readOnly + */ + path: { + readOnly: true, + + getter: function() + { + return this._path; + } + } +}); +Y.VMLPath = VMLPath; +/** + * VML implementation of the `Rect` class. + * `VMLRect` is not intended to be used directly. Instead, use the `Rect` class. + * If the browser lacks SVG and Canvas + * capabilities, the `Rect` class will point to the `VMLRect` class. + * + * @module graphics + * @class VMLRect + * @constructor + */ +VMLRect = function() +{ + VMLRect.superclass.constructor.apply(this, arguments); +}; +VMLRect.NAME = "rect"; +Y.extend(VMLRect, Y.VMLShape, { + /** + * Indicates the type of shape + * + * @property _type + * @type String + * @private + */ + _type: "rect" +}); +VMLRect.ATTRS = Y.VMLShape.ATTRS; +Y.VMLRect = VMLRect; +/** + * VML implementation of the `Ellipse` class. + * `VMLEllipse` is not intended to be used directly. Instead, use the `Ellipse` class. + * If the browser lacks SVG and Canvas + * capabilities, the `Ellipse` class will point to the `VMLEllipse` class. + * + * @module graphics + * @class VMLEllipse + * @constructor + */ +VMLEllipse = function() +{ + VMLEllipse.superclass.constructor.apply(this, arguments); +}; + +VMLEllipse.NAME = "ellipse"; + +Y.extend(VMLEllipse, Y.VMLShape, { + /** + * Indicates the type of shape + * + * @property _type + * @type String + * @private + */ + _type: "oval" +}); +VMLEllipse.ATTRS = Y.merge(Y.VMLShape.ATTRS, { + /** + * Horizontal radius for the ellipse. + * + * @config xRadius + * @type Number + */ + xRadius: { + lazyAdd: false, + + getter: function() + { + var val = this.get("width"); + val = Math.round((val/2) * 100)/100; + return val; + }, + + setter: function(val) + { + var w = val * 2; + this.set("width", w); + return val; + } + }, + + /** + * Vertical radius for the ellipse. + * + * @config yRadius + * @type Number + * @readOnly + */ + yRadius: { + lazyAdd: false, + + getter: function() + { + var val = this.get("height"); + val = Math.round((val/2) * 100)/100; + return val; + }, + + setter: function(val) + { + var h = val * 2; + this.set("height", h); + return val; + } + } +}); +Y.VMLEllipse = VMLEllipse; +/** + * VML implementation of the `Circle` class. + * `VMLCircle` is not intended to be used directly. Instead, use the `Circle` class. + * If the browser lacks SVG and Canvas + * capabilities, the `Circle` class will point to the `VMLCircle` class. + * + * @module graphics + * @class VMLCircle + * @constructor + */ +VMLCircle = function() +{ + VMLCircle.superclass.constructor.apply(this, arguments); +}; + +VMLCircle.NAME = "circle"; + +Y.extend(VMLCircle, VMLShape, { + /** + * Indicates the type of shape + * + * @property _type + * @type String + * @private + */ + _type: "oval" +}); + +VMLCircle.ATTRS = Y.merge(VMLShape.ATTRS, { + /** + * Radius for the circle. + * + * @config radius + * @type Number + */ + radius: { + lazyAdd: false, + + value: 0 + }, + + /** + * Indicates the width of the shape + * + * @config width + * @type Number + */ + width: { + setter: function(val) + { + this.set("radius", val/2); + return val; + }, + + getter: function() + { + var radius = this.get("radius"), + val = radius && radius > 0 ? radius * 2 : 0; + return val; + } + }, + + /** + * Indicates the height of the shape + * + * @config height + * @type Number + */ + height: { + setter: function(val) + { + this.set("radius", val/2); + return val; + }, + + getter: function() + { + var radius = this.get("radius"), + val = radius && radius > 0 ? radius * 2 : 0; + return val; + } + } +}); +Y.VMLCircle = VMLCircle; +/** + * Draws pie slices + * + * @module graphics + * @class VMLPieSlice + * @constructor + */ +VMLPieSlice = function() +{ + VMLPieSlice.superclass.constructor.apply(this, arguments); +}; +VMLPieSlice.NAME = "vmlPieSlice"; +Y.extend(VMLPieSlice, Y.VMLShape, Y.mix({ + /** + * Indicates the type of shape + * + * @property _type + * @type String + * @private + */ + _type: "shape", + + /** + * Change event listener + * + * @private + * @method _updateHandler + */ + _draw: function() + { + var x = this.get("cx"), + y = this.get("cy"), + startAngle = this.get("startAngle"), + arc = this.get("arc"), + radius = this.get("radius"); + this.clear(); + this.drawWedge(x, y, startAngle, arc, radius); + this.end(); + } + }, Y.VMLDrawing.prototype)); +VMLPieSlice.ATTRS = Y.mix({ + cx: { + value: 0 + }, + + cy: { + value: 0 + }, + /** + * Starting angle in relation to a circle in which to begin the pie slice drawing. + * + * @config startAngle + * @type Number + */ + startAngle: { + value: 0 + }, + + /** + * Arc of the slice. + * + * @config arc + * @type Number + */ + arc: { + value: 0 + }, + + /** + * Radius of the circle in which the pie slice is drawn + * + * @config radius + * @type Number + */ + radius: { + value: 0 + } +}, Y.VMLShape.ATTRS); +Y.VMLPieSlice = VMLPieSlice; +/** + * VML implementation of the `Graphic` class. + * `VMLGraphic` is not intended to be used directly. Instead, use the `Graphic` class. + * If the browser lacks SVG and Canvas + * capabilities, the `Graphic` class will point to the `VMLGraphic` class. + * + * @module graphics + * @class VMLGraphic + * @constructor + */ +VMLGraphic = function() { + VMLGraphic.superclass.constructor.apply(this, arguments); +}; + +VMLGraphic.NAME = "vmlGraphic"; + +VMLGraphic.ATTRS = { + /** + * 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. + * + * @config render + * @type Node | String + */ + render: {}, + + /** + * Unique id for class instance. + * + * @config id + * @type String + */ + id: { + valueFn: function() + { + return Y.guid(); + }, + + setter: function(val) + { + var node = this._node; + if(node) + { + node.setAttribute("id", val); + } + return val; + } + }, + + /** + * Key value pairs in which a shape instance is associated with its id. + * + * @config shapes + * @type Object + * @readOnly + */ + shapes: { + readOnly: true, + + getter: function() + { + return this._shapes; + } + }, + + /** + * Object containing size and coordinate data for the content of a Graphic in relation to the coordSpace node. + * + * @config contentBounds + * @type Object + */ + contentBounds: { + readOnly: true, + + getter: function() + { + return this._contentBounds; + } + }, + + /** + * The html element that represents to coordinate system of the Graphic instance. + * + * @config node + * @type HTMLElement + */ + node: { + readOnly: true, + + getter: function() + { + return this._node; + } + }, + + /** + * Indicates the width of the `Graphic`. + * + * @config width + * @type Number + */ + width: { + setter: function(val) + { + if(this._node) + { + this._node.style.width = val + "px"; + } + return val; + } + }, + + /** + * Indicates the height of the `Graphic`. + * + * @config height + * @type Number + */ + height: { + setter: function(val) + { + if(this._node) + { + this._node.style.height = val + "px"; + } + return val; + } + }, + + /** + * Determines the sizing of the Graphic. + * + *
+ *
sizeContentToGraphic
The Graphic's width and height attributes are, either explicitly set through the + * width and height attributes or are determined by the dimensions of the parent element. The + * content contained in the Graphic will be sized to fit with in the Graphic instance's dimensions. When using this + * setting, the preserveAspectRatio attribute will determine how the contents are sized.
+ *
sizeGraphicToContent
(Also accepts a value of true) The Graphic's width and height are determined by the + * size and positioning of the content.
+ *
false
The Graphic's width and height attributes are, either explicitly set through the width + * and height attributes or are determined by the dimensions of the parent element. The contents of the + * Graphic instance are not affected by this setting.
+ *
+ * + * + * @config autoSize + * @type Boolean | String + * @default false + */ + autoSize: { + value: false + }, + + /** + * Determines how content is sized when autoSize is set to sizeContentToGraphic. + * + *
+ *
none
Do not force uniform scaling. Scale the graphic content of the given element non-uniformly if necessary + * such that the element's bounding box exactly matches the viewport rectangle.
+ *
xMinYMin
Force uniform scaling position along the top left of the Graphic's node.
+ *
xMidYMin
Force uniform scaling horizontally centered and positioned at the top of the Graphic's node.
+ *
xMaxYMin
Force uniform scaling positioned horizontally from the right and vertically from the top.
+ *
xMinYMid
Force uniform scaling positioned horizontally from the left and vertically centered. + *
xMidYMid (the default)
Force uniform scaling with the content centered.
+ *
xMaxYMid
Force uniform scaling positioned horizontally from the right and vertically centered.
+ *
xMinYMax
Force uniform scaling positioned horizontally from the left and vertically from the bottom.
+ *
xMidYMax
Force uniform scaling horizontally centered and position vertically from the bottom.
+ *
xMaxYMax
Force uniform scaling positioned horizontally from the right and vertically from the bottom.
+ *
+ * + * @config preserveAspectRatio + * @type String + * @default xMidYMid + */ + preserveAspectRatio: { + value: "xMidYMid" + }, + + /** + * The contentBounds will resize to greater values but not values. (for performance) + * When resizing the contentBounds down is desirable, set the resizeDown value to true. + * + * @config resizeDown + * @type Boolean + */ + resizeDown: { + resizeDown: false + }, + + /** + * Indicates the x-coordinate for the instance. + * + * @config x + * @type Number + */ + x: { + getter: function() + { + return this._x; + }, + + setter: function(val) + { + this._x = val; + if(this._node) + { + this._node.style.left = val + "px"; + } + return val; + } + }, + + /** + * Indicates the y-coordinate for the instance. + * + * @config y + * @type Number + */ + y: { + getter: function() + { + return this._y; + }, + + setter: function(val) + { + this._y = val; + if(this._node) + { + this._node.style.top = val + "px"; + } + return val; + } + }, + + /** + * Indicates whether or not the instance will automatically redraw after a change is made to a shape. + * This property will get set to false when batching operations. + * + * @config autoDraw + * @type Boolean + * @default true + * @private + */ + autoDraw: { + value: true + }, + + visible: { + value: true, + + setter: function(val) + { + this._toggleVisible(val); + return val; + } + } +}; + +Y.extend(VMLGraphic, Y.GraphicBase, { + /** + * Sets the value of an attribute. + * + * @method set + * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can + * be passed in to set multiple attributes at once. + * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as + * the name param. + */ + set: function() + { + var host = this, + attr = arguments[0], + redrawAttrs = { + autoDraw: true, + autoSize: true, + preserveAspectRatio: true, + resizeDown: true + }, + key, + forceRedraw = false; + AttributeLite.prototype.set.apply(host, arguments); + if(host._state.autoDraw === true && Y.Object.size(this._shapes) > 0) + { + if(Y_LANG.isString && redrawAttrs[attr]) + { + forceRedraw = true; + } + else if(Y_LANG.isObject(attr)) + { + for(key in redrawAttrs) + { + if(redrawAttrs.hasOwnProperty(key) && attr[key]) + { + forceRedraw = true; + break; + } + } + } + } + if(forceRedraw) + { + host._redraw(); + } + }, + + /** + * Storage for `x` attribute. + * + * @property _x + * @type Number + * @private + */ + _x: 0, + + /** + * Storage for `y` attribute. + * + * @property _y + * @type Number + * @private + */ + _y: 0, + + /** + * Gets the current position of the graphic instance in page coordinates. + * + * @method getXY + * @return Array The XY position of the shape. + */ + getXY: function() + { + var node = this.parentNode, + x = this.get("x"), + y = this.get("y"), + xy; + if(node) + { + xy = Y.one(node).getXY(); + xy[0] += x; + xy[1] += y; + } + else + { + xy = Y.DOM._getOffset(this._node); + } + return xy; + }, + + /** + * Initializes the class. + * + * @method initializer + * @private + */ + initializer: function() { + var render = this.get("render"), + visibility = this.get("visible") ? "visible" : "hidden"; + this._shapes = {}; + this._contentBounds = { + left: 0, + top: 0, + right: 0, + bottom: 0 + }; + this._node = this._createGraphic(); + this._node.style.left = this.get("x") + "px"; + this._node.style.top = this.get("y") + "px"; + this._node.style.visibility = visibility; + this._node.setAttribute("id", this.get("id")); + if(render) + { + this.render(render); + } + }, + + /** + * Adds the graphics node to the dom. + * + * @method render + * @param {HTMLElement} parentNode node in which to render the graphics node into. + */ + render: function(render) { + var parentNode = Y.one(render), + w = this.get("width") || parseInt(parentNode.getComputedStyle("width"), 10), + h = this.get("height") || parseInt(parentNode.getComputedStyle("height"), 10); + parentNode = parentNode || DOCUMENT.body; + parentNode.appendChild(this._node); + this.parentNode = parentNode; + this.set("width", w); + this.set("height", h); + return this; + }, + + /** + * Removes all nodes. + * + * @method destroy + */ + destroy: function() + { + this.clear(); + Y.one(this._node).remove(true); + }, + + /** + * Generates a shape instance by type. + * + * @method addShape + * @param {Object} cfg attributes for the shape + * @return Shape + */ + addShape: function(cfg) + { + cfg.graphic = this; + if(!this.get("visible")) + { + cfg.visible = false; + } + var ShapeClass = this._getShapeClass(cfg.type), + shape = new ShapeClass(cfg); + this._appendShape(shape); + shape._appendStrokeAndFill(); + return shape; + }, + + /** + * Adds a shape instance to the graphic instance. + * + * @method _appendShape + * @param {Shape} shape The shape instance to be added to the graphic. + * @private + */ + _appendShape: function(shape) + { + var node = shape.node, + parentNode = this._frag || this._node; + if(this.get("autoDraw") || this.get("autoSize") === "sizeContentToGraphic") + { + parentNode.appendChild(node); + } + else + { + this._getDocFrag().appendChild(node); + } + }, + + /** + * Removes a shape instance from from the graphic instance. + * + * @method removeShape + * @param {Shape|String} shape The instance or id of the shape to be removed. + */ + removeShape: function(shape) + { + if(!(shape instanceof VMLShape)) + { + if(Y_LANG.isString(shape)) + { + shape = this._shapes[shape]; + } + } + if(shape && (shape instanceof VMLShape)) + { + shape._destroy(); + this._shapes[shape.get("id")] = null; + delete this._shapes[shape.get("id")]; + } + if(this.get("autoDraw")) + { + this._redraw(); + } + }, + + /** + * Removes all shape instances from the dom. + * + * @method removeAllShapes + */ + removeAllShapes: function() + { + var shapes = this._shapes, + i; + for(i in shapes) + { + if(shapes.hasOwnProperty(i)) + { + shapes[i].destroy(); + } + } + this._shapes = {}; + }, + + /** + * Removes all child nodes. + * + * @method _removeChildren + * @param node + * @private + */ + _removeChildren: function(node) + { + if(node.hasChildNodes()) + { + var child; + while(node.firstChild) + { + child = node.firstChild; + this._removeChildren(child); + node.removeChild(child); + } + } + }, + + /** + * Clears the graphics object. + * + * @method clear + */ + clear: function() { + this.removeAllShapes(); + this._removeChildren(this._node); + }, + + /** + * Toggles visibility + * + * @method _toggleVisible + * @param {Boolean} val indicates visibilitye + * @private + */ + _toggleVisible: function(val) + { + var i, + shapes = this._shapes, + visibility = val ? "visible" : "hidden"; + if(shapes) + { + for(i in shapes) + { + if(shapes.hasOwnProperty(i)) + { + shapes[i].set("visible", val); + } + } + } + if(this._node) + { + this._node.style.visibility = visibility; + } + if(this._node) + { + this._node.style.visibility = visibility; + } + }, + + /** + * Sets the size of the graphics object. + * + * @method setSize + * @param w {Number} width to set for the instance. + * @param h {Number} height to set for the instance. + */ + setSize: function(w, h) { + w = Math.round(w); + h = Math.round(h); + this._node.style.width = w + 'px'; + this._node.style.height = h + 'px'; + }, + + /** + * Sets the positon of the graphics object. + * + * @method setPosition + * @param {Number} x x-coordinate for the object. + * @param {Number} y y-coordinate for the object. + */ + setPosition: function(x, y) + { + x = Math.round(x); + y = Math.round(y); + this._node.style.left = x + "px"; + this._node.style.top = y + "px"; + }, + + /** + * Creates a group element + * + * @method _createGraphic + * @private + */ + _createGraphic: function() { + var group = DOCUMENT.createElement( + '' + ); + return group; + }, + + /** + * Creates a graphic node + * + * @method _createGraphicNode + * @param {String} type node type to create + * @param {String} pe specified pointer-events value + * @return HTMLElement + * @private + */ + _createGraphicNode: function(type) + { + return DOCUMENT.createElement( + '<' + + type + + ' xmlns="urn:schemas-microsft.com:vml"' + + ' style="behavior:url(#default#VML);display:inline-block;zoom:1;"' + + '/>' + ); + + }, + + /** + * Returns a shape based on the id of its dom node. + * + * @method getShapeById + * @param {String} id Dom id of the shape's node attribute. + * @return Shape + */ + getShapeById: function(id) + { + return this._shapes[id]; + }, + + /** + * Returns a shape class. Used by `addShape`. + * + * @method _getShapeClass + * @param {Shape | String} val Indicates which shape class. + * @return Function + * @private + */ + _getShapeClass: function(val) + { + var shape = this._shapeClass[val]; + if(shape) + { + return shape; + } + return val; + }, + + /** + * Look up for shape classes. Used by `addShape` to retrieve a class for instantiation. + * + * @property _shapeClass + * @type Object + * @private + */ + _shapeClass: { + circle: Y.VMLCircle, + rect: Y.VMLRect, + path: Y.VMLPath, + ellipse: Y.VMLEllipse, + pieslice: Y.VMLPieSlice + }, + + /** + * Allows for creating multiple shapes in order to batch appending and redraw operations. + * + * @method batch + * @param {Function} method Method to execute. + */ + batch: function(method) + { + var autoDraw = this.get("autoDraw"); + this.set("autoDraw", false); + method.apply(); + this.set("autoDraw", autoDraw); + }, + + /** + * Returns a document fragment to for attaching shapes. + * + * @method _getDocFrag + * @return DocumentFragment + * @private + */ + _getDocFrag: function() + { + if(!this._frag) + { + this._frag = DOCUMENT.createDocumentFragment(); + } + return this._frag; + }, + + /** + * Adds a shape to the redraw queue and calculates the contentBounds. + * + * @method addToRedrawQueue + * @param shape {VMLShape} + * @protected + */ + addToRedrawQueue: function(shape) + { + var shapeBox, + box; + this._shapes[shape.get("id")] = shape; + if(!this.get("resizeDown")) + { + shapeBox = shape.getBounds(); + box = this._contentBounds; + box.left = box.left < shapeBox.left ? box.left : shapeBox.left; + box.top = box.top < shapeBox.top ? box.top : shapeBox.top; + box.right = box.right > shapeBox.right ? box.right : shapeBox.right; + box.bottom = box.bottom > shapeBox.bottom ? box.bottom : shapeBox.bottom; + box.width = box.right - box.left; + box.height = box.bottom - box.top; + this._contentBounds = box; + } + if(this.get("autoDraw")) + { + this._redraw(); + } + }, + + /** + * Redraws all shapes. + * + * @method _redraw + * @private + */ + _redraw: function() + { + var autoSize = this.get("autoSize"), + preserveAspectRatio, + node = this.parentNode, + nodeWidth = parseFloat(node.getComputedStyle("width")), + nodeHeight = parseFloat(node.getComputedStyle("height")), + xCoordOrigin = 0, + yCoordOrigin = 0, + box = this.get("resizeDown") ? this._getUpdatedContentBounds() : this._contentBounds, + left = box.left, + right = box.right, + top = box.top, + bottom = box.bottom, + contentWidth = right - left, + contentHeight = bottom - top, + aspectRatio, + xCoordSize, + yCoordSize, + scaledWidth, + scaledHeight, + visible = this.get("visible"); + this._node.style.visibility = "hidden"; + if(autoSize) + { + if(autoSize === "sizeContentToGraphic") + { + preserveAspectRatio = this.get("preserveAspectRatio"); + if(preserveAspectRatio === "none" || contentWidth/contentHeight === nodeWidth/nodeHeight) + { + xCoordOrigin = left; + yCoordOrigin = top; + xCoordSize = contentWidth; + yCoordSize = contentHeight; + } + else + { + if(contentWidth * nodeHeight/contentHeight > nodeWidth) + { + aspectRatio = nodeHeight/nodeWidth; + xCoordSize = contentWidth; + yCoordSize = contentWidth * aspectRatio; + scaledHeight = (nodeWidth * (contentHeight/contentWidth)) * (yCoordSize/nodeHeight); + yCoordOrigin = this._calculateCoordOrigin(preserveAspectRatio.slice(5).toLowerCase(), scaledHeight, yCoordSize); + yCoordOrigin = top + yCoordOrigin; + xCoordOrigin = left; + } + else + { + aspectRatio = nodeWidth/nodeHeight; + xCoordSize = contentHeight * aspectRatio; + yCoordSize = contentHeight; + scaledWidth = (nodeHeight * (contentWidth/contentHeight)) * (xCoordSize/nodeWidth); + xCoordOrigin = this._calculateCoordOrigin(preserveAspectRatio.slice(1, 4).toLowerCase(), scaledWidth, xCoordSize); + xCoordOrigin = xCoordOrigin + left; + yCoordOrigin = top; + } + } + this._node.style.width = nodeWidth + "px"; + this._node.style.height = nodeHeight + "px"; + this._node.coordOrigin = xCoordOrigin + ", " + yCoordOrigin; + } + else + { + xCoordSize = contentWidth; + yCoordSize = contentHeight; + this._node.style.width = contentWidth + "px"; + this._node.style.height = contentHeight + "px"; + this._state.width = contentWidth; + this._state.height = contentHeight; + + } + this._node.coordSize = xCoordSize + ", " + yCoordSize; + } + else + { + this._node.style.width = nodeWidth + "px"; + this._node.style.height = nodeHeight + "px"; + this._node.coordSize = nodeWidth + ", " + nodeHeight; + } + if(this._frag) + { + this._node.appendChild(this._frag); + this._frag = null; + } + if(visible) + { + this._node.style.visibility = "visible"; + } + }, + + /** + * Determines the value for either an x or y coordinate to be used for the coordOrigin of the Graphic. + * + * @method _calculateCoordOrigin + * @param {String} position The position for placement. Possible values are min, mid and max. + * @param {Number} size The total scaled size of the content. + * @param {Number} coordsSize The coordsSize for the Graphic. + * @return Number + * @private + */ + _calculateCoordOrigin: function(position, size, coordsSize) + { + var coord; + switch(position) + { + case "min" : + coord = 0; + break; + case "mid" : + coord = (size - coordsSize)/2; + break; + case "max" : + coord = (size - coordsSize); + break; + } + return coord; + }, + + /** + * Recalculates and returns the `contentBounds` for the `Graphic` instance. + * + * @method _getUpdatedContentBounds + * @return {Object} + * @private + */ + _getUpdatedContentBounds: function() + { + var bounds, + i, + shape, + queue = this._shapes, + box = {}; + for(i in queue) + { + if(queue.hasOwnProperty(i)) + { + shape = queue[i]; + bounds = shape.getBounds(); + box.left = Y_LANG.isNumber(box.left) ? Math.min(box.left, bounds.left) : bounds.left; + box.top = Y_LANG.isNumber(box.top) ? Math.min(box.top, bounds.top) : bounds.top; + box.right = Y_LANG.isNumber(box.right) ? Math.max(box.right, bounds.right) : bounds.right; + box.bottom = Y_LANG.isNumber(box.bottom) ? Math.max(box.bottom, bounds.bottom) : bounds.bottom; + } + } + box.left = Y_LANG.isNumber(box.left) ? box.left : 0; + box.top = Y_LANG.isNumber(box.top) ? box.top : 0; + box.right = Y_LANG.isNumber(box.right) ? box.right : 0; + box.bottom = Y_LANG.isNumber(box.bottom) ? box.bottom : 0; + this._contentBounds = box; + return box; + }, + + /** + * Inserts shape on the top of the tree. + * + * @method _toFront + * @param {VMLShape} Shape to add. + * @private + */ + _toFront: function(shape) + { + var contentNode = this._node; + if(shape instanceof Y.VMLShape) + { + shape = shape.get("node"); + } + if(contentNode && shape) + { + contentNode.appendChild(shape); + } + }, + + /** + * Inserts shape as the first child of the content node. + * + * @method _toBack + * @param {VMLShape} Shape to add. + * @private + */ + _toBack: function(shape) + { + var contentNode = this._node, + targetNode; + if(shape instanceof Y.VMLShape) + { + shape = shape.get("node"); + } + if(contentNode && shape) + { + targetNode = contentNode.firstChild; + if(targetNode) + { + contentNode.insertBefore(shape, targetNode); + } + else + { + contentNode.appendChild(shape); + } + } + } +}); +Y.VMLGraphic = VMLGraphic; + + + +}, '3.10.3', {"requires": ["graphics"]});