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