src/cm/media/js/lib/yui/yui3-3.15.0/build/axis/axis-debug.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     1 YUI.add('axis', function (Y, NAME) {
       
     2 
       
     3 /**
       
     4  * Provides base functionality for drawing chart axes.
       
     5  *
       
     6  * @module charts
       
     7  * @submodule axis
       
     8  */
       
     9 var CONFIG = Y.config,
       
    10     DOCUMENT = CONFIG.doc,
       
    11     Y_Lang = Y.Lang,
       
    12     IS_STRING = Y_Lang.isString,
       
    13     Y_DOM = Y.DOM,
       
    14     LeftAxisLayout,
       
    15     RightAxisLayout,
       
    16     BottomAxisLayout,
       
    17     TopAxisLayout;
       
    18 /**
       
    19  * Algorithmic strategy for rendering a left axis.
       
    20  *
       
    21  * @class LeftAxisLayout
       
    22  * @constructor
       
    23  * @submodule axis
       
    24  */
       
    25 LeftAxisLayout = function() {};
       
    26 
       
    27 LeftAxisLayout.prototype = {
       
    28     /**
       
    29      *  Default margins for text fields.
       
    30      *
       
    31      *  @private
       
    32      *  @method _getDefaultMargins
       
    33      *  @return Object
       
    34      */
       
    35     _getDefaultMargins: function()
       
    36     {
       
    37         return {
       
    38             top: 0,
       
    39             left: 0,
       
    40             right: 4,
       
    41             bottom: 0
       
    42         };
       
    43     },
       
    44 
       
    45     /**
       
    46      * Sets the length of the tick on either side of the axis line.
       
    47      *
       
    48      * @method setTickOffset
       
    49      * @protected
       
    50      */
       
    51     setTickOffsets: function()
       
    52     {
       
    53         var host = this,
       
    54             majorTicks = host.get("styles").majorTicks,
       
    55             tickLength = majorTicks.length,
       
    56             halfTick = tickLength * 0.5,
       
    57             display = majorTicks.display;
       
    58         host.set("topTickOffset",  0);
       
    59         host.set("bottomTickOffset",  0);
       
    60 
       
    61         switch(display)
       
    62         {
       
    63             case "inside" :
       
    64                 host.set("rightTickOffset",  tickLength);
       
    65                 host.set("leftTickOffset", 0);
       
    66             break;
       
    67             case "outside" :
       
    68                 host.set("rightTickOffset", 0);
       
    69                 host.set("leftTickOffset",  tickLength);
       
    70             break;
       
    71             case "cross":
       
    72                 host.set("rightTickOffset", halfTick);
       
    73                 host.set("leftTickOffset",  halfTick);
       
    74             break;
       
    75             default:
       
    76                 host.set("rightTickOffset", 0);
       
    77                 host.set("leftTickOffset", 0);
       
    78             break;
       
    79         }
       
    80     },
       
    81 
       
    82     /**
       
    83      * Draws a tick
       
    84      *
       
    85      * @method drawTick
       
    86      * @param {Path} path reference to the path `Path` element in which to draw the tick.
       
    87      * @param {Object} pt Point on the axis in which the tick will intersect.
       
    88      * @param {Object} tickStyle Hash of properties to apply to the tick.
       
    89      * @protected
       
    90      */
       
    91     drawTick: function(path, pt, tickStyles)
       
    92     {
       
    93         var host = this,
       
    94             style = host.get("styles"),
       
    95             padding = style.padding,
       
    96             tickLength = tickStyles.length,
       
    97             start = {x:padding.left, y:pt.y},
       
    98             end = {x:tickLength + padding.left, y:pt.y};
       
    99         host.drawLine(path, start, end);
       
   100     },
       
   101 
       
   102     /**
       
   103      * Calculates the coordinates for the first point on an axis.
       
   104      *
       
   105      * @method getLineStart
       
   106      * @return {Object}
       
   107      * @protected
       
   108      */
       
   109     getLineStart: function()
       
   110     {
       
   111         var style = this.get("styles"),
       
   112             padding = style.padding,
       
   113             majorTicks = style.majorTicks,
       
   114             tickLength = majorTicks.length,
       
   115             display = majorTicks.display,
       
   116             pt = {x:padding.left, y:0};
       
   117         if(display === "outside")
       
   118         {
       
   119             pt.x += tickLength;
       
   120         }
       
   121         else if(display === "cross")
       
   122         {
       
   123             pt.x += tickLength/2;
       
   124         }
       
   125         return pt;
       
   126     },
       
   127 
       
   128     /**
       
   129      * Calculates the point for a label.
       
   130      *
       
   131      * @method getLabelPoint
       
   132      * @param {Object} point Point on the axis in which the tick will intersect.
       
   133      * @return {Object}
       
   134      * @protected
       
   135      */
       
   136     getLabelPoint: function(point)
       
   137     {
       
   138         return {x:point.x - this.get("leftTickOffset"), y:point.y};
       
   139     },
       
   140 
       
   141     /**
       
   142      * Updates the value for the `maxLabelSize` for use in calculating total size.
       
   143      *
       
   144      * @method updateMaxLabelSize
       
   145      * @param {HTMLElement} label to measure
       
   146      * @protected
       
   147      */
       
   148     updateMaxLabelSize: function(labelWidth, labelHeight)
       
   149     {
       
   150         var host = this,
       
   151             props = this._labelRotationProps,
       
   152             rot = props.rot,
       
   153             absRot = props.absRot,
       
   154             sinRadians = props.sinRadians,
       
   155             cosRadians = props.cosRadians,
       
   156             max;
       
   157         if(rot === 0)
       
   158         {
       
   159             max = labelWidth;
       
   160         }
       
   161         else if(absRot === 90)
       
   162         {
       
   163             max = labelHeight;
       
   164         }
       
   165         else
       
   166         {
       
   167             max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
       
   168         }
       
   169         host._maxLabelSize = Math.max(host._maxLabelSize, max);
       
   170     },
       
   171 
       
   172     /**
       
   173      * Determines the available label width when the axis width has been explicitly set.
       
   174      *
       
   175      * @method getExplicitlySized
       
   176      * @return Boolean
       
   177      * @protected
       
   178      */
       
   179     getExplicitlySized: function(styles)
       
   180     {
       
   181         if(this._explicitWidth)
       
   182         {
       
   183             var host = this,
       
   184                 w = host._explicitWidth,
       
   185                 totalTitleSize = host._totalTitleSize,
       
   186                 leftTickOffset = host.get("leftTickOffset"),
       
   187                 margin = styles.label.margin.right;
       
   188             host._maxLabelSize =  w - (leftTickOffset + margin + totalTitleSize);
       
   189             return true;
       
   190         }
       
   191         return false;
       
   192     },
       
   193 
       
   194     /**
       
   195      * Rotate and position title.
       
   196      *
       
   197      * @method positionTitle
       
   198      * @param {HTMLElement} label to rotate position
       
   199      * @protected
       
   200      */
       
   201     positionTitle: function(label)
       
   202     {
       
   203         var host = this,
       
   204             bounds = host._titleBounds,
       
   205             margin = host.get("styles").title.margin,
       
   206             props = host._titleRotationProps,
       
   207             w = bounds.right - bounds.left,
       
   208             labelWidth = label.offsetWidth,
       
   209             labelHeight = label.offsetHeight,
       
   210             x = (labelWidth * -0.5) + (w * 0.5),
       
   211             y = (host.get("height") * 0.5) - (labelHeight * 0.5);
       
   212         props.labelWidth = labelWidth;
       
   213         props.labelHeight = labelHeight;
       
   214         if(margin && margin.left)
       
   215         {
       
   216             x += margin.left;
       
   217         }
       
   218         props.x = x;
       
   219         props.y = y;
       
   220         props.transformOrigin = [0.5, 0.5];
       
   221         host._rotate(label, props);
       
   222     },
       
   223 
       
   224     /**
       
   225      * Rotate and position labels.
       
   226      *
       
   227      * @method positionLabel
       
   228      * @param {HTMLElement} label to rotate position
       
   229      * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
       
   230      * against.
       
   231      * @protected
       
   232      */
       
   233     positionLabel: function(label, pt, styles, i)
       
   234     {
       
   235         var host = this,
       
   236             offset = parseFloat(styles.label.offset),
       
   237             tickOffset = host.get("leftTickOffset"),
       
   238             totalTitleSize = this._totalTitleSize,
       
   239             leftOffset = pt.x + totalTitleSize - tickOffset,
       
   240             topOffset = pt.y,
       
   241             props = this._labelRotationProps,
       
   242             rot = props.rot,
       
   243             absRot = props.absRot,
       
   244             maxLabelSize = host._maxLabelSize,
       
   245             labelWidth = this._labelWidths[i],
       
   246             labelHeight = this._labelHeights[i];
       
   247         if(rot === 0)
       
   248         {
       
   249             leftOffset -= labelWidth;
       
   250             topOffset -= labelHeight * offset;
       
   251         }
       
   252         else if(rot === 90)
       
   253         {
       
   254             leftOffset -= labelWidth * 0.5;
       
   255             topOffset = topOffset + labelWidth/2 - (labelWidth * offset);
       
   256         }
       
   257         else if(rot === -90)
       
   258         {
       
   259             leftOffset -= labelWidth * 0.5;
       
   260             topOffset = topOffset - labelHeight + labelWidth/2 - (labelWidth * offset);
       
   261         }
       
   262         else
       
   263         {
       
   264             leftOffset -= labelWidth + (labelHeight * absRot/360);
       
   265             topOffset -= labelHeight * offset;
       
   266         }
       
   267         props.labelWidth = labelWidth;
       
   268         props.labelHeight = labelHeight;
       
   269         props.x = Math.round(maxLabelSize + leftOffset);
       
   270         props.y = Math.round(topOffset);
       
   271         this._rotate(label, props);
       
   272     },
       
   273 
       
   274     /**
       
   275      * Adjusts the coordinates of an axis label based on the rotation.
       
   276      *
       
   277      * @method _setRotationCoords
       
   278      * @param {Object} props Coordinates, dimension and rotation properties of the label.
       
   279      * @protected
       
   280      */
       
   281     _setRotationCoords: function(props)
       
   282     {
       
   283         var rot = props.rot,
       
   284             absRot = props.absRot,
       
   285             leftOffset,
       
   286             topOffset,
       
   287             labelWidth = props.labelWidth,
       
   288             labelHeight = props.labelHeight;
       
   289         if(rot === 0)
       
   290         {
       
   291             leftOffset = labelWidth;
       
   292             topOffset = labelHeight * 0.5;
       
   293         }
       
   294         else if(rot === 90)
       
   295         {
       
   296             topOffset = 0;
       
   297             leftOffset = labelWidth * 0.5;
       
   298         }
       
   299         else if(rot === -90)
       
   300         {
       
   301             leftOffset = labelWidth * 0.5;
       
   302             topOffset = labelHeight;
       
   303         }
       
   304         else
       
   305         {
       
   306             leftOffset = labelWidth + (labelHeight * absRot/360);
       
   307             topOffset = labelHeight * 0.5;
       
   308         }
       
   309         props.x -= leftOffset;
       
   310         props.y -= topOffset;
       
   311     },
       
   312 
       
   313     /**
       
   314      * Returns the transformOrigin to use for an axis label based on the position of the axis
       
   315      * and the rotation of the label.
       
   316      *
       
   317      * @method _getTransformOrigin
       
   318      * @param {Number} rot The rotation (in degrees) of the label.
       
   319      * @return Array
       
   320      * @protected
       
   321      */
       
   322     _getTransformOrigin: function(rot)
       
   323     {
       
   324         var transformOrigin;
       
   325         if(rot === 0)
       
   326         {
       
   327             transformOrigin = [0, 0];
       
   328         }
       
   329         else if(rot === 90)
       
   330         {
       
   331             transformOrigin = [0.5, 0];
       
   332         }
       
   333         else if(rot === -90)
       
   334         {
       
   335             transformOrigin = [0.5, 1];
       
   336         }
       
   337         else
       
   338         {
       
   339             transformOrigin = [1, 0.5];
       
   340         }
       
   341         return transformOrigin;
       
   342     },
       
   343 
       
   344     /**
       
   345      * Adjust the position of the Axis widget's content box for internal axes.
       
   346      *
       
   347      * @method offsetNodeForTick
       
   348      * @param {Node} cb contentBox of the axis
       
   349      * @protected
       
   350      */
       
   351     offsetNodeForTick: function()
       
   352     {
       
   353     },
       
   354 
       
   355     /**
       
   356      * Sets the width of the axis based on its contents.
       
   357      *
       
   358      * @method setCalculatedSize
       
   359      * @protected
       
   360      */
       
   361     setCalculatedSize: function()
       
   362     {
       
   363         var host = this,
       
   364             graphic = this.get("graphic"),
       
   365             style = host.get("styles"),
       
   366             label = style.label,
       
   367             tickOffset = host.get("leftTickOffset"),
       
   368             max = host._maxLabelSize,
       
   369             totalTitleSize = this._totalTitleSize,
       
   370             ttl = Math.round(totalTitleSize + tickOffset + max + label.margin.right);
       
   371         if(this._explicitWidth)
       
   372         {
       
   373             ttl = this._explicitWidth;
       
   374         }
       
   375         this.set("calculatedWidth", ttl);
       
   376         graphic.set("x", ttl - tickOffset);
       
   377     }
       
   378 };
       
   379 
       
   380 Y.LeftAxisLayout = LeftAxisLayout;
       
   381 /**
       
   382  * RightAxisLayout contains algorithms for rendering a right axis.
       
   383  *
       
   384  * @class RightAxisLayout
       
   385  * @constructor
       
   386  * @submodule axis
       
   387  */
       
   388 RightAxisLayout = function(){};
       
   389 
       
   390 RightAxisLayout.prototype = {
       
   391     /**
       
   392      *  Default margins for text fields.
       
   393      *
       
   394      *  @private
       
   395      *  @method _getDefaultMargins
       
   396      *  @return Object
       
   397      */
       
   398     _getDefaultMargins: function()
       
   399     {
       
   400         return {
       
   401             top: 0,
       
   402             left: 4,
       
   403             right: 0,
       
   404             bottom: 0
       
   405         };
       
   406     },
       
   407 
       
   408     /**
       
   409      * Sets the length of the tick on either side of the axis line.
       
   410      *
       
   411      * @method setTickOffset
       
   412      * @protected
       
   413      */
       
   414     setTickOffsets: function()
       
   415     {
       
   416         var host = this,
       
   417             majorTicks = host.get("styles").majorTicks,
       
   418             tickLength = majorTicks.length,
       
   419             halfTick = tickLength * 0.5,
       
   420             display = majorTicks.display;
       
   421         host.set("topTickOffset",  0);
       
   422         host.set("bottomTickOffset",  0);
       
   423 
       
   424         switch(display)
       
   425         {
       
   426             case "inside" :
       
   427                 host.set("leftTickOffset", tickLength);
       
   428                 host.set("rightTickOffset", 0);
       
   429             break;
       
   430             case "outside" :
       
   431                 host.set("leftTickOffset", 0);
       
   432                 host.set("rightTickOffset", tickLength);
       
   433             break;
       
   434             case "cross" :
       
   435                 host.set("rightTickOffset", halfTick);
       
   436                 host.set("leftTickOffset", halfTick);
       
   437             break;
       
   438             default:
       
   439                 host.set("leftTickOffset", 0);
       
   440                 host.set("rightTickOffset", 0);
       
   441             break;
       
   442         }
       
   443     },
       
   444 
       
   445     /**
       
   446      * Draws a tick
       
   447      *
       
   448      * @method drawTick
       
   449      * @param {Path} path reference to the path `Path` element in which to draw the tick.
       
   450      * @param {Object} pt Point on the axis in which the tick will intersect.
       
   451      * @param {Object} tickStyle Hash of properties to apply to the tick.
       
   452      * @protected
       
   453      */
       
   454     drawTick: function(path, pt, tickStyles)
       
   455     {
       
   456         var host = this,
       
   457             style = host.get("styles"),
       
   458             padding = style.padding,
       
   459             tickLength = tickStyles.length,
       
   460             start = {x:padding.left, y:pt.y},
       
   461             end = {x:padding.left + tickLength, y:pt.y};
       
   462         host.drawLine(path, start, end);
       
   463     },
       
   464 
       
   465     /**
       
   466      * Calculates the coordinates for the first point on an axis.
       
   467      *
       
   468      * @method getLineStart
       
   469      * @return {Object}
       
   470      * @protected
       
   471      */
       
   472     getLineStart: function()
       
   473     {
       
   474         var host = this,
       
   475             style = host.get("styles"),
       
   476             padding = style.padding,
       
   477             majorTicks = style.majorTicks,
       
   478             tickLength = majorTicks.length,
       
   479             display = majorTicks.display,
       
   480             pt = {x:padding.left, y:padding.top};
       
   481         if(display === "inside")
       
   482         {
       
   483             pt.x += tickLength;
       
   484         }
       
   485         else if(display === "cross")
       
   486         {
       
   487             pt.x += tickLength/2;
       
   488         }
       
   489         return pt;
       
   490     },
       
   491 
       
   492     /**
       
   493      * Calculates the point for a label.
       
   494      *
       
   495      * @method getLabelPoint
       
   496      * @param {Object} point Point on the axis in which the tick will intersect.
       
   497      * @return {Object}
       
   498      * @protected
       
   499      */
       
   500     getLabelPoint: function(point)
       
   501     {
       
   502         return {x:point.x + this.get("rightTickOffset"), y:point.y};
       
   503     },
       
   504 
       
   505     /**
       
   506      * Updates the value for the `maxLabelSize` for use in calculating total size.
       
   507      *
       
   508      * @method updateMaxLabelSize
       
   509      * @param {HTMLElement} label to measure
       
   510      * @protected
       
   511      */
       
   512     updateMaxLabelSize: function(labelWidth, labelHeight)
       
   513     {
       
   514         var host = this,
       
   515             props = this._labelRotationProps,
       
   516             rot = props.rot,
       
   517             absRot = props.absRot,
       
   518             sinRadians = props.sinRadians,
       
   519             cosRadians = props.cosRadians,
       
   520             max;
       
   521         if(rot === 0)
       
   522         {
       
   523             max = labelWidth;
       
   524         }
       
   525         else if(absRot === 90)
       
   526         {
       
   527             max = labelHeight;
       
   528         }
       
   529         else
       
   530         {
       
   531             max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
       
   532         }
       
   533         host._maxLabelSize = Math.max(host._maxLabelSize, max);
       
   534     },
       
   535 
       
   536     /**
       
   537      * Determines the available label width when the axis width has been explicitly set.
       
   538      *
       
   539      * @method getExplicitlySized
       
   540      * @return Boolean
       
   541      * @protected
       
   542      */
       
   543     getExplicitlySized: function(styles)
       
   544     {
       
   545         if(this._explicitWidth)
       
   546         {
       
   547             var host = this,
       
   548                 w = host._explicitWidth,
       
   549                 totalTitleSize = this._totalTitleSize,
       
   550                 rightTickOffset = host.get("rightTickOffset"),
       
   551                 margin = styles.label.margin.right;
       
   552             host._maxLabelSize =  w - (rightTickOffset + margin + totalTitleSize);
       
   553             return true;
       
   554         }
       
   555         return false;
       
   556     },
       
   557 
       
   558     /**
       
   559      * Rotate and position title.
       
   560      *
       
   561      * @method positionTitle
       
   562      * @param {HTMLElement} label to rotate position
       
   563      * @protected
       
   564      */
       
   565     positionTitle: function(label)
       
   566     {
       
   567         var host = this,
       
   568             bounds = host._titleBounds,
       
   569             margin = host.get("styles").title.margin,
       
   570             props = host._titleRotationProps,
       
   571             labelWidth = label.offsetWidth,
       
   572             labelHeight = label.offsetHeight,
       
   573             w = bounds.right - bounds.left,
       
   574             x = this.get("width") - (labelWidth * 0.5) - (w * 0.5),
       
   575             y = (host.get("height") * 0.5) - (labelHeight * 0.5);
       
   576         props.labelWidth = labelWidth;
       
   577         props.labelHeight = labelHeight;
       
   578         if(margin && margin.right)
       
   579         {
       
   580             x -= margin.left;
       
   581         }
       
   582         props.x = x;
       
   583         props.y = y;
       
   584         props.transformOrigin = [0.5, 0.5];
       
   585         host._rotate(label, props);
       
   586     },
       
   587 
       
   588     /**
       
   589      * Rotate and position labels.
       
   590      *
       
   591      * @method positionLabel
       
   592      * @param {HTMLElement} label to rotate position
       
   593      * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
       
   594      * against.
       
   595      * @protected
       
   596      */
       
   597     positionLabel: function(label, pt, styles, i)
       
   598     {
       
   599         var host = this,
       
   600             offset = parseFloat(styles.label.offset),
       
   601             tickOffset = host.get("rightTickOffset"),
       
   602             labelStyles = styles.label,
       
   603             margin = 0,
       
   604             leftOffset = pt.x,
       
   605             topOffset = pt.y,
       
   606             props = this._labelRotationProps,
       
   607             rot = props.rot,
       
   608             absRot = props.absRot,
       
   609             labelWidth = this._labelWidths[i],
       
   610             labelHeight = this._labelHeights[i];
       
   611         if(labelStyles.margin && labelStyles.margin.left)
       
   612         {
       
   613             margin = labelStyles.margin.left;
       
   614         }
       
   615         if(rot === 0)
       
   616         {
       
   617             topOffset -= labelHeight * offset;
       
   618         }
       
   619         else if(rot === 90)
       
   620         {
       
   621             leftOffset -= labelWidth * 0.5;
       
   622             topOffset = topOffset - labelHeight + labelWidth/2 - (labelWidth * offset);
       
   623         }
       
   624         else if(rot === -90)
       
   625         {
       
   626             topOffset = topOffset + labelWidth/2 - (labelWidth * offset);
       
   627             leftOffset -= labelWidth * 0.5;
       
   628         }
       
   629         else
       
   630         {
       
   631             topOffset -= labelHeight * offset;
       
   632             leftOffset += labelHeight/2 * absRot/90;
       
   633         }
       
   634         leftOffset += margin;
       
   635         leftOffset += tickOffset;
       
   636         props.labelWidth = labelWidth;
       
   637         props.labelHeight = labelHeight;
       
   638         props.x = Math.round(leftOffset);
       
   639         props.y = Math.round(topOffset);
       
   640         this._rotate(label, props);
       
   641     },
       
   642 
       
   643     /**
       
   644      * Adjusts the coordinates of an axis label based on the rotation.
       
   645      *
       
   646      * @method _setRotationCoords
       
   647      * @param {Object} props Coordinates, dimension and rotation properties of the label.
       
   648      * @protected
       
   649      */
       
   650     _setRotationCoords: function(props)
       
   651     {
       
   652         var rot = props.rot,
       
   653             absRot = props.absRot,
       
   654             leftOffset = 0,
       
   655             topOffset = 0,
       
   656             labelWidth = props.labelWidth,
       
   657             labelHeight = props.labelHeight;
       
   658         if(rot === 0)
       
   659         {
       
   660             topOffset = labelHeight * 0.5;
       
   661         }
       
   662         else if(rot === 90)
       
   663         {
       
   664             leftOffset = labelWidth * 0.5;
       
   665             topOffset = labelHeight;
       
   666         }
       
   667         else if(rot === -90)
       
   668         {
       
   669             leftOffset = labelWidth * 0.5;
       
   670         }
       
   671         else
       
   672         {
       
   673             topOffset = labelHeight * 0.5;
       
   674             leftOffset = labelHeight/2 * absRot/90;
       
   675         }
       
   676         props.x -= leftOffset;
       
   677         props.y -= topOffset;
       
   678     },
       
   679 
       
   680     /**
       
   681      * Returns the transformOrigin to use for an axis label based on the position of the axis
       
   682      * and the rotation of the label.
       
   683      *
       
   684      * @method _getTransformOrigin
       
   685      * @param {Number} rot The rotation (in degrees) of the label.
       
   686      * @return Array
       
   687      * @protected
       
   688      */
       
   689     _getTransformOrigin: function(rot)
       
   690     {
       
   691         var transformOrigin;
       
   692         if(rot === 0)
       
   693         {
       
   694             transformOrigin = [0, 0];
       
   695         }
       
   696         else if(rot === 90)
       
   697         {
       
   698             transformOrigin = [0.5, 1];
       
   699         }
       
   700         else if(rot === -90)
       
   701         {
       
   702             transformOrigin = [0.5, 0];
       
   703         }
       
   704         else
       
   705         {
       
   706             transformOrigin = [0, 0.5];
       
   707         }
       
   708         return transformOrigin;
       
   709     },
       
   710 
       
   711     /**
       
   712      * Adjusts position for inner ticks.
       
   713      *
       
   714      * @method offsetNodeForTick
       
   715      * @param {Node} cb contentBox of the axis
       
   716      * @protected
       
   717      */
       
   718     offsetNodeForTick: function(cb)
       
   719     {
       
   720         var host = this,
       
   721             tickOffset = host.get("leftTickOffset"),
       
   722             offset = 0 - tickOffset;
       
   723         cb.setStyle("left", offset);
       
   724     },
       
   725 
       
   726     /**
       
   727      * Assigns a height based on the size of the contents.
       
   728      *
       
   729      * @method setCalculatedSize
       
   730      * @protected
       
   731      */
       
   732     setCalculatedSize: function()
       
   733     {
       
   734         var host = this,
       
   735             styles = host.get("styles"),
       
   736             labelStyle = styles.label,
       
   737             totalTitleSize = this._totalTitleSize,
       
   738             ttl = Math.round(host.get("rightTickOffset") + host._maxLabelSize + totalTitleSize + labelStyle.margin.left);
       
   739         if(this._explicitWidth)
       
   740         {
       
   741             ttl = this._explicitWidth;
       
   742         }
       
   743         host.set("calculatedWidth", ttl);
       
   744         host.get("contentBox").setStyle("width", ttl);
       
   745     }
       
   746 };
       
   747 
       
   748 Y.RightAxisLayout = RightAxisLayout;
       
   749 /**
       
   750  * Contains algorithms for rendering a bottom axis.
       
   751  *
       
   752  * @class BottomAxisLayout
       
   753  * @Constructor
       
   754  * @submodule axis
       
   755  */
       
   756 BottomAxisLayout = function(){};
       
   757 
       
   758 BottomAxisLayout.prototype = {
       
   759     /**
       
   760      *  Default margins for text fields.
       
   761      *
       
   762      *  @private
       
   763      *  @method _getDefaultMargins
       
   764      *  @return Object
       
   765      */
       
   766     _getDefaultMargins: function()
       
   767     {
       
   768         return {
       
   769             top: 4,
       
   770             left: 0,
       
   771             right: 0,
       
   772             bottom: 0
       
   773         };
       
   774     },
       
   775 
       
   776     /**
       
   777      * Sets the length of the tick on either side of the axis line.
       
   778      *
       
   779      * @method setTickOffsets
       
   780      * @protected
       
   781      */
       
   782     setTickOffsets: function()
       
   783     {
       
   784         var host = this,
       
   785             majorTicks = host.get("styles").majorTicks,
       
   786             tickLength = majorTicks.length,
       
   787             halfTick = tickLength * 0.5,
       
   788             display = majorTicks.display;
       
   789         host.set("leftTickOffset",  0);
       
   790         host.set("rightTickOffset",  0);
       
   791 
       
   792         switch(display)
       
   793         {
       
   794             case "inside" :
       
   795                 host.set("topTickOffset", tickLength);
       
   796                 host.set("bottomTickOffset", 0);
       
   797             break;
       
   798             case "outside" :
       
   799                 host.set("topTickOffset", 0);
       
   800                 host.set("bottomTickOffset", tickLength);
       
   801             break;
       
   802             case "cross":
       
   803                 host.set("topTickOffset",  halfTick);
       
   804                 host.set("bottomTickOffset",  halfTick);
       
   805             break;
       
   806             default:
       
   807                 host.set("topTickOffset", 0);
       
   808                 host.set("bottomTickOffset", 0);
       
   809             break;
       
   810         }
       
   811     },
       
   812 
       
   813     /**
       
   814      * Calculates the coordinates for the first point on an axis.
       
   815      *
       
   816      * @method getLineStart
       
   817      * @protected
       
   818      */
       
   819     getLineStart: function()
       
   820     {
       
   821         var style = this.get("styles"),
       
   822             padding = style.padding,
       
   823             majorTicks = style.majorTicks,
       
   824             tickLength = majorTicks.length,
       
   825             display = majorTicks.display,
       
   826             pt = {x:0, y:padding.top};
       
   827         if(display === "inside")
       
   828         {
       
   829             pt.y += tickLength;
       
   830         }
       
   831         else if(display === "cross")
       
   832         {
       
   833             pt.y += tickLength/2;
       
   834         }
       
   835         return pt;
       
   836     },
       
   837 
       
   838     /**
       
   839      * Draws a tick
       
   840      *
       
   841      * @method drawTick
       
   842      * @param {Path} path reference to the path `Path` element in which to draw the tick.
       
   843      * @param {Object} pt hash containing x and y coordinates
       
   844      * @param {Object} tickStyles hash of properties used to draw the tick
       
   845      * @protected
       
   846      */
       
   847     drawTick: function(path, pt, tickStyles)
       
   848     {
       
   849         var host = this,
       
   850             style = host.get("styles"),
       
   851             padding = style.padding,
       
   852             tickLength = tickStyles.length,
       
   853             start = {x:pt.x, y:padding.top},
       
   854             end = {x:pt.x, y:tickLength + padding.top};
       
   855         host.drawLine(path, start, end);
       
   856     },
       
   857 
       
   858     /**
       
   859      * Calculates the point for a label.
       
   860      *
       
   861      * @method getLabelPoint
       
   862      * @param {Object} pt Object containing x and y coordinates
       
   863      * @return Object
       
   864      * @protected
       
   865      */
       
   866     getLabelPoint: function(point)
       
   867     {
       
   868         return {x:point.x, y:point.y + this.get("bottomTickOffset")};
       
   869     },
       
   870 
       
   871     /**
       
   872      * Updates the value for the `maxLabelSize` for use in calculating total size.
       
   873      *
       
   874      * @method updateMaxLabelSize
       
   875      * @param {HTMLElement} label to measure
       
   876      * @protected
       
   877      */
       
   878     updateMaxLabelSize: function(labelWidth, labelHeight)
       
   879     {
       
   880         var host = this,
       
   881             props = this._labelRotationProps,
       
   882             rot = props.rot,
       
   883             absRot = props.absRot,
       
   884             sinRadians = props.sinRadians,
       
   885             cosRadians = props.cosRadians,
       
   886             max;
       
   887         if(rot === 0)
       
   888         {
       
   889             max = labelHeight;
       
   890         }
       
   891         else if(absRot === 90)
       
   892         {
       
   893             max = labelWidth;
       
   894         }
       
   895         else
       
   896         {
       
   897             max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
       
   898         }
       
   899         host._maxLabelSize = Math.max(host._maxLabelSize, max);
       
   900     },
       
   901 
       
   902     /**
       
   903      * Determines the available label height when the axis width has been explicitly set.
       
   904      *
       
   905      * @method getExplicitlySized
       
   906      * @return Boolean
       
   907      * @protected
       
   908      */
       
   909     getExplicitlySized: function(styles)
       
   910     {
       
   911         if(this._explicitHeight)
       
   912         {
       
   913             var host = this,
       
   914                 h = host._explicitHeight,
       
   915                 totalTitleSize = host._totalTitleSize,
       
   916                 bottomTickOffset = host.get("bottomTickOffset"),
       
   917                 margin = styles.label.margin.right;
       
   918             host._maxLabelSize =  h - (bottomTickOffset + margin + totalTitleSize);
       
   919             return true;
       
   920         }
       
   921         return false;
       
   922     },
       
   923 
       
   924     /**
       
   925      * Rotate and position title.
       
   926      *
       
   927      * @method positionTitle
       
   928      * @param {HTMLElement} label to rotate position
       
   929      * @protected
       
   930      */
       
   931     positionTitle: function(label)
       
   932     {
       
   933         var host = this,
       
   934             bounds = host._titleBounds,
       
   935             margin = host.get("styles").title.margin,
       
   936             props = host._titleRotationProps,
       
   937             h = bounds.bottom - bounds.top,
       
   938             labelWidth = label.offsetWidth,
       
   939             labelHeight = label.offsetHeight,
       
   940             x = (host.get("width") * 0.5) - (labelWidth * 0.5),
       
   941             y = host.get("height") - labelHeight/2 - h/2;
       
   942         props.labelWidth = labelWidth;
       
   943         props.labelHeight = labelHeight;
       
   944         if(margin && margin.bottom)
       
   945         {
       
   946             y -= margin.bottom;
       
   947         }
       
   948         props.x = x;
       
   949         props.y = y;
       
   950         props.transformOrigin = [0.5, 0.5];
       
   951         host._rotate(label, props);
       
   952     },
       
   953 
       
   954     /**
       
   955      * Rotate and position labels.
       
   956      *
       
   957      * @method positionLabel
       
   958      * @param {HTMLElement} label to rotate position
       
   959      * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
       
   960      * against.
       
   961      * @protected
       
   962      */
       
   963     positionLabel: function(label, pt, styles, i)
       
   964     {
       
   965         var host = this,
       
   966             offset = parseFloat(styles.label.offset),
       
   967             tickOffset = host.get("bottomTickOffset"),
       
   968             labelStyles = styles.label,
       
   969             margin = 0,
       
   970             props = host._labelRotationProps,
       
   971             rot = props.rot,
       
   972             absRot = props.absRot,
       
   973             leftOffset = Math.round(pt.x),
       
   974             topOffset = Math.round(pt.y),
       
   975             labelWidth = host._labelWidths[i],
       
   976             labelHeight = host._labelHeights[i];
       
   977         if(labelStyles.margin && labelStyles.margin.top)
       
   978         {
       
   979             margin = labelStyles.margin.top;
       
   980         }
       
   981         if(rot === 90)
       
   982         {
       
   983             topOffset -= labelHeight/2 * rot/90;
       
   984             leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
       
   985         }
       
   986         else if(rot === -90)
       
   987         {
       
   988             topOffset -= labelHeight/2 * absRot/90;
       
   989             leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
       
   990         }
       
   991         else if(rot > 0)
       
   992         {
       
   993             leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
       
   994             topOffset -= labelHeight/2 * rot/90;
       
   995         }
       
   996         else if(rot < 0)
       
   997         {
       
   998             leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
       
   999             topOffset -= labelHeight/2 * absRot/90;
       
  1000         }
       
  1001         else
       
  1002         {
       
  1003             leftOffset -= labelWidth * offset;
       
  1004         }
       
  1005         topOffset += margin;
       
  1006         topOffset += tickOffset;
       
  1007         props.labelWidth = labelWidth;
       
  1008         props.labelHeight = labelHeight;
       
  1009         props.x = leftOffset;
       
  1010         props.y = topOffset;
       
  1011         host._rotate(label, props);
       
  1012     },
       
  1013 
       
  1014     /**
       
  1015      * Adjusts the coordinates of an axis label based on the rotation.
       
  1016      *
       
  1017      * @method _setRotationCoords
       
  1018      * @param {Object} props Coordinates, dimension and rotation properties of the label.
       
  1019      * @protected
       
  1020      */
       
  1021     _setRotationCoords: function(props)
       
  1022     {
       
  1023         var rot = props.rot,
       
  1024             absRot = props.absRot,
       
  1025             labelWidth = props.labelWidth,
       
  1026             labelHeight = props.labelHeight,
       
  1027             leftOffset,
       
  1028             topOffset;
       
  1029 
       
  1030         if(rot > 0)
       
  1031         {
       
  1032             leftOffset = 0;
       
  1033             topOffset = labelHeight/2 * rot/90;
       
  1034         }
       
  1035         else if(rot < 0)
       
  1036         {
       
  1037             leftOffset = labelWidth;
       
  1038             topOffset = labelHeight/2 * absRot/90;
       
  1039         }
       
  1040         else
       
  1041         {
       
  1042             leftOffset = labelWidth * 0.5;
       
  1043             topOffset = 0;
       
  1044         }
       
  1045         props.x -= leftOffset;
       
  1046         props.y -= topOffset;
       
  1047     },
       
  1048 
       
  1049     /**
       
  1050      * Returns the transformOrigin to use for an axis label based on the position of the axis
       
  1051      * and the rotation of the label.
       
  1052      *
       
  1053      * @method _getTransformOrigin
       
  1054      * @param {Number} rot The rotation (in degrees) of the label.
       
  1055      * @return Array
       
  1056      * @protected
       
  1057      */
       
  1058     _getTransformOrigin: function(rot)
       
  1059     {
       
  1060         var transformOrigin;
       
  1061         if(rot > 0)
       
  1062         {
       
  1063             transformOrigin = [0, 0.5];
       
  1064         }
       
  1065         else if(rot < 0)
       
  1066         {
       
  1067             transformOrigin = [1, 0.5];
       
  1068         }
       
  1069         else
       
  1070         {
       
  1071             transformOrigin = [0, 0];
       
  1072         }
       
  1073         return transformOrigin;
       
  1074     },
       
  1075 
       
  1076     /**
       
  1077      * Adjusts position for inner ticks.
       
  1078      *
       
  1079      * @method offsetNodeForTick
       
  1080      * @param {Node} cb contentBox of the axis
       
  1081      * @protected
       
  1082      */
       
  1083     offsetNodeForTick: function(cb)
       
  1084     {
       
  1085         var host = this;
       
  1086         cb.setStyle("top", 0 - host.get("topTickOffset"));
       
  1087     },
       
  1088 
       
  1089     /**
       
  1090      * Assigns a height based on the size of the contents.
       
  1091      *
       
  1092      * @method setCalculatedSize
       
  1093      * @protected
       
  1094      */
       
  1095     setCalculatedSize: function()
       
  1096     {
       
  1097         var host = this,
       
  1098             styles = host.get("styles"),
       
  1099             labelStyle = styles.label,
       
  1100             totalTitleSize = host._totalTitleSize,
       
  1101             ttl = Math.round(host.get("bottomTickOffset") + host._maxLabelSize + labelStyle.margin.top + totalTitleSize);
       
  1102         if(host._explicitHeight)
       
  1103         {
       
  1104             ttl = host._explicitHeight;
       
  1105         }
       
  1106         host.set("calculatedHeight", ttl);
       
  1107     }
       
  1108 };
       
  1109 Y.BottomAxisLayout = BottomAxisLayout;
       
  1110 /**
       
  1111  * Contains algorithms for rendering a top axis.
       
  1112  *
       
  1113  * @class TopAxisLayout
       
  1114  * @constructor
       
  1115  * @submodule axis
       
  1116  */
       
  1117 TopAxisLayout = function(){};
       
  1118 
       
  1119 TopAxisLayout.prototype = {
       
  1120     /**
       
  1121      *  Default margins for text fields.
       
  1122      *
       
  1123      *  @private
       
  1124      *  @method _getDefaultMargins
       
  1125      *  @return Object
       
  1126      */
       
  1127     _getDefaultMargins: function()
       
  1128     {
       
  1129         return {
       
  1130             top: 0,
       
  1131             left: 0,
       
  1132             right: 0,
       
  1133             bottom: 4
       
  1134         };
       
  1135     },
       
  1136 
       
  1137     /**
       
  1138      * Sets the length of the tick on either side of the axis line.
       
  1139      *
       
  1140      * @method setTickOffsets
       
  1141      * @protected
       
  1142      */
       
  1143     setTickOffsets: function()
       
  1144     {
       
  1145         var host = this,
       
  1146             majorTicks = host.get("styles").majorTicks,
       
  1147             tickLength = majorTicks.length,
       
  1148             halfTick = tickLength * 0.5,
       
  1149             display = majorTicks.display;
       
  1150         host.set("leftTickOffset",  0);
       
  1151         host.set("rightTickOffset",  0);
       
  1152         switch(display)
       
  1153         {
       
  1154             case "inside" :
       
  1155                 host.set("bottomTickOffset", tickLength);
       
  1156                 host.set("topTickOffset", 0);
       
  1157             break;
       
  1158             case "outside" :
       
  1159                 host.set("bottomTickOffset", 0);
       
  1160                 host.set("topTickOffset",  tickLength);
       
  1161             break;
       
  1162             case "cross" :
       
  1163                 host.set("topTickOffset", halfTick);
       
  1164                 host.set("bottomTickOffset", halfTick);
       
  1165             break;
       
  1166             default:
       
  1167                 host.set("topTickOffset", 0);
       
  1168                 host.set("bottomTickOffset", 0);
       
  1169             break;
       
  1170         }
       
  1171     },
       
  1172 
       
  1173     /**
       
  1174      * Calculates the coordinates for the first point on an axis.
       
  1175      *
       
  1176      * @method getLineStart
       
  1177      * @protected
       
  1178      */
       
  1179     getLineStart: function()
       
  1180     {
       
  1181         var host = this,
       
  1182             style = host.get("styles"),
       
  1183             padding = style.padding,
       
  1184             majorTicks = style.majorTicks,
       
  1185             tickLength = majorTicks.length,
       
  1186             display = majorTicks.display,
       
  1187             pt = {x:0, y:padding.top};
       
  1188         if(display === "outside")
       
  1189         {
       
  1190             pt.y += tickLength;
       
  1191         }
       
  1192         else if(display === "cross")
       
  1193         {
       
  1194             pt.y += tickLength/2;
       
  1195         }
       
  1196         return pt;
       
  1197     },
       
  1198 
       
  1199     /**
       
  1200      * Draws a tick
       
  1201      *
       
  1202      * @method drawTick
       
  1203      * @param {Path} path reference to the path `Path` element in which to draw the tick.
       
  1204      * @param {Object} pt hash containing x and y coordinates
       
  1205      * @param {Object} tickStyles hash of properties used to draw the tick
       
  1206      * @protected
       
  1207      */
       
  1208     drawTick: function(path, pt, tickStyles)
       
  1209     {
       
  1210         var host = this,
       
  1211             style = host.get("styles"),
       
  1212             padding = style.padding,
       
  1213             tickLength = tickStyles.length,
       
  1214             start = {x:pt.x, y:padding.top},
       
  1215             end = {x:pt.x, y:tickLength + padding.top};
       
  1216         host.drawLine(path, start, end);
       
  1217     },
       
  1218 
       
  1219     /**
       
  1220      * Calculates the point for a label.
       
  1221      *
       
  1222      * @method getLabelPoint
       
  1223      * @param {Object} pt hash containing x and y coordinates
       
  1224      * @return Object
       
  1225      * @protected
       
  1226      */
       
  1227     getLabelPoint: function(pt)
       
  1228     {
       
  1229         return {x:pt.x, y:pt.y - this.get("topTickOffset")};
       
  1230     },
       
  1231 
       
  1232     /**
       
  1233      * Updates the value for the `maxLabelSize` for use in calculating total size.
       
  1234      *
       
  1235      * @method updateMaxLabelSize
       
  1236      * @param {HTMLElement} label to measure
       
  1237      * @protected
       
  1238      */
       
  1239     updateMaxLabelSize: function(labelWidth, labelHeight)
       
  1240     {
       
  1241         var host = this,
       
  1242             props = this._labelRotationProps,
       
  1243             rot = props.rot,
       
  1244             absRot = props.absRot,
       
  1245             sinRadians = props.sinRadians,
       
  1246             cosRadians = props.cosRadians,
       
  1247             max;
       
  1248         if(rot === 0)
       
  1249         {
       
  1250             max = labelHeight;
       
  1251         }
       
  1252         else if(absRot === 90)
       
  1253         {
       
  1254             max = labelWidth;
       
  1255         }
       
  1256         else
       
  1257         {
       
  1258             max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
       
  1259         }
       
  1260         host._maxLabelSize = Math.max(host._maxLabelSize, max);
       
  1261     },
       
  1262 
       
  1263     /**
       
  1264      * Determines the available label height when the axis width has been explicitly set.
       
  1265      *
       
  1266      * @method getExplicitlySized
       
  1267      * @return Boolean
       
  1268      * @protected
       
  1269      */
       
  1270     getExplicitlySized: function(styles)
       
  1271     {
       
  1272         if(this._explicitHeight)
       
  1273         {
       
  1274             var host = this,
       
  1275                 h = host._explicitHeight,
       
  1276                 totalTitleSize = host._totalTitleSize,
       
  1277                 topTickOffset = host.get("topTickOffset"),
       
  1278                 margin = styles.label.margin.right;
       
  1279             host._maxLabelSize =  h - (topTickOffset + margin + totalTitleSize);
       
  1280             return true;
       
  1281         }
       
  1282         return false;
       
  1283     },
       
  1284 
       
  1285     /**
       
  1286      * Rotate and position title.
       
  1287      *
       
  1288      * @method positionTitle
       
  1289      * @param {HTMLElement} label to rotate position
       
  1290      * @protected
       
  1291      */
       
  1292     positionTitle: function(label)
       
  1293     {
       
  1294         var host = this,
       
  1295             bounds = host._titleBounds,
       
  1296             margin = host.get("styles").title.margin,
       
  1297             props = host._titleRotationProps,
       
  1298             labelWidth = label.offsetWidth,
       
  1299             labelHeight = label.offsetHeight,
       
  1300             h = bounds.bottom - bounds.top,
       
  1301             x = (host.get("width") * 0.5) - (labelWidth * 0.5),
       
  1302             y = h/2 - labelHeight/2;
       
  1303         props.labelWidth = labelWidth;
       
  1304         props.labelHeight = labelHeight;
       
  1305         if(margin && margin.top)
       
  1306         {
       
  1307             y += margin.top;
       
  1308         }
       
  1309         props.x = x;
       
  1310         props.y = y;
       
  1311         props.transformOrigin = [0.5, 0.5];
       
  1312         host._rotate(label, props);
       
  1313     },
       
  1314 
       
  1315     /**
       
  1316      * Rotate and position labels.
       
  1317      *
       
  1318      * @method positionLabel
       
  1319      * @param {HTMLElement} label to rotate position
       
  1320      * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
       
  1321      * against.
       
  1322      * @protected
       
  1323      */
       
  1324     positionLabel: function(label, pt, styles, i)
       
  1325     {
       
  1326         var host = this,
       
  1327             offset = parseFloat(styles.label.offset),
       
  1328             totalTitleSize = this._totalTitleSize,
       
  1329             maxLabelSize = host._maxLabelSize,
       
  1330             leftOffset = pt.x,
       
  1331             topOffset = pt.y + totalTitleSize + maxLabelSize,
       
  1332             props = this._labelRotationProps,
       
  1333             rot = props.rot,
       
  1334             absRot = props.absRot,
       
  1335             labelWidth = this._labelWidths[i],
       
  1336             labelHeight = this._labelHeights[i];
       
  1337         if(rot === 0)
       
  1338         {
       
  1339             leftOffset -= labelWidth * offset;
       
  1340             topOffset -= labelHeight;
       
  1341         }
       
  1342         else
       
  1343         {
       
  1344             if(rot === 90)
       
  1345             {
       
  1346                 leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
       
  1347                 topOffset -= (labelHeight * 0.5);
       
  1348             }
       
  1349             else if (rot === -90)
       
  1350             {
       
  1351                 leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
       
  1352                 topOffset -= (labelHeight * 0.5);
       
  1353             }
       
  1354             else if(rot > 0)
       
  1355             {
       
  1356                 leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
       
  1357                 topOffset -= labelHeight - (labelHeight * rot/180);
       
  1358             }
       
  1359             else
       
  1360             {
       
  1361                 leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
       
  1362                 topOffset -= labelHeight - (labelHeight * absRot/180);
       
  1363             }
       
  1364         }
       
  1365         props.x = Math.round(leftOffset);
       
  1366         props.y = Math.round(topOffset);
       
  1367         props.labelWidth = labelWidth;
       
  1368         props.labelHeight = labelHeight;
       
  1369         this._rotate(label, props);
       
  1370     },
       
  1371 
       
  1372     /**
       
  1373      * Adjusts the coordinates of an axis label based on the rotation.
       
  1374      *
       
  1375      * @method _setRotationCoords
       
  1376      * @param {Object} props Coordinates, dimension and rotation properties of the label.
       
  1377      * @protected
       
  1378      */
       
  1379     _setRotationCoords: function(props)
       
  1380     {
       
  1381         var rot = props.rot,
       
  1382             absRot = props.absRot,
       
  1383             labelWidth = props.labelWidth,
       
  1384             labelHeight = props.labelHeight,
       
  1385             leftOffset,
       
  1386             topOffset;
       
  1387         if(rot === 0)
       
  1388         {
       
  1389             leftOffset = labelWidth * 0.5;
       
  1390             topOffset = labelHeight;
       
  1391         }
       
  1392         else
       
  1393         {
       
  1394             if(rot === 90)
       
  1395             {
       
  1396                 leftOffset = labelWidth;
       
  1397                 topOffset = (labelHeight * 0.5);
       
  1398             }
       
  1399             else if (rot === -90)
       
  1400             {
       
  1401                 topOffset = (labelHeight * 0.5);
       
  1402             }
       
  1403             else if(rot > 0)
       
  1404             {
       
  1405                 leftOffset = labelWidth;
       
  1406                 topOffset = labelHeight - (labelHeight * rot/180);
       
  1407             }
       
  1408             else
       
  1409             {
       
  1410                 topOffset = labelHeight - (labelHeight * absRot/180);
       
  1411             }
       
  1412         }
       
  1413         props.x -= leftOffset;
       
  1414         props.y -= topOffset;
       
  1415     },
       
  1416 
       
  1417     /**
       
  1418      * Returns the transformOrigin to use for an axis label based on the position of the axis
       
  1419      * and the rotation of the label.
       
  1420      *
       
  1421      * @method _getTransformOrigin
       
  1422      * @param {Number} rot The rotation (in degrees) of the label.
       
  1423      * @return Array
       
  1424      * @protected
       
  1425      */
       
  1426     _getTransformOrigin: function(rot)
       
  1427     {
       
  1428         var transformOrigin;
       
  1429         if(rot === 0)
       
  1430         {
       
  1431             transformOrigin = [0, 0];
       
  1432         }
       
  1433         else
       
  1434         {
       
  1435             if(rot === 90)
       
  1436             {
       
  1437                 transformOrigin = [1, 0.5];
       
  1438             }
       
  1439             else if (rot === -90)
       
  1440             {
       
  1441                 transformOrigin = [0, 0.5];
       
  1442             }
       
  1443             else if(rot > 0)
       
  1444             {
       
  1445                 transformOrigin = [1, 0.5];
       
  1446             }
       
  1447             else
       
  1448             {
       
  1449                 transformOrigin = [0, 0.5];
       
  1450             }
       
  1451         }
       
  1452         return transformOrigin;
       
  1453     },
       
  1454 
       
  1455     /**
       
  1456      * Adjusts position for inner ticks.
       
  1457      *
       
  1458      * @method offsetNodeForTick
       
  1459      * @param {Node} cb contentBox of the axis
       
  1460      * @protected
       
  1461      */
       
  1462     offsetNodeForTick: function()
       
  1463     {
       
  1464     },
       
  1465 
       
  1466     /**
       
  1467      * Assigns a height based on the size of the contents.
       
  1468      *
       
  1469      * @method setCalculatedSize
       
  1470      * @protected
       
  1471      */
       
  1472     setCalculatedSize: function()
       
  1473     {
       
  1474         var host = this,
       
  1475             graphic = host.get("graphic"),
       
  1476             styles = host.get("styles"),
       
  1477             labelMargin = styles.label.margin,
       
  1478             totalLabelSize = labelMargin.bottom + host._maxLabelSize,
       
  1479             totalTitleSize = host._totalTitleSize,
       
  1480             topTickOffset = this.get("topTickOffset"),
       
  1481             ttl = Math.round(topTickOffset + totalLabelSize + totalTitleSize);
       
  1482         if(this._explicitHeight)
       
  1483         {
       
  1484            ttl = this._explicitHeight;
       
  1485         }
       
  1486         host.set("calculatedHeight", ttl);
       
  1487         graphic.set("y", ttl - topTickOffset);
       
  1488     }
       
  1489 };
       
  1490 Y.TopAxisLayout = TopAxisLayout;
       
  1491 
       
  1492 /**
       
  1493  * An abstract class that provides the core functionality for draw a chart axis. Axis is used by the following classes:
       
  1494  * <ul>
       
  1495  *      <li>{{#crossLink "CategoryAxis"}}{{/crossLink}}</li>
       
  1496  *      <li>{{#crossLink "NumericAxis"}}{{/crossLink}}</li>
       
  1497  *      <li>{{#crossLink "StackedAxis"}}{{/crossLink}}</li>
       
  1498  *      <li>{{#crossLink "TimeAxis"}}{{/crossLink}}</li>
       
  1499  *  </ul>
       
  1500  *
       
  1501  * @class Axis
       
  1502  * @extends Widget
       
  1503  * @uses AxisBase
       
  1504  * @uses TopAxisLayout
       
  1505  * @uses RightAxisLayout
       
  1506  * @uses BottomAxisLayout
       
  1507  * @uses LeftAxisLayout
       
  1508  * @constructor
       
  1509  * @param {Object} config (optional) Configuration parameters.
       
  1510  * @submodule axis
       
  1511  */
       
  1512 Y.Axis = Y.Base.create("axis", Y.Widget, [Y.AxisBase], {
       
  1513     /**
       
  1514      * Calculates and returns a value based on the number of labels and the index of
       
  1515      * the current label.
       
  1516      *
       
  1517      * @method getLabelByIndex
       
  1518      * @param {Number} i Index of the label.
       
  1519      * @param {Number} l Total number of labels.
       
  1520      * @return String
       
  1521      */
       
  1522     getLabelByIndex: function(i, l)
       
  1523     {
       
  1524         var position = this.get("position"),
       
  1525             direction = position === "left" || position === "right" ? "vertical" : "horizontal";
       
  1526         return this._getLabelByIndex(i, l, direction);
       
  1527     },
       
  1528 
       
  1529     /**
       
  1530      * @method bindUI
       
  1531      * @private
       
  1532      */
       
  1533     bindUI: function()
       
  1534     {
       
  1535         this.after("dataReady", Y.bind(this._dataChangeHandler, this));
       
  1536         this.after("dataUpdate", Y.bind(this._dataChangeHandler, this));
       
  1537         this.after("stylesChange", this._updateHandler);
       
  1538         this.after("overlapGraphChange", this._updateHandler);
       
  1539         this.after("positionChange", this._positionChangeHandler);
       
  1540         this.after("widthChange", this._handleSizeChange);
       
  1541         this.after("heightChange", this._handleSizeChange);
       
  1542         this.after("calculatedWidthChange", this._handleSizeChange);
       
  1543         this.after("calculatedHeightChange", this._handleSizeChange);
       
  1544     },
       
  1545     /**
       
  1546      * Storage for calculatedWidth value.
       
  1547      *
       
  1548      * @property _calculatedWidth
       
  1549      * @type Number
       
  1550      * @private
       
  1551      */
       
  1552     _calculatedWidth: 0,
       
  1553 
       
  1554     /**
       
  1555      * Storage for calculatedHeight value.
       
  1556      *
       
  1557      * @property _calculatedHeight
       
  1558      * @type Number
       
  1559      * @private
       
  1560      */
       
  1561     _calculatedHeight: 0,
       
  1562 
       
  1563     /**
       
  1564      * Handles change to the dataProvider
       
  1565      *
       
  1566      * @method _dataChangeHandler
       
  1567      * @param {Object} e Event object
       
  1568      * @private
       
  1569      */
       
  1570     _dataChangeHandler: function()
       
  1571     {
       
  1572         if(this.get("rendered"))
       
  1573         {
       
  1574             this._drawAxis();
       
  1575         }
       
  1576     },
       
  1577 
       
  1578     /**
       
  1579      * Handles change to the position attribute
       
  1580      *
       
  1581      * @method _positionChangeHandler
       
  1582      * @param {Object} e Event object
       
  1583      * @private
       
  1584      */
       
  1585     _positionChangeHandler: function(e)
       
  1586     {
       
  1587         this._updateGraphic(e.newVal);
       
  1588         this._updateHandler();
       
  1589     },
       
  1590 
       
  1591     /**
       
  1592      * Updates the the Graphic instance
       
  1593      *
       
  1594      * @method _updateGraphic
       
  1595      * @param {String} position Position of axis
       
  1596      * @private
       
  1597      */
       
  1598     _updateGraphic: function(position)
       
  1599     {
       
  1600         var graphic = this.get("graphic");
       
  1601         if(position === "none")
       
  1602         {
       
  1603             if(graphic)
       
  1604             {
       
  1605                 graphic.destroy();
       
  1606             }
       
  1607         }
       
  1608         else
       
  1609         {
       
  1610             if(!graphic)
       
  1611             {
       
  1612                 this._setCanvas();
       
  1613             }
       
  1614         }
       
  1615     },
       
  1616 
       
  1617     /**
       
  1618      * Handles changes to axis.
       
  1619      *
       
  1620      * @method _updateHandler
       
  1621      * @param {Object} e Event object
       
  1622      * @private
       
  1623      */
       
  1624     _updateHandler: function()
       
  1625     {
       
  1626         if(this.get("rendered"))
       
  1627         {
       
  1628             this._drawAxis();
       
  1629         }
       
  1630     },
       
  1631 
       
  1632     /**
       
  1633      * @method renderUI
       
  1634      * @private
       
  1635      */
       
  1636     renderUI: function()
       
  1637     {
       
  1638         this._updateGraphic(this.get("position"));
       
  1639     },
       
  1640 
       
  1641     /**
       
  1642      * @method syncUI
       
  1643      * @private
       
  1644      */
       
  1645     syncUI: function()
       
  1646     {
       
  1647         var layout = this._layout,
       
  1648             defaultMargins,
       
  1649             styles,
       
  1650             label,
       
  1651             title,
       
  1652             i;
       
  1653         if(layout)
       
  1654         {
       
  1655             defaultMargins = layout._getDefaultMargins();
       
  1656             styles = this.get("styles");
       
  1657             label = styles.label.margin;
       
  1658             title =styles.title.margin;
       
  1659             //need to defaultMargins method to the layout classes.
       
  1660             for(i in defaultMargins)
       
  1661             {
       
  1662                 if(defaultMargins.hasOwnProperty(i))
       
  1663                 {
       
  1664                     label[i] = label[i] === undefined ? defaultMargins[i] : label[i];
       
  1665                     title[i] = title[i] === undefined ? defaultMargins[i] : title[i];
       
  1666                 }
       
  1667             }
       
  1668         }
       
  1669         this._drawAxis();
       
  1670     },
       
  1671 
       
  1672     /**
       
  1673      * Creates a graphic instance to be used for the axis line and ticks.
       
  1674      *
       
  1675      * @method _setCanvas
       
  1676      * @private
       
  1677      */
       
  1678     _setCanvas: function()
       
  1679     {
       
  1680         var cb = this.get("contentBox"),
       
  1681             bb = this.get("boundingBox"),
       
  1682             p = this.get("position"),
       
  1683             pn = this._parentNode,
       
  1684             w = this.get("width"),
       
  1685             h = this.get("height");
       
  1686         bb.setStyle("position", "absolute");
       
  1687         bb.setStyle("zIndex", 2);
       
  1688         w = w ? w + "px" : pn.getStyle("width");
       
  1689         h = h ? h + "px" : pn.getStyle("height");
       
  1690         if(p === "top" || p === "bottom")
       
  1691         {
       
  1692             cb.setStyle("width", w);
       
  1693         }
       
  1694         else
       
  1695         {
       
  1696             cb.setStyle("height", h);
       
  1697         }
       
  1698         cb.setStyle("position", "relative");
       
  1699         cb.setStyle("left", "0px");
       
  1700         cb.setStyle("top", "0px");
       
  1701         this.set("graphic", new Y.Graphic());
       
  1702         this.get("graphic").render(cb);
       
  1703     },
       
  1704 
       
  1705     /**
       
  1706      * Gets the default value for the `styles` attribute. Overrides
       
  1707      * base implementation.
       
  1708      *
       
  1709      * @method _getDefaultStyles
       
  1710      * @return Object
       
  1711      * @protected
       
  1712      */
       
  1713     _getDefaultStyles: function()
       
  1714     {
       
  1715         var axisstyles = {
       
  1716             majorTicks: {
       
  1717                 display:"inside",
       
  1718                 length:4,
       
  1719                 color:"#dad8c9",
       
  1720                 weight:1,
       
  1721                 alpha:1
       
  1722             },
       
  1723             minorTicks: {
       
  1724                 display:"none",
       
  1725                 length:2,
       
  1726                 color:"#dad8c9",
       
  1727                 weight:1
       
  1728             },
       
  1729             line: {
       
  1730                 weight:1,
       
  1731                 color:"#dad8c9",
       
  1732                 alpha:1
       
  1733             },
       
  1734             majorUnit: {
       
  1735                 determinant:"count",
       
  1736                 count:11,
       
  1737                 distance:75
       
  1738             },
       
  1739             top: "0px",
       
  1740             left: "0px",
       
  1741             width: "100px",
       
  1742             height: "100px",
       
  1743             label: {
       
  1744                 color:"#808080",
       
  1745                 alpha: 1,
       
  1746                 fontSize:"85%",
       
  1747                 rotation: 0,
       
  1748                 offset: 0.5,
       
  1749                 margin: {
       
  1750                     top: undefined,
       
  1751                     right: undefined,
       
  1752                     bottom: undefined,
       
  1753                     left: undefined
       
  1754                 }
       
  1755             },
       
  1756             title: {
       
  1757                 color:"#808080",
       
  1758                 alpha: 1,
       
  1759                 fontSize:"85%",
       
  1760                 rotation: undefined,
       
  1761                 margin: {
       
  1762                     top: undefined,
       
  1763                     right: undefined,
       
  1764                     bottom: undefined,
       
  1765                     left: undefined
       
  1766                 }
       
  1767             },
       
  1768             hideOverlappingLabelTicks: false
       
  1769         };
       
  1770 
       
  1771         return Y.merge(Y.Renderer.prototype._getDefaultStyles(), axisstyles);
       
  1772     },
       
  1773 
       
  1774     /**
       
  1775      * Updates the axis when the size changes.
       
  1776      *
       
  1777      * @method _handleSizeChange
       
  1778      * @param {Object} e Event object.
       
  1779      * @private
       
  1780      */
       
  1781     _handleSizeChange: function(e)
       
  1782     {
       
  1783         var attrName = e.attrName,
       
  1784             pos = this.get("position"),
       
  1785             vert = pos === "left" || pos === "right",
       
  1786             cb = this.get("contentBox"),
       
  1787             hor = pos === "bottom" || pos === "top";
       
  1788         cb.setStyle("width", this.get("width"));
       
  1789         cb.setStyle("height", this.get("height"));
       
  1790         if((hor && attrName === "width") || (vert && attrName === "height"))
       
  1791         {
       
  1792             this._drawAxis();
       
  1793         }
       
  1794     },
       
  1795 
       
  1796     /**
       
  1797      * Maps key values to classes containing layout algorithms
       
  1798      *
       
  1799      * @property _layoutClasses
       
  1800      * @type Object
       
  1801      * @private
       
  1802      */
       
  1803     _layoutClasses:
       
  1804     {
       
  1805         top : TopAxisLayout,
       
  1806         bottom: BottomAxisLayout,
       
  1807         left: LeftAxisLayout,
       
  1808         right : RightAxisLayout
       
  1809     },
       
  1810 
       
  1811     /**
       
  1812      * Draws a line segment between 2 points
       
  1813      *
       
  1814      * @method drawLine
       
  1815      * @param {Object} startPoint x and y coordinates for the start point of the line segment
       
  1816      * @param {Object} endPoint x and y coordinates for the for the end point of the line segment
       
  1817      * @param {Object} line styles (weight, color and alpha to be applied to the line segment)
       
  1818      * @private
       
  1819      */
       
  1820     drawLine: function(path, startPoint, endPoint)
       
  1821     {
       
  1822         path.moveTo(startPoint.x, startPoint.y);
       
  1823         path.lineTo(endPoint.x, endPoint.y);
       
  1824     },
       
  1825 
       
  1826     /**
       
  1827      * Generates the properties necessary for rotating and positioning a text field.
       
  1828      *
       
  1829      * @method _getTextRotationProps
       
  1830      * @param {Object} styles properties for the text field
       
  1831      * @return Object
       
  1832      * @private
       
  1833      */
       
  1834     _getTextRotationProps: function(styles)
       
  1835     {
       
  1836         if(styles.rotation === undefined)
       
  1837         {
       
  1838             switch(this.get("position"))
       
  1839             {
       
  1840                 case "left" :
       
  1841                     styles.rotation = -90;
       
  1842                 break;
       
  1843                 case "right" :
       
  1844                     styles.rotation = 90;
       
  1845                 break;
       
  1846                 default :
       
  1847                     styles.rotation = 0;
       
  1848                 break;
       
  1849             }
       
  1850         }
       
  1851         var rot =  Math.min(90, Math.max(-90, styles.rotation)),
       
  1852             absRot = Math.abs(rot),
       
  1853             radCon = Math.PI/180,
       
  1854             sinRadians = parseFloat(parseFloat(Math.sin(absRot * radCon)).toFixed(8)),
       
  1855             cosRadians = parseFloat(parseFloat(Math.cos(absRot * radCon)).toFixed(8));
       
  1856         return {
       
  1857             rot: rot,
       
  1858             absRot: absRot,
       
  1859             radCon: radCon,
       
  1860             sinRadians: sinRadians,
       
  1861             cosRadians: cosRadians,
       
  1862             textAlpha: styles.alpha
       
  1863         };
       
  1864     },
       
  1865 
       
  1866     /**
       
  1867      * Draws an axis.
       
  1868      *
       
  1869      * @method _drawAxis
       
  1870      * @private
       
  1871      */
       
  1872     _drawAxis: function ()
       
  1873     {
       
  1874         if(this._drawing)
       
  1875         {
       
  1876             this._callLater = true;
       
  1877             return;
       
  1878         }
       
  1879         this._drawing = true;
       
  1880         this._callLater = false;
       
  1881         if(this._layout)
       
  1882         {
       
  1883             var styles = this.get("styles"),
       
  1884                 line = styles.line,
       
  1885                 labelStyles = styles.label,
       
  1886                 majorTickStyles = styles.majorTicks,
       
  1887                 drawTicks = majorTickStyles.display !== "none",
       
  1888                 len,
       
  1889                 i = 0,
       
  1890                 layout = this._layout,
       
  1891                 layoutLength,
       
  1892                 lineStart,
       
  1893                 label,
       
  1894                 labelWidth,
       
  1895                 labelHeight,
       
  1896                 labelFunction = this.get("labelFunction"),
       
  1897                 labelFunctionScope = this.get("labelFunctionScope"),
       
  1898                 labelFormat = this.get("labelFormat"),
       
  1899                 graphic = this.get("graphic"),
       
  1900                 path = this.get("path"),
       
  1901                 tickPath,
       
  1902                 explicitlySized,
       
  1903                 position = this.get("position"),
       
  1904                 labelData,
       
  1905                 labelValues,
       
  1906                 point,
       
  1907                 points,
       
  1908                 firstPoint,
       
  1909                 lastPoint,
       
  1910                 firstLabel,
       
  1911                 lastLabel,
       
  1912                 staticCoord,
       
  1913                 dynamicCoord,
       
  1914                 edgeOffset,
       
  1915                 explicitLabels = this._labelValuesExplicitlySet ? this.get("labelValues") : null,
       
  1916                 direction = (position === "left" || position === "right") ? "vertical" : "horizontal";
       
  1917             this._labelWidths = [];
       
  1918             this._labelHeights = [];
       
  1919             graphic.set("autoDraw", false);
       
  1920             path.clear();
       
  1921             path.set("stroke", {
       
  1922                 weight: line.weight,
       
  1923                 color: line.color,
       
  1924                 opacity: line.alpha
       
  1925             });
       
  1926             this._labelRotationProps = this._getTextRotationProps(labelStyles);
       
  1927             this._labelRotationProps.transformOrigin = layout._getTransformOrigin(this._labelRotationProps.rot);
       
  1928             layout.setTickOffsets.apply(this);
       
  1929             layoutLength = this.getLength();
       
  1930 
       
  1931             len = this.getTotalMajorUnits();
       
  1932             edgeOffset = this.getEdgeOffset(len, layoutLength);
       
  1933             this.set("edgeOffset", edgeOffset);
       
  1934             lineStart = layout.getLineStart.apply(this);
       
  1935 
       
  1936             if(direction === "vertical")
       
  1937             {
       
  1938                 staticCoord = "x";
       
  1939                 dynamicCoord = "y";
       
  1940             }
       
  1941             else
       
  1942             {
       
  1943                 staticCoord = "y";
       
  1944                 dynamicCoord = "x";
       
  1945             }
       
  1946 
       
  1947             labelData = this._getLabelData(
       
  1948                 lineStart[staticCoord],
       
  1949                 staticCoord,
       
  1950                 dynamicCoord,
       
  1951                 this.get("minimum"),
       
  1952                 this.get("maximum"),
       
  1953                 edgeOffset,
       
  1954                 layoutLength - edgeOffset - edgeOffset,
       
  1955                 len,
       
  1956                 explicitLabels
       
  1957             );
       
  1958 
       
  1959             points = labelData.points;
       
  1960             labelValues = labelData.values;
       
  1961             len = points.length;
       
  1962             if(!this._labelValuesExplicitlySet)
       
  1963             {
       
  1964                 this.set("labelValues", labelValues, {src: "internal"});
       
  1965             }
       
  1966 
       
  1967             //Don't create the last label or tick.
       
  1968             if(this.get("hideFirstMajorUnit"))
       
  1969             {
       
  1970                 firstPoint = points.shift();
       
  1971                 firstLabel = labelValues.shift();
       
  1972                 len = len - 1;
       
  1973             }
       
  1974 
       
  1975             //Don't create the last label or tick.
       
  1976             if(this.get("hideLastMajorUnit"))
       
  1977             {
       
  1978                 lastPoint = points.pop();
       
  1979                 lastLabel = labelValues.pop();
       
  1980                 len = len - 1;
       
  1981             }
       
  1982 
       
  1983             if(len < 1)
       
  1984             {
       
  1985                 this._clearLabelCache();
       
  1986             }
       
  1987             else
       
  1988             {
       
  1989                 this.drawLine(path, lineStart, this.getLineEnd(lineStart));
       
  1990                 if(drawTicks)
       
  1991                 {
       
  1992                     tickPath = this.get("tickPath");
       
  1993                     tickPath.clear();
       
  1994                     tickPath.set("stroke", {
       
  1995                         weight: majorTickStyles.weight,
       
  1996                         color: majorTickStyles.color,
       
  1997                         opacity: majorTickStyles.alpha
       
  1998                     });
       
  1999                     for(i = 0; i < len; i = i + 1)
       
  2000                     {
       
  2001                         point = points[i];
       
  2002                         if(point)
       
  2003                         {
       
  2004                             layout.drawTick.apply(this, [tickPath, points[i], majorTickStyles]);
       
  2005                         }
       
  2006                     }
       
  2007                 }
       
  2008                 this._createLabelCache();
       
  2009                 this._maxLabelSize = 0;
       
  2010                 this._totalTitleSize = 0;
       
  2011                 this._titleSize = 0;
       
  2012                 this._setTitle();
       
  2013                 explicitlySized = layout.getExplicitlySized.apply(this, [styles]);
       
  2014                 for(i = 0; i < len; i = i + 1)
       
  2015                 {
       
  2016                     point = points[i];
       
  2017                     if(point)
       
  2018                     {
       
  2019                         label = this.getLabel(labelStyles);
       
  2020                         this._labels.push(label);
       
  2021                         this.get("appendLabelFunction")(label, labelFunction.apply(labelFunctionScope, [labelValues[i], labelFormat]));
       
  2022                         labelWidth = Math.round(label.offsetWidth);
       
  2023                         labelHeight = Math.round(label.offsetHeight);
       
  2024                         if(!explicitlySized)
       
  2025                         {
       
  2026                             this._layout.updateMaxLabelSize.apply(this, [labelWidth, labelHeight]);
       
  2027                         }
       
  2028                         this._labelWidths.push(labelWidth);
       
  2029                         this._labelHeights.push(labelHeight);
       
  2030                     }
       
  2031                 }
       
  2032                 this._clearLabelCache();
       
  2033                 if(this.get("overlapGraph"))
       
  2034                 {
       
  2035                    layout.offsetNodeForTick.apply(this, [this.get("contentBox")]);
       
  2036                 }
       
  2037                 layout.setCalculatedSize.apply(this);
       
  2038                 if(this._titleTextField)
       
  2039                 {
       
  2040                     this._layout.positionTitle.apply(this, [this._titleTextField]);
       
  2041                 }
       
  2042                 len = this._labels.length;
       
  2043                 for(i = 0; i < len; ++i)
       
  2044                 {
       
  2045                     layout.positionLabel.apply(this, [this.get("labels")[i], points[i], styles, i]);
       
  2046                 }
       
  2047                 if(firstPoint)
       
  2048                 {
       
  2049                     points.unshift(firstPoint);
       
  2050                 }
       
  2051                 if(lastPoint)
       
  2052                 {
       
  2053                     points.push(lastPoint);
       
  2054                 }
       
  2055                 if(firstLabel)
       
  2056                 {
       
  2057                     labelValues.unshift(firstLabel);
       
  2058                 }
       
  2059                 if(lastLabel)
       
  2060                 {
       
  2061                     labelValues.push(lastLabel);
       
  2062                 }
       
  2063                 this._tickPoints = points;
       
  2064             }
       
  2065         }
       
  2066         this._drawing = false;
       
  2067         if(this._callLater)
       
  2068         {
       
  2069             this._drawAxis();
       
  2070         }
       
  2071         else
       
  2072         {
       
  2073             this._updatePathElement();
       
  2074             this.fire("axisRendered");
       
  2075         }
       
  2076     },
       
  2077 
       
  2078     /**
       
  2079      * Calculates and sets the total size of a title.
       
  2080      *
       
  2081      * @method _setTotalTitleSize
       
  2082      * @param {Object} styles Properties for the title field.
       
  2083      * @private
       
  2084      */
       
  2085     _setTotalTitleSize: function(styles)
       
  2086     {
       
  2087         var title = this._titleTextField,
       
  2088             w = title.offsetWidth,
       
  2089             h = title.offsetHeight,
       
  2090             rot = this._titleRotationProps.rot,
       
  2091             bounds,
       
  2092             size,
       
  2093             margin = styles.margin,
       
  2094             position = this.get("position"),
       
  2095             matrix = new Y.Matrix();
       
  2096         matrix.rotate(rot);
       
  2097         bounds = matrix.getContentRect(w, h);
       
  2098         if(position === "left" || position === "right")
       
  2099         {
       
  2100             size = bounds.right - bounds.left;
       
  2101             if(margin)
       
  2102             {
       
  2103                 size += margin.left + margin.right;
       
  2104             }
       
  2105         }
       
  2106         else
       
  2107         {
       
  2108             size = bounds.bottom - bounds.top;
       
  2109             if(margin)
       
  2110             {
       
  2111                 size += margin.top + margin.bottom;
       
  2112             }
       
  2113         }
       
  2114         this._titleBounds = bounds;
       
  2115         this._totalTitleSize = size;
       
  2116     },
       
  2117 
       
  2118     /**
       
  2119      *  Updates path.
       
  2120      *
       
  2121      *  @method _updatePathElement
       
  2122      *  @private
       
  2123      */
       
  2124     _updatePathElement: function()
       
  2125     {
       
  2126         var path = this._path,
       
  2127             tickPath = this._tickPath,
       
  2128             redrawGraphic = false,
       
  2129             graphic = this.get("graphic");
       
  2130         if(path)
       
  2131         {
       
  2132             redrawGraphic = true;
       
  2133             path.end();
       
  2134         }
       
  2135         if(tickPath)
       
  2136         {
       
  2137             redrawGraphic = true;
       
  2138             tickPath.end();
       
  2139         }
       
  2140         if(redrawGraphic)
       
  2141         {
       
  2142             graphic._redraw();
       
  2143         }
       
  2144     },
       
  2145 
       
  2146     /**
       
  2147      * Updates the content and style properties for a title field.
       
  2148      *
       
  2149      * @method _updateTitle
       
  2150      * @private
       
  2151      */
       
  2152     _setTitle: function()
       
  2153     {
       
  2154         var i,
       
  2155             styles,
       
  2156             customStyles,
       
  2157             title = this.get("title"),
       
  2158             titleTextField = this._titleTextField,
       
  2159             parentNode;
       
  2160         if(title !== null && title !== undefined)
       
  2161         {
       
  2162             customStyles = {
       
  2163                     rotation: "rotation",
       
  2164                     margin: "margin",
       
  2165                     alpha: "alpha"
       
  2166             };
       
  2167             styles = this.get("styles").title;
       
  2168             if(!titleTextField)
       
  2169             {
       
  2170                 titleTextField = DOCUMENT.createElement('span');
       
  2171                 titleTextField.style.display = "block";
       
  2172                 titleTextField.style.whiteSpace = "nowrap";
       
  2173                 titleTextField.setAttribute("class", "axisTitle");
       
  2174                 this.get("contentBox").append(titleTextField);
       
  2175             }
       
  2176             else if(!DOCUMENT.createElementNS)
       
  2177             {
       
  2178                 if(titleTextField.style.filter)
       
  2179                 {
       
  2180                     titleTextField.style.filter = null;
       
  2181                 }
       
  2182             }
       
  2183             titleTextField.style.position = "absolute";
       
  2184             for(i in styles)
       
  2185             {
       
  2186                 if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
       
  2187                 {
       
  2188                     titleTextField.style[i] = styles[i];
       
  2189                 }
       
  2190             }
       
  2191             this.get("appendTitleFunction")(titleTextField, title);
       
  2192             this._titleTextField = titleTextField;
       
  2193             this._titleRotationProps = this._getTextRotationProps(styles);
       
  2194             this._setTotalTitleSize(styles);
       
  2195         }
       
  2196         else if(titleTextField)
       
  2197         {
       
  2198             parentNode = titleTextField.parentNode;
       
  2199             if(parentNode)
       
  2200             {
       
  2201                 parentNode.removeChild(titleTextField);
       
  2202             }
       
  2203             this._titleTextField = null;
       
  2204             this._totalTitleSize = 0;
       
  2205         }
       
  2206     },
       
  2207 
       
  2208     /**
       
  2209      * Creates or updates an axis label.
       
  2210      *
       
  2211      * @method getLabel
       
  2212      * @param {Object} styles styles applied to label
       
  2213      * @return HTMLElement
       
  2214      * @private
       
  2215      */
       
  2216     getLabel: function(styles)
       
  2217     {
       
  2218         var i,
       
  2219             label,
       
  2220             labelCache = this._labelCache,
       
  2221             customStyles = {
       
  2222                 rotation: "rotation",
       
  2223                 margin: "margin",
       
  2224                 alpha: "alpha"
       
  2225             };
       
  2226         if(labelCache && labelCache.length > 0)
       
  2227         {
       
  2228             label = labelCache.shift();
       
  2229         }
       
  2230         else
       
  2231         {
       
  2232             label = DOCUMENT.createElement("span");
       
  2233             label.className = Y.Lang.trim([label.className, "axisLabel"].join(' '));
       
  2234             this.get("contentBox").append(label);
       
  2235         }
       
  2236         if(!DOCUMENT.createElementNS)
       
  2237         {
       
  2238             if(label.style.filter)
       
  2239             {
       
  2240                 label.style.filter = null;
       
  2241             }
       
  2242         }
       
  2243         label.style.display = "block";
       
  2244         label.style.whiteSpace = "nowrap";
       
  2245         label.style.position = "absolute";
       
  2246         for(i in styles)
       
  2247         {
       
  2248             if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
       
  2249             {
       
  2250                 label.style[i] = styles[i];
       
  2251             }
       
  2252         }
       
  2253         return label;
       
  2254     },
       
  2255 
       
  2256     /**
       
  2257      * Creates a cache of labels that can be re-used when the axis redraws.
       
  2258      *
       
  2259      * @method _createLabelCache
       
  2260      * @private
       
  2261      */
       
  2262     _createLabelCache: function()
       
  2263     {
       
  2264         if(this._labels)
       
  2265         {
       
  2266             while(this._labels.length > 0)
       
  2267             {
       
  2268                 this._labelCache.push(this._labels.shift());
       
  2269             }
       
  2270         }
       
  2271         else
       
  2272         {
       
  2273             this._clearLabelCache();
       
  2274         }
       
  2275         this._labels = [];
       
  2276     },
       
  2277 
       
  2278     /**
       
  2279      * Removes axis labels from the dom and clears the label cache.
       
  2280      *
       
  2281      * @method _clearLabelCache
       
  2282      * @private
       
  2283      */
       
  2284     _clearLabelCache: function()
       
  2285     {
       
  2286         if(this._labelCache)
       
  2287         {
       
  2288             var len = this._labelCache.length,
       
  2289                 i = 0,
       
  2290                 label;
       
  2291             for(; i < len; ++i)
       
  2292             {
       
  2293                 label = this._labelCache[i];
       
  2294                 this._removeChildren(label);
       
  2295                 Y.Event.purgeElement(label, true);
       
  2296                 label.parentNode.removeChild(label);
       
  2297             }
       
  2298         }
       
  2299         this._labelCache = [];
       
  2300     },
       
  2301 
       
  2302     /**
       
  2303      * Gets the end point of an axis.
       
  2304      *
       
  2305      * @method getLineEnd
       
  2306      * @return Object
       
  2307      * @private
       
  2308      */
       
  2309     getLineEnd: function(pt)
       
  2310     {
       
  2311         var w = this.get("width"),
       
  2312             h = this.get("height"),
       
  2313             pos = this.get("position");
       
  2314         if(pos === "top" || pos === "bottom")
       
  2315         {
       
  2316             return {x:w, y:pt.y};
       
  2317         }
       
  2318         else
       
  2319         {
       
  2320             return {x:pt.x, y:h};
       
  2321         }
       
  2322     },
       
  2323 
       
  2324     /**
       
  2325      * Calcuates the width or height of an axis depending on its direction.
       
  2326      *
       
  2327      * @method getLength
       
  2328      * @return Number
       
  2329      * @private
       
  2330      */
       
  2331     getLength: function()
       
  2332     {
       
  2333         var l,
       
  2334             style = this.get("styles"),
       
  2335             padding = style.padding,
       
  2336             w = this.get("width"),
       
  2337             h = this.get("height"),
       
  2338             pos = this.get("position");
       
  2339         if(pos === "top" || pos === "bottom")
       
  2340         {
       
  2341             l = w - (padding.left + padding.right);
       
  2342         }
       
  2343         else
       
  2344         {
       
  2345             l = h - (padding.top + padding.bottom);
       
  2346         }
       
  2347         return l;
       
  2348     },
       
  2349 
       
  2350     /**
       
  2351      * Gets the position of the first point on an axis.
       
  2352      *
       
  2353      * @method getFirstPoint
       
  2354      * @param {Object} pt Object containing x and y coordinates.
       
  2355      * @return Object
       
  2356      * @private
       
  2357      */
       
  2358     getFirstPoint:function(pt)
       
  2359     {
       
  2360         var style = this.get("styles"),
       
  2361             pos = this.get("position"),
       
  2362             padding = style.padding,
       
  2363             np = {x:pt.x, y:pt.y};
       
  2364         if(pos === "top" || pos === "bottom")
       
  2365         {
       
  2366             np.x += padding.left + this.get("edgeOffset");
       
  2367         }
       
  2368         else
       
  2369         {
       
  2370             np.y += this.get("height") - (padding.top + this.get("edgeOffset"));
       
  2371         }
       
  2372         return np;
       
  2373     },
       
  2374 
       
  2375     /**
       
  2376      * Rotates and positions a text field.
       
  2377      *
       
  2378      * @method _rotate
       
  2379      * @param {HTMLElement} label text field to rotate and position
       
  2380      * @param {Object} props properties to be applied to the text field.
       
  2381      * @private
       
  2382      */
       
  2383     _rotate: function(label, props)
       
  2384     {
       
  2385         var rot = props.rot,
       
  2386             x = props.x,
       
  2387             y = props.y,
       
  2388             filterString,
       
  2389             textAlpha,
       
  2390             matrix = new Y.Matrix(),
       
  2391             transformOrigin = props.transformOrigin || [0, 0],
       
  2392             offsetRect;
       
  2393         if(DOCUMENT.createElementNS)
       
  2394         {
       
  2395             matrix.translate(x, y);
       
  2396             matrix.rotate(rot);
       
  2397             Y_DOM.setStyle(label, "transformOrigin", (transformOrigin[0] * 100) + "% " + (transformOrigin[1] * 100) + "%");
       
  2398             Y_DOM.setStyle(label, "transform", matrix.toCSSText());
       
  2399         }
       
  2400         else
       
  2401         {
       
  2402             textAlpha = props.textAlpha;
       
  2403             if(Y_Lang.isNumber(textAlpha) && textAlpha < 1 && textAlpha > -1 && !isNaN(textAlpha))
       
  2404             {
       
  2405                 filterString = "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + Math.round(textAlpha * 100) + ")";
       
  2406             }
       
  2407             if(rot !== 0)
       
  2408             {
       
  2409                 //ms filters kind of, sort of uses a transformOrigin of 0, 0.
       
  2410                 //we'll translate the difference to create a true 0, 0 origin.
       
  2411                 matrix.rotate(rot);
       
  2412                 offsetRect = matrix.getContentRect(props.labelWidth, props.labelHeight);
       
  2413                 matrix.init();
       
  2414                 matrix.translate(offsetRect.left, offsetRect.top);
       
  2415                 matrix.translate(x, y);
       
  2416                 this._simulateRotateWithTransformOrigin(matrix, rot, transformOrigin, props.labelWidth, props.labelHeight);
       
  2417                 if(filterString)
       
  2418                 {
       
  2419                     filterString += " ";
       
  2420                 }
       
  2421                 else
       
  2422                 {
       
  2423                     filterString = "";
       
  2424                 }
       
  2425                 filterString += matrix.toFilterText();
       
  2426                 label.style.left = matrix.dx + "px";
       
  2427                 label.style.top = matrix.dy + "px";
       
  2428             }
       
  2429             else
       
  2430             {
       
  2431                 label.style.left = x + "px";
       
  2432                 label.style.top = y + "px";
       
  2433             }
       
  2434             if(filterString)
       
  2435             {
       
  2436                 label.style.filter = filterString;
       
  2437             }
       
  2438         }
       
  2439     },
       
  2440 
       
  2441     /**
       
  2442      * Simulates a rotation with a specified transformOrigin.
       
  2443      *
       
  2444      * @method _simulateTransformOrigin
       
  2445      * @param {Matrix} matrix Reference to a `Matrix` instance.
       
  2446      * @param {Number} rot The rotation (in degrees) that will be performed on a matrix.
       
  2447      * @param {Array} transformOrigin An array represeniting the origin in which to perform the transform. The first
       
  2448      * index represents the x origin and the second index represents the y origin.
       
  2449      * @param {Number} w The width of the object that will be transformed.
       
  2450      * @param {Number} h The height of the object that will be transformed.
       
  2451      * @private
       
  2452      */
       
  2453     _simulateRotateWithTransformOrigin: function(matrix, rot, transformOrigin, w, h)
       
  2454     {
       
  2455         var transformX = transformOrigin[0] * w,
       
  2456             transformY = transformOrigin[1] * h;
       
  2457         transformX = !isNaN(transformX) ? transformX : 0;
       
  2458         transformY = !isNaN(transformY) ? transformY : 0;
       
  2459         matrix.translate(transformX, transformY);
       
  2460         matrix.rotate(rot);
       
  2461         matrix.translate(-transformX, -transformY);
       
  2462     },
       
  2463 
       
  2464     /**
       
  2465      * Returns the coordinates (top, right, bottom, left) for the bounding box of the last label.
       
  2466      *
       
  2467      * @method getMaxLabelBounds
       
  2468      * @return Object
       
  2469      */
       
  2470     getMaxLabelBounds: function()
       
  2471     {
       
  2472         return this._getLabelBounds(this.getMaximumValue());
       
  2473     },
       
  2474 
       
  2475     /**
       
  2476      * Returns the coordinates (top, right, bottom, left) for the bounding box of the first label.
       
  2477      *
       
  2478      * @method getMinLabelBounds
       
  2479      * @return Object
       
  2480      */
       
  2481     getMinLabelBounds: function()
       
  2482     {
       
  2483         return this._getLabelBounds(this.getMinimumValue());
       
  2484     },
       
  2485 
       
  2486     /**
       
  2487      * Returns the coordinates (top, right, bottom, left) for the bounding box of a label.
       
  2488      *
       
  2489      * @method _getLabelBounds
       
  2490      * @param {String} Value of the label
       
  2491      * @return Object
       
  2492      * @private
       
  2493      */
       
  2494     _getLabelBounds: function(val)
       
  2495     {
       
  2496         var layout = this._layout,
       
  2497             labelStyles = this.get("styles").label,
       
  2498             matrix = new Y.Matrix(),
       
  2499             label,
       
  2500             props = this._getTextRotationProps(labelStyles);
       
  2501             props.transformOrigin = layout._getTransformOrigin(props.rot);
       
  2502         label = this.getLabel(labelStyles);
       
  2503         this.get("appendLabelFunction")(label, this.get("labelFunction").apply(this, [val, this.get("labelFormat")]));
       
  2504         props.labelWidth = label.offsetWidth;
       
  2505         props.labelHeight = label.offsetHeight;
       
  2506         this._removeChildren(label);
       
  2507         Y.Event.purgeElement(label, true);
       
  2508         label.parentNode.removeChild(label);
       
  2509         props.x = 0;
       
  2510         props.y = 0;
       
  2511         layout._setRotationCoords(props);
       
  2512         matrix.translate(props.x, props.y);
       
  2513         this._simulateRotateWithTransformOrigin(matrix, props.rot, props.transformOrigin, props.labelWidth, props.labelHeight);
       
  2514         return matrix.getContentRect(props.labelWidth, props.labelHeight);
       
  2515     },
       
  2516 
       
  2517     /**
       
  2518      * Removes all DOM elements from an HTML element. Used to clear out labels during detruction
       
  2519      * phase.
       
  2520      *
       
  2521      * @method _removeChildren
       
  2522      * @private
       
  2523      */
       
  2524     _removeChildren: function(node)
       
  2525     {
       
  2526         if(node.hasChildNodes())
       
  2527         {
       
  2528             var child;
       
  2529             while(node.firstChild)
       
  2530             {
       
  2531                 child = node.firstChild;
       
  2532                 this._removeChildren(child);
       
  2533                 node.removeChild(child);
       
  2534             }
       
  2535         }
       
  2536     },
       
  2537 
       
  2538     /**
       
  2539      * Destructor implementation Axis class. Removes all labels and the Graphic instance from the widget.
       
  2540      *
       
  2541      * @method destructor
       
  2542      * @protected
       
  2543      */
       
  2544     destructor: function()
       
  2545     {
       
  2546         var cb = this.get("contentBox").getDOMNode(),
       
  2547             labels = this.get("labels"),
       
  2548             graphic = this.get("graphic"),
       
  2549             label,
       
  2550             len = labels ? labels.length : 0;
       
  2551         if(len > 0)
       
  2552         {
       
  2553             while(labels.length > 0)
       
  2554             {
       
  2555                 label = labels.shift();
       
  2556                 this._removeChildren(label);
       
  2557                 cb.removeChild(label);
       
  2558                 label = null;
       
  2559             }
       
  2560         }
       
  2561         if(graphic)
       
  2562         {
       
  2563             graphic.destroy();
       
  2564         }
       
  2565     },
       
  2566 
       
  2567     /**
       
  2568      * Length in pixels of largest text bounding box. Used to calculate the height of the axis.
       
  2569      *
       
  2570      * @property maxLabelSize
       
  2571      * @type Number
       
  2572      * @protected
       
  2573      */
       
  2574     _maxLabelSize: 0,
       
  2575 
       
  2576     /**
       
  2577      * Updates the content of text field. This method writes a value into a text field using
       
  2578      * `appendChild`. If the value is a `String`, it is converted to a `TextNode` first.
       
  2579      *
       
  2580      * @method _setText
       
  2581      * @param label {HTMLElement} label to be updated
       
  2582      * @param val {String} value with which to update the label
       
  2583      * @private
       
  2584      */
       
  2585     _setText: function(textField, val)
       
  2586     {
       
  2587         textField.innerHTML = "";
       
  2588         if(Y_Lang.isNumber(val))
       
  2589         {
       
  2590             val = val + "";
       
  2591         }
       
  2592         else if(!val)
       
  2593         {
       
  2594             val = "";
       
  2595         }
       
  2596         if(IS_STRING(val))
       
  2597         {
       
  2598             val = DOCUMENT.createTextNode(val);
       
  2599         }
       
  2600         textField.appendChild(val);
       
  2601     },
       
  2602 
       
  2603     /**
       
  2604      * Returns the total number of majorUnits that will appear on an axis.
       
  2605      *
       
  2606      * @method getTotalMajorUnits
       
  2607      * @return Number
       
  2608      */
       
  2609     getTotalMajorUnits: function()
       
  2610     {
       
  2611         var units,
       
  2612             majorUnit = this.get("styles").majorUnit,
       
  2613             len;
       
  2614         if(majorUnit.determinant === "count")
       
  2615         {
       
  2616             units = majorUnit.count;
       
  2617         }
       
  2618         else if(majorUnit.determinant === "distance")
       
  2619         {
       
  2620             len = this.getLength();
       
  2621             units = (len/majorUnit.distance) + 1;
       
  2622         }
       
  2623         return units;
       
  2624     },
       
  2625 
       
  2626     /**
       
  2627      * Returns the distance between major units on an axis.
       
  2628      *
       
  2629      * @method getMajorUnitDistance
       
  2630      * @param {Number} len Number of ticks
       
  2631      * @param {Number} uiLen Size of the axis.
       
  2632      * @param {Object} majorUnit Hash of properties used to determine the majorUnit
       
  2633      * @return Number
       
  2634      */
       
  2635     getMajorUnitDistance: function(len, uiLen, majorUnit)
       
  2636     {
       
  2637         var dist;
       
  2638         if(majorUnit.determinant === "count")
       
  2639         {
       
  2640             if(!this.get("calculateEdgeOffset"))
       
  2641             {
       
  2642                 len = len - 1;
       
  2643             }
       
  2644             dist = uiLen/len;
       
  2645         }
       
  2646         else if(majorUnit.determinant === "distance")
       
  2647         {
       
  2648             dist = majorUnit.distance;
       
  2649         }
       
  2650         return dist;
       
  2651     },
       
  2652 
       
  2653     /**
       
  2654      * Checks to see if data extends beyond the range of the axis. If so,
       
  2655      * that data will need to be hidden. This method is internal, temporary and subject
       
  2656      * to removal in the future.
       
  2657      *
       
  2658      * @method _hasDataOverflow
       
  2659      * @protected
       
  2660      * @return Boolean
       
  2661      */
       
  2662     _hasDataOverflow: function()
       
  2663     {
       
  2664         if(this.get("setMin") || this.get("setMax"))
       
  2665         {
       
  2666             return true;
       
  2667         }
       
  2668         return false;
       
  2669     },
       
  2670 
       
  2671     /**
       
  2672      * Returns a string corresponding to the first label on an
       
  2673      * axis.
       
  2674      *
       
  2675      * @method getMinimumValue
       
  2676      * @return String
       
  2677      */
       
  2678     getMinimumValue: function()
       
  2679     {
       
  2680         return this.get("minimum");
       
  2681     },
       
  2682 
       
  2683     /**
       
  2684      * Returns a string corresponding to the last label on an
       
  2685      * axis.
       
  2686      *
       
  2687      * @method getMaximumValue
       
  2688      * @return String
       
  2689      */
       
  2690     getMaximumValue: function()
       
  2691     {
       
  2692         return this.get("maximum");
       
  2693     }
       
  2694 }, {
       
  2695     ATTRS:
       
  2696     {
       
  2697         /**
       
  2698          * When set, defines the width of a vertical axis instance. By default, vertical axes automatically size based
       
  2699          * on their contents. When the width attribute is set, the axis will not calculate its width. When the width
       
  2700          * attribute is explicitly set, axis labels will postion themselves off of the the inner edge of the axis and the
       
  2701          * title, if present, will position itself off of the outer edge. If a specified width is less than the sum of
       
  2702          * the axis' contents, excess content will overflow.
       
  2703          *
       
  2704          * @attribute width
       
  2705          * @type Number
       
  2706          */
       
  2707         width: {
       
  2708             lazyAdd: false,
       
  2709 
       
  2710             getter: function()
       
  2711             {
       
  2712                 if(this._explicitWidth)
       
  2713                 {
       
  2714                     return this._explicitWidth;
       
  2715                 }
       
  2716                 return this._calculatedWidth;
       
  2717             },
       
  2718 
       
  2719             setter: function(val)
       
  2720             {
       
  2721                 this._explicitWidth = val;
       
  2722                 return val;
       
  2723             }
       
  2724         },
       
  2725 
       
  2726         /**
       
  2727          * When set, defines the height of a horizontal axis instance. By default, horizontal axes automatically size based
       
  2728          * on their contents. When the height attribute is set, the axis will not calculate its height. When the height
       
  2729          * attribute is explicitly set, axis labels will postion themselves off of the the inner edge of the axis and the
       
  2730          * title, if present, will position itself off of the outer edge. If a specified height is less than the sum of
       
  2731          * the axis' contents, excess content will overflow.
       
  2732          *
       
  2733          * @attribute height
       
  2734          * @type Number
       
  2735          */
       
  2736         height: {
       
  2737             lazyAdd: false,
       
  2738 
       
  2739             getter: function()
       
  2740             {
       
  2741                 if(this._explicitHeight)
       
  2742                 {
       
  2743                     return this._explicitHeight;
       
  2744                 }
       
  2745                 return this._calculatedHeight;
       
  2746             },
       
  2747 
       
  2748             setter: function(val)
       
  2749             {
       
  2750                 this._explicitHeight = val;
       
  2751                 return val;
       
  2752             }
       
  2753         },
       
  2754 
       
  2755         /**
       
  2756          * Calculated value of an axis' width. By default, the value is used internally for vertical axes. If the `width`
       
  2757          * attribute is explicitly set, this value will be ignored.
       
  2758          *
       
  2759          * @attribute calculatedWidth
       
  2760          * @type Number
       
  2761          * @private
       
  2762          */
       
  2763         calculatedWidth: {
       
  2764             getter: function()
       
  2765             {
       
  2766                 return this._calculatedWidth;
       
  2767             },
       
  2768 
       
  2769             setter: function(val)
       
  2770             {
       
  2771                 this._calculatedWidth = val;
       
  2772                 return val;
       
  2773             }
       
  2774         },
       
  2775 
       
  2776         /**
       
  2777          * Calculated value of an axis' height. By default, the value is used internally for horizontal axes. If the `height`
       
  2778          * attribute is explicitly set, this value will be ignored.
       
  2779          *
       
  2780          * @attribute calculatedHeight
       
  2781          * @type Number
       
  2782          * @private
       
  2783          */
       
  2784         calculatedHeight: {
       
  2785             getter: function()
       
  2786             {
       
  2787                 return this._calculatedHeight;
       
  2788             },
       
  2789 
       
  2790             setter: function(val)
       
  2791             {
       
  2792                 this._calculatedHeight = val;
       
  2793                 return val;
       
  2794             }
       
  2795         },
       
  2796 
       
  2797         /**
       
  2798          * Difference between the first/last tick and edge of axis.
       
  2799          *
       
  2800          * @attribute edgeOffset
       
  2801          * @type Number
       
  2802          * @protected
       
  2803          */
       
  2804         edgeOffset:
       
  2805         {
       
  2806             value: 0
       
  2807         },
       
  2808 
       
  2809         /**
       
  2810          * The graphic in which the axis line and ticks will be rendered.
       
  2811          *
       
  2812          * @attribute graphic
       
  2813          * @type Graphic
       
  2814          */
       
  2815         graphic: {},
       
  2816 
       
  2817         /**
       
  2818          *  @attribute path
       
  2819          *  @type Shape
       
  2820          *  @readOnly
       
  2821          *  @private
       
  2822          */
       
  2823         path: {
       
  2824             readOnly: true,
       
  2825 
       
  2826             getter: function()
       
  2827             {
       
  2828                 if(!this._path)
       
  2829                 {
       
  2830                     var graphic = this.get("graphic");
       
  2831                     if(graphic)
       
  2832                     {
       
  2833                         this._path = graphic.addShape({type:"path"});
       
  2834                     }
       
  2835                 }
       
  2836                 return this._path;
       
  2837             }
       
  2838         },
       
  2839 
       
  2840         /**
       
  2841          *  @attribute tickPath
       
  2842          *  @type Shape
       
  2843          *  @readOnly
       
  2844          *  @private
       
  2845          */
       
  2846         tickPath: {
       
  2847             readOnly: true,
       
  2848 
       
  2849             getter: function()
       
  2850             {
       
  2851                 if(!this._tickPath)
       
  2852                 {
       
  2853                     var graphic = this.get("graphic");
       
  2854                     if(graphic)
       
  2855                     {
       
  2856                         this._tickPath = graphic.addShape({type:"path"});
       
  2857                     }
       
  2858                 }
       
  2859                 return this._tickPath;
       
  2860             }
       
  2861         },
       
  2862 
       
  2863         /**
       
  2864          * Contains the contents of the axis.
       
  2865          *
       
  2866          * @attribute node
       
  2867          * @type HTMLElement
       
  2868          */
       
  2869         node: {},
       
  2870 
       
  2871         /**
       
  2872          * Direction of the axis.
       
  2873          *
       
  2874          * @attribute position
       
  2875          * @type String
       
  2876          */
       
  2877         position: {
       
  2878             lazyAdd: false,
       
  2879 
       
  2880             setter: function(val)
       
  2881             {
       
  2882                 var LayoutClass = this._layoutClasses[val];
       
  2883                 if(val && val !== "none")
       
  2884                 {
       
  2885                     this._layout = new LayoutClass();
       
  2886                 }
       
  2887                 return val;
       
  2888             }
       
  2889         },
       
  2890 
       
  2891         /**
       
  2892          * Distance determined by the tick styles used to calculate the distance between the axis
       
  2893          * line in relation to the top of the axis.
       
  2894          *
       
  2895          * @attribute topTickOffset
       
  2896          * @type Number
       
  2897          */
       
  2898         topTickOffset: {
       
  2899             value: 0
       
  2900         },
       
  2901 
       
  2902         /**
       
  2903          * Distance determined by the tick styles used to calculate the distance between the axis
       
  2904          * line in relation to the bottom of the axis.
       
  2905          *
       
  2906          * @attribute bottomTickOffset
       
  2907          * @type Number
       
  2908          */
       
  2909         bottomTickOffset: {
       
  2910             value: 0
       
  2911         },
       
  2912 
       
  2913         /**
       
  2914          * Distance determined by the tick styles used to calculate the distance between the axis
       
  2915          * line in relation to the left of the axis.
       
  2916          *
       
  2917          * @attribute leftTickOffset
       
  2918          * @type Number
       
  2919          */
       
  2920         leftTickOffset: {
       
  2921             value: 0
       
  2922         },
       
  2923 
       
  2924         /**
       
  2925          * Distance determined by the tick styles used to calculate the distance between the axis
       
  2926          * line in relation to the right side of the axis.
       
  2927          *
       
  2928          * @attribute rightTickOffset
       
  2929          * @type Number
       
  2930          */
       
  2931         rightTickOffset: {
       
  2932             value: 0
       
  2933         },
       
  2934 
       
  2935         /**
       
  2936          * Collection of labels used to render the axis.
       
  2937          *
       
  2938          * @attribute labels
       
  2939          * @type Array
       
  2940          */
       
  2941         labels: {
       
  2942             readOnly: true,
       
  2943             getter: function()
       
  2944             {
       
  2945                 return this._labels;
       
  2946             }
       
  2947         },
       
  2948 
       
  2949         /**
       
  2950          * Collection of points used for placement of labels and ticks along the axis.
       
  2951          *
       
  2952          * @attribute tickPoints
       
  2953          * @type Array
       
  2954          */
       
  2955         tickPoints: {
       
  2956             readOnly: true,
       
  2957 
       
  2958             getter: function()
       
  2959             {
       
  2960                 if(this.get("position") === "none")
       
  2961                 {
       
  2962                     return this.get("styles").majorUnit.count;
       
  2963                 }
       
  2964                 return this._tickPoints;
       
  2965             }
       
  2966         },
       
  2967 
       
  2968         /**
       
  2969          * Indicates whether the axis overlaps the graph. If an axis is the inner most axis on a given
       
  2970          * position and the tick position is inside or cross, the axis will need to overlap the graph.
       
  2971          *
       
  2972          * @attribute overlapGraph
       
  2973          * @type Boolean
       
  2974          */
       
  2975         overlapGraph: {
       
  2976             value:true,
       
  2977 
       
  2978             validator: function(val)
       
  2979             {
       
  2980                 return Y_Lang.isBoolean(val);
       
  2981             }
       
  2982         },
       
  2983 
       
  2984         /**
       
  2985          * Length in pixels of largest text bounding box. Used to calculate the height of the axis.
       
  2986          *
       
  2987          * @attribute maxLabelSize
       
  2988          * @type Number
       
  2989          * @protected
       
  2990          */
       
  2991         maxLabelSize: {
       
  2992             getter: function()
       
  2993             {
       
  2994                 return this._maxLabelSize;
       
  2995             },
       
  2996 
       
  2997             setter: function(val)
       
  2998             {
       
  2999                 this._maxLabelSize = val;
       
  3000                 return val;
       
  3001             }
       
  3002         },
       
  3003 
       
  3004         /**
       
  3005          *  Title for the axis. When specified, the title will display. The position of the title is determined by the axis position.
       
  3006          *  <dl>
       
  3007          *      <dt>top</dt><dd>Appears above the axis and it labels. The default rotation is 0.</dd>
       
  3008          *      <dt>right</dt><dd>Appears to the right of the axis and its labels. The default rotation is 90.</dd>
       
  3009          *      <dt>bottom</dt><dd>Appears below the axis and its labels. The default rotation is 0.</dd>
       
  3010          *      <dt>left</dt><dd>Appears to the left of the axis and its labels. The default rotation is -90.</dd>
       
  3011          *  </dl>
       
  3012          *
       
  3013          *  @attribute title
       
  3014          *  @type String
       
  3015          */
       
  3016         title: {
       
  3017             value: null
       
  3018         },
       
  3019 
       
  3020         /**
       
  3021          * Function used to append an axis value to an axis label. This function has the following signature:
       
  3022          *  <dl>
       
  3023          *      <dt>textField</dt><dd>The axis label to be appended. (`HTMLElement`)</dd>
       
  3024          *      <dt>val</dt><dd>The value to attach to the text field. This method will accept an `HTMLELement`
       
  3025          *      or a `String`. This method does not use (`HTMLElement` | `String`)</dd>
       
  3026          *  </dl>
       
  3027          * The default method appends a value to the `HTMLElement` using the `appendChild` method. If the given
       
  3028          * value is a `String`, the method will convert the the value to a `textNode` before appending to the
       
  3029          * `HTMLElement`. This method will not convert an `HTMLString` to an `HTMLElement`.
       
  3030          *
       
  3031          * @attribute appendLabelFunction
       
  3032          * @type Function
       
  3033          */
       
  3034         appendLabelFunction: {
       
  3035             valueFn: function()
       
  3036             {
       
  3037                 return this._setText;
       
  3038             }
       
  3039         },
       
  3040 
       
  3041         /**
       
  3042          * Function used to append a title value to the title object. This function has the following signature:
       
  3043          *  <dl>
       
  3044          *      <dt>textField</dt><dd>The title text field to be appended. (`HTMLElement`)</dd>
       
  3045          *      <dt>val</dt><dd>The value to attach to the text field. This method will accept an `HTMLELement`
       
  3046          *      or a `String`. This method does not use (`HTMLElement` | `String`)</dd>
       
  3047          *  </dl>
       
  3048          * The default method appends a value to the `HTMLElement` using the `appendChild` method. If the given
       
  3049          * value is a `String`, the method will convert the the value to a `textNode` before appending to the
       
  3050          * `HTMLElement` element. This method will not convert an `HTMLString` to an `HTMLElement`.
       
  3051          *
       
  3052          * @attribute appendTitleFunction
       
  3053          * @type Function
       
  3054          */
       
  3055         appendTitleFunction: {
       
  3056             valueFn: function()
       
  3057             {
       
  3058                 return this._setText;
       
  3059             }
       
  3060         },
       
  3061 
       
  3062         /**
       
  3063          * An array containing the unformatted values of the axis labels. By default, TimeAxis, NumericAxis and
       
  3064          * StackedAxis labelValues are determined by the majorUnit style. By default, CategoryAxis labels are
       
  3065          * determined by the values of the dataProvider.
       
  3066          * <p>When the labelValues attribute is explicitly set, the labelValues are dictated by the set value and
       
  3067          * the position of ticks and labels are determined by where those values would fall on the axis. </p>
       
  3068          *
       
  3069          * @attribute labelValues
       
  3070          * @type Array
       
  3071          */
       
  3072         labelValues: {
       
  3073             lazyAdd: false,
       
  3074 
       
  3075             setter: function(val)
       
  3076             {
       
  3077                 var opts = arguments[2];
       
  3078                 if(!val || (opts && opts.src && opts.src === "internal"))
       
  3079                 {
       
  3080                     this._labelValuesExplicitlySet = false;
       
  3081                 }
       
  3082                 else
       
  3083                 {
       
  3084                     this._labelValuesExplicitlySet = true;
       
  3085                 }
       
  3086                 return val;
       
  3087             }
       
  3088         },
       
  3089 
       
  3090         /**
       
  3091          * Suppresses the creation of the the first visible label and tick.
       
  3092          *
       
  3093          * @attribute hideFirstMajorUnit
       
  3094          * @type Boolean
       
  3095          */
       
  3096         hideFirstMajorUnit: {
       
  3097             value: false
       
  3098         },
       
  3099 
       
  3100         /**
       
  3101          * Suppresses the creation of the the last visible label and tick.
       
  3102          *
       
  3103          * @attribute hideLastMajorUnit
       
  3104          * @type Boolean
       
  3105          */
       
  3106         hideLastMajorUnit: {
       
  3107             value: false
       
  3108         }
       
  3109 
       
  3110         /**
       
  3111          * Style properties used for drawing an axis. This attribute is inherited from `Renderer`. Below are the default values:
       
  3112          *  <dl>
       
  3113          *      <dt>majorTicks</dt><dd>Properties used for drawing ticks.
       
  3114          *          <dl>
       
  3115          *              <dt>display</dt><dd>Position of the tick. Possible values are `inside`, `outside`, `cross` and `none`.
       
  3116          *              The default value is `inside`.</dd>
       
  3117          *              <dt>length</dt><dd>The length (in pixels) of the tick. The default value is 4.</dd>
       
  3118          *              <dt>color</dt><dd>The color of the tick. The default value is `#dad8c9`</dd>
       
  3119          *              <dt>weight</dt><dd>Number indicating the width of the tick. The default value is 1.</dd>
       
  3120          *              <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
       
  3121          *          </dl>
       
  3122          *      </dd>
       
  3123          *      <dt>line</dt><dd>Properties used for drawing the axis line.
       
  3124          *          <dl>
       
  3125          *              <dt>weight</dt><dd>Number indicating the width of the axis line. The default value is 1.</dd>
       
  3126          *              <dt>color</dt><dd>The color of the axis line. The default value is `#dad8c9`.</dd>
       
  3127          *              <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
       
  3128          *          </dl>
       
  3129          *      </dd>
       
  3130          *      <dt>majorUnit</dt><dd>Properties used to calculate the `majorUnit` for the axis.
       
  3131          *          <dl>
       
  3132          *              <dt>determinant</dt><dd>The algorithm used for calculating distance between ticks. The possible options are
       
  3133          *              `count` and `distance`. If the `determinant` is `count`, the axis ticks will spaced so that a specified number
       
  3134          *              of ticks appear on the axis. If the `determinant` is `distance`, the axis ticks will spaced out according to
       
  3135          *              the specified distance. The default value is `count`.</dd>
       
  3136          *              <dt>count</dt><dd>Number of ticks to appear on the axis when the `determinant` is `count`. The default value is 11.</dd>
       
  3137          *              <dt>distance</dt><dd>The distance (in pixels) between ticks when the `determinant` is `distance`. The default
       
  3138          *              value is 75.</dd>
       
  3139          *          </dl>
       
  3140          *      </dd>
       
  3141          *      <dt>label</dt><dd>Properties and styles applied to the axis labels.
       
  3142          *          <dl>
       
  3143          *              <dt>color</dt><dd>The color of the labels. The default value is `#808080`.</dd>
       
  3144          *              <dt>alpha</dt><dd>Number between 0 and 1 indicating the opacity of the labels. The default value is 1.</dd>
       
  3145          *              <dt>fontSize</dt><dd>The font-size of the labels. The default value is 85%</dd>
       
  3146          *              <dt>rotation</dt><dd>The rotation, in degrees (between -90 and 90) of the labels. The default value is 0.</dd>
       
  3147          *              <dt>offset</td><dd>A number between 0 and 1 indicating the relationship of the label to a tick. For a horizontal axis
       
  3148          *              label, a value of 0 will position the label's left side even to the the tick. A position of 1 would position the
       
  3149          *              right side of the label with the tick. A position of 0.5 would center the label horizontally with the tick. For a
       
  3150          *              vertical axis, a value of 0 would position the top of the label with the tick, a value of 1 would position the bottom
       
  3151          *              of the label with the tick and a value 0 would center the label vertically with the tick. The default value is 0.5.</dd>
       
  3152          *              <dt>margin</dt><dd>The distance between the label and the axis/tick. Depending on the position of the `Axis`,
       
  3153          *              only one of the properties used.
       
  3154          *                  <dl>
       
  3155          *                      <dt>top</dt><dd>Pixel value used for an axis with a `position` of `bottom`. The default value is 4.</dd>
       
  3156          *                      <dt>right</dt><dd>Pixel value used for an axis with a `position` of `left`. The default value is 4.</dd>
       
  3157          *                      <dt>bottom</dt><dd>Pixel value used for an axis with a `position` of `top`. The default value is 4.</dd>
       
  3158          *                      <dt>left</dt><dd>Pixel value used for an axis with a `position` of `right`. The default value is 4.</dd>
       
  3159          *                  </dl>
       
  3160          *              </dd>
       
  3161          *          </dl>
       
  3162          *      </dd>
       
  3163          *  </dl>
       
  3164          *
       
  3165          * @attribute styles
       
  3166          * @type Object
       
  3167          */
       
  3168     }
       
  3169 });
       
  3170 Y.AxisType = Y.Base.create("baseAxis", Y.Axis, [], {});
       
  3171 
       
  3172 
       
  3173 }, '@VERSION@', {"requires": ["dom", "widget", "widget-position", "widget-stack", "graphics", "axis-base"]});