text: YUI.add('axis', function (Y, NAME) {
  
  /**
   * Provides base functionality for drawing chart axes.
   *
   * @module charts
   * @submodule axis
   */
  var CONFIG = Y.config,
      DOCUMENT = CONFIG.doc,
      Y_Lang = Y.Lang,
      IS_STRING = Y_Lang.isString,
      Y_DOM = Y.DOM,
      LeftAxisLayout,
      RightAxisLayout,
      BottomAxisLayout,
      TopAxisLayout;
  /**
   * Algorithmic strategy for rendering a left axis.
   *
   * @class LeftAxisLayout
   * @constructor
   * @submodule axis
   */
  LeftAxisLayout = function() {};
  
  LeftAxisLayout.prototype = {
      /**
       *  Default margins for text fields.
       *
       *  @private
       *  @method _getDefaultMargins
       *  @return Object
       */
      _getDefaultMargins: function()
      {
          return {
              top: 0,
              left: 0,
              right: 4,
              bottom: 0
          };
      },
  
      /**
       * Sets the length of the tick on either side of the axis line.
       *
       * @method setTickOffset
       * @protected
       */
      setTickOffsets: function()
      {
          var host = this,
              majorTicks = host.get("styles").majorTicks,
              tickLength = majorTicks.length,
              halfTick = tickLength * 0.5,
              display = majorTicks.display;
          host.set("topTickOffset",  0);
          host.set("bottomTickOffset",  0);
  
          switch(display)
          {
              case "inside" :
                  host.set("rightTickOffset",  tickLength);
                  host.set("leftTickOffset", 0);
              break;
              case "outside" :
                  host.set("rightTickOffset", 0);
                  host.set("leftTickOffset",  tickLength);
              break;
              case "cross":
                  host.set("rightTickOffset", halfTick);
                  host.set("leftTickOffset",  halfTick);
              break;
              default:
                  host.set("rightTickOffset", 0);
                  host.set("leftTickOffset", 0);
              break;
          }
      },
  
      /**
       * Draws a tick
       *
       * @method drawTick
       * @param {Path} path reference to the path `Path` element in which to draw the tick.
       * @param {Object} pt Point on the axis in which the tick will intersect.
       * @param {Object} tickStyle Hash of properties to apply to the tick.
       * @protected
       */
      drawTick: function(path, pt, tickStyles)
      {
          var host = this,
              style = host.get("styles"),
              padding = style.padding,
              tickLength = tickStyles.length,
              start = {x:padding.left, y:pt.y},
              end = {x:tickLength + padding.left, y:pt.y};
          host.drawLine(path, start, end);
      },
  
      /**
       * Calculates the coordinates for the first point on an axis.
       *
       * @method getLineStart
       * @return {Object}
       * @protected
       */
      getLineStart: function()
      {
          var style = this.get("styles"),
              padding = style.padding,
              majorTicks = style.majorTicks,
              tickLength = majorTicks.length,
              display = majorTicks.display,
              pt = {x:padding.left, y:0};
          if(display === "outside")
          {
              pt.x += tickLength;
          }
          else if(display === "cross")
          {
              pt.x += tickLength/2;
          }
          return pt;
      },
  
      /**
       * Calculates the point for a label.
       *
       * @method getLabelPoint
       * @param {Object} point Point on the axis in which the tick will intersect.
       * @return {Object}
       * @protected
       */
      getLabelPoint: function(point)
      {
          return {x:point.x - this.get("leftTickOffset"), y:point.y};
      },
  
      /**
       * Updates the value for the `maxLabelSize` for use in calculating total size.
       *
       * @method updateMaxLabelSize
       * @param {HTMLElement} label to measure
       * @protected
       */
      updateMaxLabelSize: function(labelWidth, labelHeight)
      {
          var host = this,
              props = this._labelRotationProps,
              rot = props.rot,
              absRot = props.absRot,
              sinRadians = props.sinRadians,
              cosRadians = props.cosRadians,
              max;
          if(rot === 0)
          {
              max = labelWidth;
          }
          else if(absRot === 90)
          {
              max = labelHeight;
          }
          else
          {
              max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
          }
          host._maxLabelSize = Math.max(host._maxLabelSize, max);
      },
  
      /**
       * Determines the available label width when the axis width has been explicitly set.
       *
       * @method getExplicitlySized
       * @return Boolean
       * @protected
       */
      getExplicitlySized: function(styles)
      {
          if(this._explicitWidth)
          {
              var host = this,
                  w = host._explicitWidth,
                  totalTitleSize = host._totalTitleSize,
                  leftTickOffset = host.get("leftTickOffset"),
                  margin = styles.label.margin.right;
              host._maxLabelSize =  w - (leftTickOffset + margin + totalTitleSize);
              return true;
          }
          return false;
      },
  
      /**
       * Rotate and position title.
       *
       * @method positionTitle
       * @param {HTMLElement} label to rotate position
       * @protected
       */
      positionTitle: function(label)
      {
          var host = this,
              bounds = host._titleBounds,
              margin = host.get("styles").title.margin,
              props = host._titleRotationProps,
              w = bounds.right - bounds.left,
              labelWidth = label.offsetWidth,
              labelHeight = label.offsetHeight,
              x = (labelWidth * -0.5) + (w * 0.5),
              y = (host.get("height") * 0.5) - (labelHeight * 0.5);
          props.labelWidth = labelWidth;
          props.labelHeight = labelHeight;
          if(margin && margin.left)
          {
              x += margin.left;
          }
          props.x = x;
          props.y = y;
          props.transformOrigin = [0.5, 0.5];
          host._rotate(label, props);
      },
  
      /**
       * Rotate and position labels.
       *
       * @method positionLabel
       * @param {HTMLElement} label to rotate position
       * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
       * against.
       * @protected
       */
      positionLabel: function(label, pt, styles, i)
      {
          var host = this,
              offset = parseFloat(styles.label.offset),
              tickOffset = host.get("leftTickOffset"),
              totalTitleSize = this._totalTitleSize,
              leftOffset = pt.x + totalTitleSize - tickOffset,
              topOffset = pt.y,
              props = this._labelRotationProps,
              rot = props.rot,
              absRot = props.absRot,
              maxLabelSize = host._maxLabelSize,
              labelWidth = this._labelWidths[i],
              labelHeight = this._labelHeights[i];
          if(rot === 0)
          {
              leftOffset -= labelWidth;
              topOffset -= labelHeight * offset;
          }
          else if(rot === 90)
          {
              leftOffset -= labelWidth * 0.5;
              topOffset = topOffset + labelWidth/2 - (labelWidth * offset);
          }
          else if(rot === -90)
          {
              leftOffset -= labelWidth * 0.5;
              topOffset = topOffset - labelHeight + labelWidth/2 - (labelWidth * offset);
          }
          else
          {
              leftOffset -= labelWidth + (labelHeight * absRot/360);
              topOffset -= labelHeight * offset;
          }
          props.labelWidth = labelWidth;
          props.labelHeight = labelHeight;
          props.x = Math.round(maxLabelSize + leftOffset);
          props.y = Math.round(topOffset);
          this._rotate(label, props);
      },
  
      /**
       * Adjusts the coordinates of an axis label based on the rotation.
       *
       * @method _setRotationCoords
       * @param {Object} props Coordinates, dimension and rotation properties of the label.
       * @protected
       */
      _setRotationCoords: function(props)
      {
          var rot = props.rot,
              absRot = props.absRot,
              leftOffset,
              topOffset,
              labelWidth = props.labelWidth,
              labelHeight = props.labelHeight;
          if(rot === 0)
          {
              leftOffset = labelWidth;
              topOffset = labelHeight * 0.5;
          }
          else if(rot === 90)
          {
              topOffset = 0;
              leftOffset = labelWidth * 0.5;
          }
          else if(rot === -90)
          {
              leftOffset = labelWidth * 0.5;
              topOffset = labelHeight;
          }
          else
          {
              leftOffset = labelWidth + (labelHeight * absRot/360);
              topOffset = labelHeight * 0.5;
          }
          props.x -= leftOffset;
          props.y -= topOffset;
      },
  
      /**
       * Returns the transformOrigin to use for an axis label based on the position of the axis
       * and the rotation of the label.
       *
       * @method _getTransformOrigin
       * @param {Number} rot The rotation (in degrees) of the label.
       * @return Array
       * @protected
       */
      _getTransformOrigin: function(rot)
      {
          var transformOrigin;
          if(rot === 0)
          {
              transformOrigin = [0, 0];
          }
          else if(rot === 90)
          {
              transformOrigin = [0.5, 0];
          }
          else if(rot === -90)
          {
              transformOrigin = [0.5, 1];
          }
          else
          {
              transformOrigin = [1, 0.5];
          }
          return transformOrigin;
      },
  
      /**
       * Adjust the position of the Axis widget's content box for internal axes.
       *
       * @method offsetNodeForTick
       * @param {Node} cb contentBox of the axis
       * @protected
       */
      offsetNodeForTick: function()
      {
      },
  
      /**
       * Sets the width of the axis based on its contents.
       *
       * @method setCalculatedSize
       * @protected
       */
      setCalculatedSize: function()
      {
          var host = this,
              graphic = this.get("graphic"),
              style = host.get("styles"),
              label = style.label,
              tickOffset = host.get("leftTickOffset"),
              max = host._maxLabelSize,
              totalTitleSize = this._totalTitleSize,
              ttl = Math.round(totalTitleSize + tickOffset + max + label.margin.right);
          if(this._explicitWidth)
          {
              ttl = this._explicitWidth;
          }
          this.set("calculatedWidth", ttl);
          graphic.set("x", ttl - tickOffset);
      }
  };
  
  Y.LeftAxisLayout = LeftAxisLayout;
  /**
   * RightAxisLayout contains algorithms for rendering a right axis.
   *
   * @class RightAxisLayout
   * @constructor
   * @submodule axis
   */
  RightAxisLayout = function(){};
  
  RightAxisLayout.prototype = {
      /**
       *  Default margins for text fields.
       *
       *  @private
       *  @method _getDefaultMargins
       *  @return Object
       */
      _getDefaultMargins: function()
      {
          return {
              top: 0,
              left: 4,
              right: 0,
              bottom: 0
          };
      },
  
      /**
       * Sets the length of the tick on either side of the axis line.
       *
       * @method setTickOffset
       * @protected
       */
      setTickOffsets: function()
      {
          var host = this,
              majorTicks = host.get("styles").majorTicks,
              tickLength = majorTicks.length,
              halfTick = tickLength * 0.5,
              display = majorTicks.display;
          host.set("topTickOffset",  0);
          host.set("bottomTickOffset",  0);
  
          switch(display)
          {
              case "inside" :
                  host.set("leftTickOffset", tickLength);
                  host.set("rightTickOffset", 0);
              break;
              case "outside" :
                  host.set("leftTickOffset", 0);
                  host.set("rightTickOffset", tickLength);
              break;
              case "cross" :
                  host.set("rightTickOffset", halfTick);
                  host.set("leftTickOffset", halfTick);
              break;
              default:
                  host.set("leftTickOffset", 0);
                  host.set("rightTickOffset", 0);
              break;
          }
      },
  
      /**
       * Draws a tick
       *
       * @method drawTick
       * @param {Path} path reference to the path `Path` element in which to draw the tick.
       * @param {Object} pt Point on the axis in which the tick will intersect.
       * @param {Object} tickStyle Hash of properties to apply to the tick.
       * @protected
       */
      drawTick: function(path, pt, tickStyles)
      {
          var host = this,
              style = host.get("styles"),
              padding = style.padding,
              tickLength = tickStyles.length,
              start = {x:padding.left, y:pt.y},
              end = {x:padding.left + tickLength, y:pt.y};
          host.drawLine(path, start, end);
      },
  
      /**
       * Calculates the coordinates for the first point on an axis.
       *
       * @method getLineStart
       * @return {Object}
       * @protected
       */
      getLineStart: function()
      {
          var host = this,
              style = host.get("styles"),
              padding = style.padding,
              majorTicks = style.majorTicks,
              tickLength = majorTicks.length,
              display = majorTicks.display,
              pt = {x:padding.left, y:padding.top};
          if(display === "inside")
          {
              pt.x += tickLength;
          }
          else if(display === "cross")
          {
              pt.x += tickLength/2;
          }
          return pt;
      },
  
      /**
       * Calculates the point for a label.
       *
       * @method getLabelPoint
       * @param {Object} point Point on the axis in which the tick will intersect.
       * @return {Object}
       * @protected
       */
      getLabelPoint: function(point)
      {
          return {x:point.x + this.get("rightTickOffset"), y:point.y};
      },
  
      /**
       * Updates the value for the `maxLabelSize` for use in calculating total size.
       *
       * @method updateMaxLabelSize
       * @param {HTMLElement} label to measure
       * @protected
       */
      updateMaxLabelSize: function(labelWidth, labelHeight)
      {
          var host = this,
              props = this._labelRotationProps,
              rot = props.rot,
              absRot = props.absRot,
              sinRadians = props.sinRadians,
              cosRadians = props.cosRadians,
              max;
          if(rot === 0)
          {
              max = labelWidth;
          }
          else if(absRot === 90)
          {
              max = labelHeight;
          }
          else
          {
              max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
          }
          host._maxLabelSize = Math.max(host._maxLabelSize, max);
      },
  
      /**
       * Determines the available label width when the axis width has been explicitly set.
       *
       * @method getExplicitlySized
       * @return Boolean
       * @protected
       */
      getExplicitlySized: function(styles)
      {
          if(this._explicitWidth)
          {
              var host = this,
                  w = host._explicitWidth,
                  totalTitleSize = this._totalTitleSize,
                  rightTickOffset = host.get("rightTickOffset"),
                  margin = styles.label.margin.right;
              host._maxLabelSize =  w - (rightTickOffset + margin + totalTitleSize);
              return true;
          }
          return false;
      },
  
      /**
       * Rotate and position title.
       *
       * @method positionTitle
       * @param {HTMLElement} label to rotate position
       * @protected
       */
      positionTitle: function(label)
      {
          var host = this,
              bounds = host._titleBounds,
              margin = host.get("styles").title.margin,
              props = host._titleRotationProps,
              labelWidth = label.offsetWidth,
              labelHeight = label.offsetHeight,
              w = bounds.right - bounds.left,
              x = this.get("width") - (labelWidth * 0.5) - (w * 0.5),
              y = (host.get("height") * 0.5) - (labelHeight * 0.5);
          props.labelWidth = labelWidth;
          props.labelHeight = labelHeight;
          if(margin && margin.right)
          {
              x -= margin.left;
          }
          props.x = x;
          props.y = y;
          props.transformOrigin = [0.5, 0.5];
          host._rotate(label, props);
      },
  
      /**
       * Rotate and position labels.
       *
       * @method positionLabel
       * @param {HTMLElement} label to rotate position
       * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
       * against.
       * @protected
       */
      positionLabel: function(label, pt, styles, i)
      {
          var host = this,
              offset = parseFloat(styles.label.offset),
              tickOffset = host.get("rightTickOffset"),
              labelStyles = styles.label,
              margin = 0,
              leftOffset = pt.x,
              topOffset = pt.y,
              props = this._labelRotationProps,
              rot = props.rot,
              absRot = props.absRot,
              labelWidth = this._labelWidths[i],
              labelHeight = this._labelHeights[i];
          if(labelStyles.margin && labelStyles.margin.left)
          {
              margin = labelStyles.margin.left;
          }
          if(rot === 0)
          {
              topOffset -= labelHeight * offset;
          }
          else if(rot === 90)
          {
              leftOffset -= labelWidth * 0.5;
              topOffset = topOffset - labelHeight + labelWidth/2 - (labelWidth * offset);
          }
          else if(rot === -90)
          {
              topOffset = topOffset + labelWidth/2 - (labelWidth * offset);
              leftOffset -= labelWidth * 0.5;
          }
          else
          {
              topOffset -= labelHeight * offset;
              leftOffset += labelHeight/2 * absRot/90;
          }
          leftOffset += margin;
          leftOffset += tickOffset;
          props.labelWidth = labelWidth;
          props.labelHeight = labelHeight;
          props.x = Math.round(leftOffset);
          props.y = Math.round(topOffset);
          this._rotate(label, props);
      },
  
      /**
       * Adjusts the coordinates of an axis label based on the rotation.
       *
       * @method _setRotationCoords
       * @param {Object} props Coordinates, dimension and rotation properties of the label.
       * @protected
       */
      _setRotationCoords: function(props)
      {
          var rot = props.rot,
              absRot = props.absRot,
              leftOffset = 0,
              topOffset = 0,
              labelWidth = props.labelWidth,
              labelHeight = props.labelHeight;
          if(rot === 0)
          {
              topOffset = labelHeight * 0.5;
          }
          else if(rot === 90)
          {
              leftOffset = labelWidth * 0.5;
              topOffset = labelHeight;
          }
          else if(rot === -90)
          {
              leftOffset = labelWidth * 0.5;
          }
          else
          {
              topOffset = labelHeight * 0.5;
              leftOffset = labelHeight/2 * absRot/90;
          }
          props.x -= leftOffset;
          props.y -= topOffset;
      },
  
      /**
       * Returns the transformOrigin to use for an axis label based on the position of the axis
       * and the rotation of the label.
       *
       * @method _getTransformOrigin
       * @param {Number} rot The rotation (in degrees) of the label.
       * @return Array
       * @protected
       */
      _getTransformOrigin: function(rot)
      {
          var transformOrigin;
          if(rot === 0)
          {
              transformOrigin = [0, 0];
          }
          else if(rot === 90)
          {
              transformOrigin = [0.5, 1];
          }
          else if(rot === -90)
          {
              transformOrigin = [0.5, 0];
          }
          else
          {
              transformOrigin = [0, 0.5];
          }
          return transformOrigin;
      },
  
      /**
       * Adjusts position for inner ticks.
       *
       * @method offsetNodeForTick
       * @param {Node} cb contentBox of the axis
       * @protected
       */
      offsetNodeForTick: function(cb)
      {
          var host = this,
              tickOffset = host.get("leftTickOffset"),
              offset = 0 - tickOffset;
          cb.setStyle("left", offset);
      },
  
      /**
       * Assigns a height based on the size of the contents.
       *
       * @method setCalculatedSize
       * @protected
       */
      setCalculatedSize: function()
      {
          var host = this,
              styles = host.get("styles"),
              labelStyle = styles.label,
              totalTitleSize = this._totalTitleSize,
              ttl = Math.round(host.get("rightTickOffset") + host._maxLabelSize + totalTitleSize + labelStyle.margin.left);
          if(this._explicitWidth)
          {
              ttl = this._explicitWidth;
          }
          host.set("calculatedWidth", ttl);
          host.get("contentBox").setStyle("width", ttl);
      }
  };
  
  Y.RightAxisLayout = RightAxisLayout;
  /**
   * Contains algorithms for rendering a bottom axis.
   *
   * @class BottomAxisLayout
   * @Constructor
   * @submodule axis
   */
  BottomAxisLayout = function(){};
  
  BottomAxisLayout.prototype = {
      /**
       *  Default margins for text fields.
       *
       *  @private
       *  @method _getDefaultMargins
       *  @return Object
       */
      _getDefaultMargins: function()
      {
          return {
              top: 4,
              left: 0,
              right: 0,
              bottom: 0
          };
      },
  
      /**
       * Sets the length of the tick on either side of the axis line.
       *
       * @method setTickOffsets
       * @protected
       */
      setTickOffsets: function()
      {
          var host = this,
              majorTicks = host.get("styles").majorTicks,
              tickLength = majorTicks.length,
              halfTick = tickLength * 0.5,
              display = majorTicks.display;
          host.set("leftTickOffset",  0);
          host.set("rightTickOffset",  0);
  
          switch(display)
          {
              case "inside" :
                  host.set("topTickOffset", tickLength);
                  host.set("bottomTickOffset", 0);
              break;
              case "outside" :
                  host.set("topTickOffset", 0);
                  host.set("bottomTickOffset", tickLength);
              break;
              case "cross":
                  host.set("topTickOffset",  halfTick);
                  host.set("bottomTickOffset",  halfTick);
              break;
              default:
                  host.set("topTickOffset", 0);
                  host.set("bottomTickOffset", 0);
              break;
          }
      },
  
      /**
       * Calculates the coordinates for the first point on an axis.
       *
       * @method getLineStart
       * @protected
       */
      getLineStart: function()
      {
          var style = this.get("styles"),
              padding = style.padding,
              majorTicks = style.majorTicks,
              tickLength = majorTicks.length,
              display = majorTicks.display,
              pt = {x:0, y:padding.top};
          if(display === "inside")
          {
              pt.y += tickLength;
          }
          else if(display === "cross")
          {
              pt.y += tickLength/2;
          }
          return pt;
      },
  
      /**
       * Draws a tick
       *
       * @method drawTick
       * @param {Path} path reference to the path `Path` element in which to draw the tick.
       * @param {Object} pt hash containing x and y coordinates
       * @param {Object} tickStyles hash of properties used to draw the tick
       * @protected
       */
      drawTick: function(path, pt, tickStyles)
      {
          var host = this,
              style = host.get("styles"),
              padding = style.padding,
              tickLength = tickStyles.length,
              start = {x:pt.x, y:padding.top},
              end = {x:pt.x, y:tickLength + padding.top};
          host.drawLine(path, start, end);
      },
  
      /**
       * Calculates the point for a label.
       *
       * @method getLabelPoint
       * @param {Object} pt Object containing x and y coordinates
       * @return Object
       * @protected
       */
      getLabelPoint: function(point)
      {
          return {x:point.x, y:point.y + this.get("bottomTickOffset")};
      },
  
      /**
       * Updates the value for the `maxLabelSize` for use in calculating total size.
       *
       * @method updateMaxLabelSize
       * @param {HTMLElement} label to measure
       * @protected
       */
      updateMaxLabelSize: function(labelWidth, labelHeight)
      {
          var host = this,
              props = this._labelRotationProps,
              rot = props.rot,
              absRot = props.absRot,
              sinRadians = props.sinRadians,
              cosRadians = props.cosRadians,
              max;
          if(rot === 0)
          {
              max = labelHeight;
          }
          else if(absRot === 90)
          {
              max = labelWidth;
          }
          else
          {
              max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
          }
          host._maxLabelSize = Math.max(host._maxLabelSize, max);
      },
  
      /**
       * Determines the available label height when the axis width has been explicitly set.
       *
       * @method getExplicitlySized
       * @return Boolean
       * @protected
       */
      getExplicitlySized: function(styles)
      {
          if(this._explicitHeight)
          {
              var host = this,
                  h = host._explicitHeight,
                  totalTitleSize = host._totalTitleSize,
                  bottomTickOffset = host.get("bottomTickOffset"),
                  margin = styles.label.margin.right;
              host._maxLabelSize =  h - (bottomTickOffset + margin + totalTitleSize);
              return true;
          }
          return false;
      },
  
      /**
       * Rotate and position title.
       *
       * @method positionTitle
       * @param {HTMLElement} label to rotate position
       * @protected
       */
      positionTitle: function(label)
      {
          var host = this,
              bounds = host._titleBounds,
              margin = host.get("styles").title.margin,
              props = host._titleRotationProps,
              h = bounds.bottom - bounds.top,
              labelWidth = label.offsetWidth,
              labelHeight = label.offsetHeight,
              x = (host.get("width") * 0.5) - (labelWidth * 0.5),
              y = host.get("height") - labelHeight/2 - h/2;
          props.labelWidth = labelWidth;
          props.labelHeight = labelHeight;
          if(margin && margin.bottom)
          {
              y -= margin.bottom;
          }
          props.x = x;
          props.y = y;
          props.transformOrigin = [0.5, 0.5];
          host._rotate(label, props);
      },
  
      /**
       * Rotate and position labels.
       *
       * @method positionLabel
       * @param {HTMLElement} label to rotate position
       * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
       * against.
       * @protected
       */
      positionLabel: function(label, pt, styles, i)
      {
          var host = this,
              offset = parseFloat(styles.label.offset),
              tickOffset = host.get("bottomTickOffset"),
              labelStyles = styles.label,
              margin = 0,
              props = host._labelRotationProps,
              rot = props.rot,
              absRot = props.absRot,
              leftOffset = Math.round(pt.x),
              topOffset = Math.round(pt.y),
              labelWidth = host._labelWidths[i],
              labelHeight = host._labelHeights[i];
          if(labelStyles.margin && labelStyles.margin.top)
          {
              margin = labelStyles.margin.top;
          }
          if(rot === 90)
          {
              topOffset -= labelHeight/2 * rot/90;
              leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
          }
          else if(rot === -90)
          {
              topOffset -= labelHeight/2 * absRot/90;
              leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
          }
          else if(rot > 0)
          {
              leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
              topOffset -= labelHeight/2 * rot/90;
          }
          else if(rot < 0)
          {
              leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
              topOffset -= labelHeight/2 * absRot/90;
          }
          else
          {
              leftOffset -= labelWidth * offset;
          }
          topOffset += margin;
          topOffset += tickOffset;
          props.labelWidth = labelWidth;
          props.labelHeight = labelHeight;
          props.x = leftOffset;
          props.y = topOffset;
          host._rotate(label, props);
      },
  
      /**
       * Adjusts the coordinates of an axis label based on the rotation.
       *
       * @method _setRotationCoords
       * @param {Object} props Coordinates, dimension and rotation properties of the label.
       * @protected
       */
      _setRotationCoords: function(props)
      {
          var rot = props.rot,
              absRot = props.absRot,
              labelWidth = props.labelWidth,
              labelHeight = props.labelHeight,
              leftOffset,
              topOffset;
  
          if(rot > 0)
          {
              leftOffset = 0;
              topOffset = labelHeight/2 * rot/90;
          }
          else if(rot < 0)
          {
              leftOffset = labelWidth;
              topOffset = labelHeight/2 * absRot/90;
          }
          else
          {
              leftOffset = labelWidth * 0.5;
              topOffset = 0;
          }
          props.x -= leftOffset;
          props.y -= topOffset;
      },
  
      /**
       * Returns the transformOrigin to use for an axis label based on the position of the axis
       * and the rotation of the label.
       *
       * @method _getTransformOrigin
       * @param {Number} rot The rotation (in degrees) of the label.
       * @return Array
       * @protected
       */
      _getTransformOrigin: function(rot)
      {
          var transformOrigin;
          if(rot > 0)
          {
              transformOrigin = [0, 0.5];
          }
          else if(rot < 0)
          {
              transformOrigin = [1, 0.5];
          }
          else
          {
              transformOrigin = [0, 0];
          }
          return transformOrigin;
      },
  
      /**
       * Adjusts position for inner ticks.
       *
       * @method offsetNodeForTick
       * @param {Node} cb contentBox of the axis
       * @protected
       */
      offsetNodeForTick: function(cb)
      {
          var host = this;
          cb.setStyle("top", 0 - host.get("topTickOffset"));
      },
  
      /**
       * Assigns a height based on the size of the contents.
       *
       * @method setCalculatedSize
       * @protected
       */
      setCalculatedSize: function()
      {
          var host = this,
              styles = host.get("styles"),
              labelStyle = styles.label,
              totalTitleSize = host._totalTitleSize,
              ttl = Math.round(host.get("bottomTickOffset") + host._maxLabelSize + labelStyle.margin.top + totalTitleSize);
          if(host._explicitHeight)
          {
              ttl = host._explicitHeight;
          }
          host.set("calculatedHeight", ttl);
      }
  };
  Y.BottomAxisLayout = BottomAxisLayout;
  /**
   * Contains algorithms for rendering a top axis.
   *
   * @class TopAxisLayout
   * @constructor
   * @submodule axis
   */
  TopAxisLayout = function(){};
  
  TopAxisLayout.prototype = {
      /**
       *  Default margins for text fields.
       *
       *  @private
       *  @method _getDefaultMargins
       *  @return Object
       */
      _getDefaultMargins: function()
      {
          return {
              top: 0,
              left: 0,
              right: 0,
              bottom: 4
          };
      },
  
      /**
       * Sets the length of the tick on either side of the axis line.
       *
       * @method setTickOffsets
       * @protected
       */
      setTickOffsets: function()
      {
          var host = this,
              majorTicks = host.get("styles").majorTicks,
              tickLength = majorTicks.length,
              halfTick = tickLength * 0.5,
              display = majorTicks.display;
          host.set("leftTickOffset",  0);
          host.set("rightTickOffset",  0);
          switch(display)
          {
              case "inside" :
                  host.set("bottomTickOffset", tickLength);
                  host.set("topTickOffset", 0);
              break;
              case "outside" :
                  host.set("bottomTickOffset", 0);
                  host.set("topTickOffset",  tickLength);
              break;
              case "cross" :
                  host.set("topTickOffset", halfTick);
                  host.set("bottomTickOffset", halfTick);
              break;
              default:
                  host.set("topTickOffset", 0);
                  host.set("bottomTickOffset", 0);
              break;
          }
      },
  
      /**
       * Calculates the coordinates for the first point on an axis.
       *
       * @method getLineStart
       * @protected
       */
      getLineStart: function()
      {
          var host = this,
              style = host.get("styles"),
              padding = style.padding,
              majorTicks = style.majorTicks,
              tickLength = majorTicks.length,
              display = majorTicks.display,
              pt = {x:0, y:padding.top};
          if(display === "outside")
          {
              pt.y += tickLength;
          }
          else if(display === "cross")
          {
              pt.y += tickLength/2;
          }
          return pt;
      },
  
      /**
       * Draws a tick
       *
       * @method drawTick
       * @param {Path} path reference to the path `Path` element in which to draw the tick.
       * @param {Object} pt hash containing x and y coordinates
       * @param {Object} tickStyles hash of properties used to draw the tick
       * @protected
       */
      drawTick: function(path, pt, tickStyles)
      {
          var host = this,
              style = host.get("styles"),
              padding = style.padding,
              tickLength = tickStyles.length,
              start = {x:pt.x, y:padding.top},
              end = {x:pt.x, y:tickLength + padding.top};
          host.drawLine(path, start, end);
      },
  
      /**
       * Calculates the point for a label.
       *
       * @method getLabelPoint
       * @param {Object} pt hash containing x and y coordinates
       * @return Object
       * @protected
       */
      getLabelPoint: function(pt)
      {
          return {x:pt.x, y:pt.y - this.get("topTickOffset")};
      },
  
      /**
       * Updates the value for the `maxLabelSize` for use in calculating total size.
       *
       * @method updateMaxLabelSize
       * @param {HTMLElement} label to measure
       * @protected
       */
      updateMaxLabelSize: function(labelWidth, labelHeight)
      {
          var host = this,
              props = this._labelRotationProps,
              rot = props.rot,
              absRot = props.absRot,
              sinRadians = props.sinRadians,
              cosRadians = props.cosRadians,
              max;
          if(rot === 0)
          {
              max = labelHeight;
          }
          else if(absRot === 90)
          {
              max = labelWidth;
          }
          else
          {
              max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
          }
          host._maxLabelSize = Math.max(host._maxLabelSize, max);
      },
  
      /**
       * Determines the available label height when the axis width has been explicitly set.
       *
       * @method getExplicitlySized
       * @return Boolean
       * @protected
       */
      getExplicitlySized: function(styles)
      {
          if(this._explicitHeight)
          {
              var host = this,
                  h = host._explicitHeight,
                  totalTitleSize = host._totalTitleSize,
                  topTickOffset = host.get("topTickOffset"),
                  margin = styles.label.margin.right;
              host._maxLabelSize =  h - (topTickOffset + margin + totalTitleSize);
              return true;
          }
          return false;
      },
  
      /**
       * Rotate and position title.
       *
       * @method positionTitle
       * @param {HTMLElement} label to rotate position
       * @protected
       */
      positionTitle: function(label)
      {
          var host = this,
              bounds = host._titleBounds,
              margin = host.get("styles").title.margin,
              props = host._titleRotationProps,
              labelWidth = label.offsetWidth,
              labelHeight = label.offsetHeight,
              h = bounds.bottom - bounds.top,
              x = (host.get("width") * 0.5) - (labelWidth * 0.5),
              y = h/2 - labelHeight/2;
          props.labelWidth = labelWidth;
          props.labelHeight = labelHeight;
          if(margin && margin.top)
          {
              y += margin.top;
          }
          props.x = x;
          props.y = y;
          props.transformOrigin = [0.5, 0.5];
          host._rotate(label, props);
      },
  
      /**
       * Rotate and position labels.
       *
       * @method positionLabel
       * @param {HTMLElement} label to rotate position
       * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
       * against.
       * @protected
       */
      positionLabel: function(label, pt, styles, i)
      {
          var host = this,
              offset = parseFloat(styles.label.offset),
              totalTitleSize = this._totalTitleSize,
              maxLabelSize = host._maxLabelSize,
              leftOffset = pt.x,
              topOffset = pt.y + totalTitleSize + maxLabelSize,
              props = this._labelRotationProps,
              rot = props.rot,
              absRot = props.absRot,
              labelWidth = this._labelWidths[i],
              labelHeight = this._labelHeights[i];
          if(rot === 0)
          {
              leftOffset -= labelWidth * offset;
              topOffset -= labelHeight;
          }
          else
          {
              if(rot === 90)
              {
                  leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
                  topOffset -= (labelHeight * 0.5);
              }
              else if (rot === -90)
              {
                  leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
                  topOffset -= (labelHeight * 0.5);
              }
              else if(rot > 0)
              {
                  leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
                  topOffset -= labelHeight - (labelHeight * rot/180);
              }
              else
              {
                  leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
                  topOffset -= labelHeight - (labelHeight * absRot/180);
              }
          }
          props.x = Math.round(leftOffset);
          props.y = Math.round(topOffset);
          props.labelWidth = labelWidth;
          props.labelHeight = labelHeight;
          this._rotate(label, props);
      },
  
      /**
       * Adjusts the coordinates of an axis label based on the rotation.
       *
       * @method _setRotationCoords
       * @param {Object} props Coordinates, dimension and rotation properties of the label.
       * @protected
       */
      _setRotationCoords: function(props)
      {
          var rot = props.rot,
              absRot = props.absRot,
              labelWidth = props.labelWidth,
              labelHeight = props.labelHeight,
              leftOffset,
              topOffset;
          if(rot === 0)
          {
              leftOffset = labelWidth * 0.5;
              topOffset = labelHeight;
          }
          else
          {
              if(rot === 90)
              {
                  leftOffset = labelWidth;
                  topOffset = (labelHeight * 0.5);
              }
              else if (rot === -90)
              {
                  topOffset = (labelHeight * 0.5);
              }
              else if(rot > 0)
              {
                  leftOffset = labelWidth;
                  topOffset = labelHeight - (labelHeight * rot/180);
              }
              else
              {
                  topOffset = labelHeight - (labelHeight * absRot/180);
              }
          }
          props.x -= leftOffset;
          props.y -= topOffset;
      },
  
      /**
       * Returns the transformOrigin to use for an axis label based on the position of the axis
       * and the rotation of the label.
       *
       * @method _getTransformOrigin
       * @param {Number} rot The rotation (in degrees) of the label.
       * @return Array
       * @protected
       */
      _getTransformOrigin: function(rot)
      {
          var transformOrigin;
          if(rot === 0)
          {
              transformOrigin = [0, 0];
          }
          else
          {
              if(rot === 90)
              {
                  transformOrigin = [1, 0.5];
              }
              else if (rot === -90)
              {
                  transformOrigin = [0, 0.5];
              }
              else if(rot > 0)
              {
                  transformOrigin = [1, 0.5];
              }
              else
              {
                  transformOrigin = [0, 0.5];
              }
          }
          return transformOrigin;
      },
  
      /**
       * Adjusts position for inner ticks.
       *
       * @method offsetNodeForTick
       * @param {Node} cb contentBox of the axis
       * @protected
       */
      offsetNodeForTick: function()
      {
      },
  
      /**
       * Assigns a height based on the size of the contents.
       *
       * @method setCalculatedSize
       * @protected
       */
      setCalculatedSize: function()
      {
          var host = this,
              graphic = host.get("graphic"),
              styles = host.get("styles"),
              labelMargin = styles.label.margin,
              totalLabelSize = labelMargin.bottom + host._maxLabelSize,
              totalTitleSize = host._totalTitleSize,
              topTickOffset = this.get("topTickOffset"),
              ttl = Math.round(topTickOffset + totalLabelSize + totalTitleSize);
          if(this._explicitHeight)
          {
             ttl = this._explicitHeight;
          }
          host.set("calculatedHeight", ttl);
          graphic.set("y", ttl - topTickOffset);
      }
  };
  Y.TopAxisLayout = TopAxisLayout;
  
  /**
   * An abstract class that provides the core functionality for draw a chart axis. Axis is used by the following classes:
   * <ul>
   *      <li>{{#crossLink "CategoryAxis"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "NumericAxis"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "StackedAxis"}}{{/crossLink}}</li>
   *      <li>{{#crossLink "TimeAxis"}}{{/crossLink}}</li>
   *  </ul>
   *
   * @class Axis
   * @extends Widget
   * @uses AxisBase
   * @uses TopAxisLayout
   * @uses RightAxisLayout
   * @uses BottomAxisLayout
   * @uses LeftAxisLayout
   * @constructor
   * @param {Object} config (optional) Configuration parameters.
   * @submodule axis
   */
  Y.Axis = Y.Base.create("axis", Y.Widget, [Y.AxisBase], {
      /**
       * Calculates and returns a value based on the number of labels and the index of
       * the current label.
       *
       * @method getLabelByIndex
       * @param {Number} i Index of the label.
       * @param {Number} l Total number of labels.
       * @return String
       */
      getLabelByIndex: function(i, l)
      {
          var position = this.get("position"),
              direction = position === "left" || position === "right" ? "vertical" : "horizontal";
          return this._getLabelByIndex(i, l, direction);
      },
  
      /**
       * @method bindUI
       * @private
       */
      bindUI: function()
      {
          this.after("dataReady", Y.bind(this._dataChangeHandler, this));
          this.after("dataUpdate", Y.bind(this._dataChangeHandler, this));
          this.after("stylesChange", this._updateHandler);
          this.after("overlapGraphChange", this._updateHandler);
          this.after("positionChange", this._positionChangeHandler);
          this.after("widthChange", this._handleSizeChange);
          this.after("heightChange", this._handleSizeChange);
          this.after("calculatedWidthChange", this._handleSizeChange);
          this.after("calculatedHeightChange", this._handleSizeChange);
      },
      /**
       * Storage for calculatedWidth value.
       *
       * @property _calculatedWidth
       * @type Number
       * @private
       */
      _calculatedWidth: 0,
  
      /**
       * Storage for calculatedHeight value.
       *
       * @property _calculatedHeight
       * @type Number
       * @private
       */
      _calculatedHeight: 0,
  
      /**
       * Handles change to the dataProvider
       *
       * @method _dataChangeHandler
       * @param {Object} e Event object
       * @private
       */
      _dataChangeHandler: function()
      {
          if(this.get("rendered"))
          {
              this._drawAxis();
          }
      },
  
      /**
       * Handles change to the position attribute
       *
       * @method _positionChangeHandler
       * @param {Object} e Event object
       * @private
       */
      _positionChangeHandler: function(e)
      {
          this._updateGraphic(e.newVal);
          this._updateHandler();
      },
  
      /**
       * Updates the the Graphic instance
       *
       * @method _updateGraphic
       * @param {String} position Position of axis
       * @private
       */
      _updateGraphic: function(position)
      {
          var graphic = this.get("graphic");
          if(position === "none")
          {
              if(graphic)
              {
                  graphic.destroy();
              }
          }
          else
          {
              if(!graphic)
              {
                  this._setCanvas();
              }
          }
      },
  
      /**
       * Handles changes to axis.
       *
       * @method _updateHandler
       * @param {Object} e Event object
       * @private
       */
      _updateHandler: function()
      {
          if(this.get("rendered"))
          {
              this._drawAxis();
          }
      },
  
      /**
       * @method renderUI
       * @private
       */
      renderUI: function()
      {
          this._updateGraphic(this.get("position"));
      },
  
      /**
       * @method syncUI
       * @private
       */
      syncUI: function()
      {
          var layout = this._layout,
              defaultMargins,
              styles,
              label,
              title,
              i;
          if(layout)
          {
              defaultMargins = layout._getDefaultMargins();
              styles = this.get("styles");
              label = styles.label.margin;
              title =styles.title.margin;
              //need to defaultMargins method to the layout classes.
              for(i in defaultMargins)
              {
                  if(defaultMargins.hasOwnProperty(i))
                  {
                      label[i] = label[i] === undefined ? defaultMargins[i] : label[i];
                      title[i] = title[i] === undefined ? defaultMargins[i] : title[i];
                  }
              }
          }
          this._drawAxis();
      },
  
      /**
       * Creates a graphic instance to be used for the axis line and ticks.
       *
       * @method _setCanvas
       * @private
       */
      _setCanvas: function()
      {
          var cb = this.get("contentBox"),
              bb = this.get("boundingBox"),
              p = this.get("position"),
              pn = this._parentNode,
              w = this.get("width"),
              h = this.get("height");
          bb.setStyle("position", "absolute");
          bb.setStyle("zIndex", 2);
          w = w ? w + "px" : pn.getStyle("width");
          h = h ? h + "px" : pn.getStyle("height");
          if(p === "top" || p === "bottom")
          {
              cb.setStyle("width", w);
          }
          else
          {
              cb.setStyle("height", h);
          }
          cb.setStyle("position", "relative");
          cb.setStyle("left", "0px");
          cb.setStyle("top", "0px");
          this.set("graphic", new Y.Graphic());
          this.get("graphic").render(cb);
      },
  
      /**
       * Gets the default value for the `styles` attribute. Overrides
       * base implementation.
       *
       * @method _getDefaultStyles
       * @return Object
       * @protected
       */
      _getDefaultStyles: function()
      {
          var axisstyles = {
              majorTicks: {
                  display:"inside",
                  length:4,
                  color:"#dad8c9",
                  weight:1,
                  alpha:1
              },
              minorTicks: {
                  display:"none",
                  length:2,
                  color:"#dad8c9",
                  weight:1
              },
              line: {
                  weight:1,
                  color:"#dad8c9",
                  alpha:1
              },
              majorUnit: {
                  determinant:"count",
                  count:11,
                  distance:75
              },
              top: "0px",
              left: "0px",
              width: "100px",
              height: "100px",
              label: {
                  color:"#808080",
                  alpha: 1,
                  fontSize:"85%",
                  rotation: 0,
                  offset: 0.5,
                  margin: {
                      top: undefined,
                      right: undefined,
                      bottom: undefined,
                      left: undefined
                  }
              },
              title: {
                  color:"#808080",
                  alpha: 1,
                  fontSize:"85%",
                  rotation: undefined,
                  margin: {
                      top: undefined,
                      right: undefined,
                      bottom: undefined,
                      left: undefined
                  }
              },
              hideOverlappingLabelTicks: false
          };
  
          return Y.merge(Y.Renderer.prototype._getDefaultStyles(), axisstyles);
      },
  
      /**
       * Updates the axis when the size changes.
       *
       * @method _handleSizeChange
       * @param {Object} e Event object.
       * @private
       */
      _handleSizeChange: function(e)
      {
          var attrName = e.attrName,
              pos = this.get("position"),
              vert = pos === "left" || pos === "right",
              cb = this.get("contentBox"),
              hor = pos === "bottom" || pos === "top";
          cb.setStyle("width", this.get("width"));
          cb.setStyle("height", this.get("height"));
          if((hor && attrName === "width") || (vert && attrName === "height"))
          {
              this._drawAxis();
          }
      },
  
      /**
       * Maps key values to classes containing layout algorithms
       *
       * @property _layoutClasses
       * @type Object
       * @private
       */
      _layoutClasses:
      {
          top : TopAxisLayout,
          bottom: BottomAxisLayout,
          left: LeftAxisLayout,
          right : RightAxisLayout
      },
  
      /**
       * Draws a line segment between 2 points
       *
       * @method drawLine
       * @param {Object} startPoint x and y coordinates for the start point of the line segment
       * @param {Object} endPoint x and y coordinates for the for the end point of the line segment
       * @param {Object} line styles (weight, color and alpha to be applied to the line segment)
       * @private
       */
      drawLine: function(path, startPoint, endPoint)
      {
          path.moveTo(startPoint.x, startPoint.y);
          path.lineTo(endPoint.x, endPoint.y);
      },
  
      /**
       * Generates the properties necessary for rotating and positioning a text field.
       *
       * @method _getTextRotationProps
       * @param {Object} styles properties for the text field
       * @return Object
       * @private
       */
      _getTextRotationProps: function(styles)
      {
          if(styles.rotation === undefined)
          {
              switch(this.get("position"))
              {
                  case "left" :
                      styles.rotation = -90;
                  break;
                  case "right" :
                      styles.rotation = 90;
                  break;
                  default :
                      styles.rotation = 0;
                  break;
              }
          }
          var rot =  Math.min(90, Math.max(-90, styles.rotation)),
              absRot = Math.abs(rot),
              radCon = Math.PI/180,
              sinRadians = parseFloat(parseFloat(Math.sin(absRot * radCon)).toFixed(8)),
              cosRadians = parseFloat(parseFloat(Math.cos(absRot * radCon)).toFixed(8));
          return {
              rot: rot,
              absRot: absRot,
              radCon: radCon,
              sinRadians: sinRadians,
              cosRadians: cosRadians,
              textAlpha: styles.alpha
          };
      },
  
      /**
       * Draws an axis.
       *
       * @method _drawAxis
       * @private
       */
      _drawAxis: function ()
      {
          if(this._drawing)
          {
              this._callLater = true;
              return;
          }
          this._drawing = true;
          this._callLater = false;
          if(this._layout)
          {
              var styles = this.get("styles"),
                  line = styles.line,
                  labelStyles = styles.label,
                  majorTickStyles = styles.majorTicks,
                  drawTicks = majorTickStyles.display !== "none",
                  len,
                  i = 0,
                  layout = this._layout,
                  layoutLength,
                  lineStart,
                  label,
                  labelWidth,
                  labelHeight,
                  labelFunction = this.get("labelFunction"),
                  labelFunctionScope = this.get("labelFunctionScope"),
                  labelFormat = this.get("labelFormat"),
                  graphic = this.get("graphic"),
                  path = this.get("path"),
                  tickPath,
                  explicitlySized,
                  position = this.get("position"),
                  labelData,
                  labelValues,
                  point,
                  points,
                  firstPoint,
                  lastPoint,
                  firstLabel,
                  lastLabel,
                  staticCoord,
                  dynamicCoord,
                  edgeOffset,
                  explicitLabels = this._labelValuesExplicitlySet ? this.get("labelValues") : null,
                  direction = (position === "left" || position === "right") ? "vertical" : "horizontal";
              this._labelWidths = [];
              this._labelHeights = [];
              graphic.set("autoDraw", false);
              path.clear();
              path.set("stroke", {
                  weight: line.weight,
                  color: line.color,
                  opacity: line.alpha
              });
              this._labelRotationProps = this._getTextRotationProps(labelStyles);
              this._labelRotationProps.transformOrigin = layout._getTransformOrigin(this._labelRotationProps.rot);
              layout.setTickOffsets.apply(this);
              layoutLength = this.getLength();
  
              len = this.getTotalMajorUnits();
              edgeOffset = this.getEdgeOffset(len, layoutLength);
              this.set("edgeOffset", edgeOffset);
              lineStart = layout.getLineStart.apply(this);
  
              if(direction === "vertical")
              {
                  staticCoord = "x";
                  dynamicCoord = "y";
              }
              else
              {
                  staticCoord = "y";
                  dynamicCoord = "x";
              }
  
              labelData = this._getLabelData(
                  lineStart[staticCoord],
                  staticCoord,
                  dynamicCoord,
                  this.get("minimum"),
                  this.get("maximum"),
                  edgeOffset,
                  layoutLength - edgeOffset - edgeOffset,
                  len,
                  explicitLabels
              );
  
              points = labelData.points;
              labelValues = labelData.values;
              len = points.length;
              if(!this._labelValuesExplicitlySet)
              {
                  this.set("labelValues", labelValues, {src: "internal"});
              }
  
              //Don't create the last label or tick.
              if(this.get("hideFirstMajorUnit"))
              {
                  firstPoint = points.shift();
                  firstLabel = labelValues.shift();
                  len = len - 1;
              }
  
              //Don't create the last label or tick.
              if(this.get("hideLastMajorUnit"))
              {
                  lastPoint = points.pop();
                  lastLabel = labelValues.pop();
                  len = len - 1;
              }
  
              if(len < 1)
              {
                  this._clearLabelCache();
              }
              else
              {
                  this.drawLine(path, lineStart, this.getLineEnd(lineStart));
                  if(drawTicks)
                  {
                      tickPath = this.get("tickPath");
                      tickPath.clear();
                      tickPath.set("stroke", {
                          weight: majorTickStyles.weight,
                          color: majorTickStyles.color,
                          opacity: majorTickStyles.alpha
                      });
                      for(i = 0; i < len; i = i + 1)
                      {
                          point = points[i];
                          if(point)
                          {
                              layout.drawTick.apply(this, [tickPath, points[i], majorTickStyles]);
                          }
                      }
                  }
                  this._createLabelCache();
                  this._maxLabelSize = 0;
                  this._totalTitleSize = 0;
                  this._titleSize = 0;
                  this._setTitle();
                  explicitlySized = layout.getExplicitlySized.apply(this, [styles]);
                  for(i = 0; i < len; i = i + 1)
                  {
                      point = points[i];
                      if(point)
                      {
                          label = this.getLabel(labelStyles);
                          this._labels.push(label);
                          this.get("appendLabelFunction")(label, labelFunction.apply(labelFunctionScope, [labelValues[i], labelFormat]));
                          labelWidth = Math.round(label.offsetWidth);
                          labelHeight = Math.round(label.offsetHeight);
                          if(!explicitlySized)
                          {
                              this._layout.updateMaxLabelSize.apply(this, [labelWidth, labelHeight]);
                          }
                          this._labelWidths.push(labelWidth);
                          this._labelHeights.push(labelHeight);
                      }
                  }
                  this._clearLabelCache();
                  if(this.get("overlapGraph"))
                  {
                     layout.offsetNodeForTick.apply(this, [this.get("contentBox")]);
                  }
                  layout.setCalculatedSize.apply(this);
                  if(this._titleTextField)
                  {
                      this._layout.positionTitle.apply(this, [this._titleTextField]);
                  }
                  len = this._labels.length;
                  for(i = 0; i < len; ++i)
                  {
                      layout.positionLabel.apply(this, [this.get("labels")[i], points[i], styles, i]);
                  }
                  if(firstPoint)
                  {
                      points.unshift(firstPoint);
                  }
                  if(lastPoint)
                  {
                      points.push(lastPoint);
                  }
                  if(firstLabel)
                  {
                      labelValues.unshift(firstLabel);
                  }
                  if(lastLabel)
                  {
                      labelValues.push(lastLabel);
                  }
                  this._tickPoints = points;
              }
          }
          this._drawing = false;
          if(this._callLater)
          {
              this._drawAxis();
          }
          else
          {
              this._updatePathElement();
              this.fire("axisRendered");
          }
      },
  
      /**
       * Calculates and sets the total size of a title.
       *
       * @method _setTotalTitleSize
       * @param {Object} styles Properties for the title field.
       * @private
       */
      _setTotalTitleSize: function(styles)
      {
          var title = this._titleTextField,
              w = title.offsetWidth,
              h = title.offsetHeight,
              rot = this._titleRotationProps.rot,
              bounds,
              size,
              margin = styles.margin,
              position = this.get("position"),
              matrix = new Y.Matrix();
          matrix.rotate(rot);
          bounds = matrix.getContentRect(w, h);
          if(position === "left" || position === "right")
          {
              size = bounds.right - bounds.left;
              if(margin)
              {
                  size += margin.left + margin.right;
              }
          }
          else
          {
              size = bounds.bottom - bounds.top;
              if(margin)
              {
                  size += margin.top + margin.bottom;
              }
          }
          this._titleBounds = bounds;
          this._totalTitleSize = size;
      },
  
      /**
       *  Updates path.
       *
       *  @method _updatePathElement
       *  @private
       */
      _updatePathElement: function()
      {
          var path = this._path,
              tickPath = this._tickPath,
              redrawGraphic = false,
              graphic = this.get("graphic");
          if(path)
          {
              redrawGraphic = true;
              path.end();
          }
          if(tickPath)
          {
              redrawGraphic = true;
              tickPath.end();
          }
          if(redrawGraphic)
          {
              graphic._redraw();
          }
      },
  
      /**
       * Updates the content and style properties for a title field.
       *
       * @method _updateTitle
       * @private
       */
      _setTitle: function()
      {
          var i,
              styles,
              customStyles,
              title = this.get("title"),
              titleTextField = this._titleTextField,
              parentNode;
          if(title !== null && title !== undefined)
          {
              customStyles = {
                      rotation: "rotation",
                      margin: "margin",
                      alpha: "alpha"
              };
              styles = this.get("styles").title;
              if(!titleTextField)
              {
                  titleTextField = DOCUMENT.createElement('span');
                  titleTextField.style.display = "block";
                  titleTextField.style.whiteSpace = "nowrap";
                  titleTextField.setAttribute("class", "axisTitle");
                  this.get("contentBox").append(titleTextField);
              }
              else if(!DOCUMENT.createElementNS)
              {
                  if(titleTextField.style.filter)
                  {
                      titleTextField.style.filter = null;
                  }
              }
              titleTextField.style.position = "absolute";
              for(i in styles)
              {
                  if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
                  {
                      titleTextField.style[i] = styles[i];
                  }
              }
              this.get("appendTitleFunction")(titleTextField, title);
              this._titleTextField = titleTextField;
              this._titleRotationProps = this._getTextRotationProps(styles);
              this._setTotalTitleSize(styles);
          }
          else if(titleTextField)
          {
              parentNode = titleTextField.parentNode;
              if(parentNode)
              {
                  parentNode.removeChild(titleTextField);
              }
              this._titleTextField = null;
              this._totalTitleSize = 0;
          }
      },
  
      /**
       * Creates or updates an axis label.
       *
       * @method getLabel
       * @param {Object} styles styles applied to label
       * @return HTMLElement
       * @private
       */
      getLabel: function(styles)
      {
          var i,
              label,
              labelCache = this._labelCache,
              customStyles = {
                  rotation: "rotation",
                  margin: "margin",
                  alpha: "alpha"
              };
          if(labelCache && labelCache.length > 0)
          {
              label = labelCache.shift();
          }
          else
          {
              label = DOCUMENT.createElement("span");
              label.className = Y.Lang.trim([label.className, "axisLabel"].join(' '));
              this.get("contentBox").append(label);
          }
          if(!DOCUMENT.createElementNS)
          {
              if(label.style.filter)
              {
                  label.style.filter = null;
              }
          }
          label.style.display = "block";
          label.style.whiteSpace = "nowrap";
          label.style.position = "absolute";
          for(i in styles)
          {
              if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
              {
                  label.style[i] = styles[i];
              }
          }
          return label;
      },
  
      /**
       * Creates a cache of labels that can be re-used when the axis redraws.
       *
       * @method _createLabelCache
       * @private
       */
      _createLabelCache: function()
      {
          if(this._labels)
          {
              while(this._labels.length > 0)
              {
                  this._labelCache.push(this._labels.shift());
              }
          }
          else
          {
              this._clearLabelCache();
          }
          this._labels = [];
      },
  
      /**
       * Removes axis labels from the dom and clears the label cache.
       *
       * @method _clearLabelCache
       * @private
       */
      _clearLabelCache: function()
      {
          if(this._labelCache)
          {
              var len = this._labelCache.length,
                  i = 0,
                  label;
              for(; i < len; ++i)
              {
                  label = this._labelCache[i];
                  this._removeChildren(label);
                  Y.Event.purgeElement(label, true);
                  label.parentNode.removeChild(label);
              }
          }
          this._labelCache = [];
      },
  
      /**
       * Gets the end point of an axis.
       *
       * @method getLineEnd
       * @return Object
       * @private
       */
      getLineEnd: function(pt)
      {
          var w = this.get("width"),
              h = this.get("height"),
              pos = this.get("position");
          if(pos === "top" || pos === "bottom")
          {
              return {x:w, y:pt.y};
          }
          else
          {
              return {x:pt.x, y:h};
          }
      },
  
      /**
       * Calcuates the width or height of an axis depending on its direction.
       *
       * @method getLength
       * @return Number
       * @private
       */
      getLength: function()
      {
          var l,
              style = this.get("styles"),
              padding = style.padding,
              w = this.get("width"),
              h = this.get("height"),
              pos = this.get("position");
          if(pos === "top" || pos === "bottom")
          {
              l = w - (padding.left + padding.right);
          }
          else
          {
              l = h - (padding.top + padding.bottom);
          }
          return l;
      },
  
      /**
       * Gets the position of the first point on an axis.
       *
       * @method getFirstPoint
       * @param {Object} pt Object containing x and y coordinates.
       * @return Object
       * @private
       */
      getFirstPoint:function(pt)
      {
          var style = this.get("styles"),
              pos = this.get("position"),
              padding = style.padding,
              np = {x:pt.x, y:pt.y};
          if(pos === "top" || pos === "bottom")
          {
              np.x += padding.left + this.get("edgeOffset");
          }
          else
          {
              np.y += this.get("height") - (padding.top + this.get("edgeOffset"));
          }
          return np;
      },
  
      /**
       * Rotates and positions a text field.
       *
       * @method _rotate
       * @param {HTMLElement} label text field to rotate and position
       * @param {Object} props properties to be applied to the text field.
       * @private
       */
      _rotate: function(label, props)
      {
          var rot = props.rot,
              x = props.x,
              y = props.y,
              filterString,
              textAlpha,
              matrix = new Y.Matrix(),
              transformOrigin = props.transformOrigin || [0, 0],
              offsetRect;
          if(DOCUMENT.createElementNS)
          {
              matrix.translate(x, y);
              matrix.rotate(rot);
              Y_DOM.setStyle(label, "transformOrigin", (transformOrigin[0] * 100) + "% " + (transformOrigin[1] * 100) + "%");
              Y_DOM.setStyle(label, "transform", matrix.toCSSText());
          }
          else
          {
              textAlpha = props.textAlpha;
              if(Y_Lang.isNumber(textAlpha) && textAlpha < 1 && textAlpha > -1 && !isNaN(textAlpha))
              {
                  filterString = "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + Math.round(textAlpha * 100) + ")";
              }
              if(rot !== 0)
              {
                  //ms filters kind of, sort of uses a transformOrigin of 0, 0.
                  //we'll translate the difference to create a true 0, 0 origin.
                  matrix.rotate(rot);
                  offsetRect = matrix.getContentRect(props.labelWidth, props.labelHeight);
                  matrix.init();
                  matrix.translate(offsetRect.left, offsetRect.top);
                  matrix.translate(x, y);
                  this._simulateRotateWithTransformOrigin(matrix, rot, transformOrigin, props.labelWidth, props.labelHeight);
                  if(filterString)
                  {
                      filterString += " ";
                  }
                  else
                  {
                      filterString = "";
                  }
                  filterString += matrix.toFilterText();
                  label.style.left = matrix.dx + "px";
                  label.style.top = matrix.dy + "px";
              }
              else
              {
                  label.style.left = x + "px";
                  label.style.top = y + "px";
              }
              if(filterString)
              {
                  label.style.filter = filterString;
              }
          }
      },
  
      /**
       * Simulates a rotation with a specified transformOrigin.
       *
       * @method _simulateTransformOrigin
       * @param {Matrix} matrix Reference to a `Matrix` instance.
       * @param {Number} rot The rotation (in degrees) that will be performed on a matrix.
       * @param {Array} transformOrigin An array represeniting the origin in which to perform the transform. The first
       * index represents the x origin and the second index represents the y origin.
       * @param {Number} w The width of the object that will be transformed.
       * @param {Number} h The height of the object that will be transformed.
       * @private
       */
      _simulateRotateWithTransformOrigin: function(matrix, rot, transformOrigin, w, h)
      {
          var transformX = transformOrigin[0] * w,
              transformY = transformOrigin[1] * h;
          transformX = !isNaN(transformX) ? transformX : 0;
          transformY = !isNaN(transformY) ? transformY : 0;
          matrix.translate(transformX, transformY);
          matrix.rotate(rot);
          matrix.translate(-transformX, -transformY);
      },
  
      /**
       * Returns the coordinates (top, right, bottom, left) for the bounding box of the last label.
       *
       * @method getMaxLabelBounds
       * @return Object
       */
      getMaxLabelBounds: function()
      {
          return this._getLabelBounds(this.getMaximumValue());
      },
  
      /**
       * Returns the coordinates (top, right, bottom, left) for the bounding box of the first label.
       *
       * @method getMinLabelBounds
       * @return Object
       */
      getMinLabelBounds: function()
      {
          return this._getLabelBounds(this.getMinimumValue());
      },
  
      /**
       * Returns the coordinates (top, right, bottom, left) for the bounding box of a label.
       *
       * @method _getLabelBounds
       * @param {String} Value of the label
       * @return Object
       * @private
       */
      _getLabelBounds: function(val)
      {
          var layout = this._layout,
              labelStyles = this.get("styles").label,
              matrix = new Y.Matrix(),
              label,
              props = this._getTextRotationProps(labelStyles);
              props.transformOrigin = layout._getTransformOrigin(props.rot);
          label = this.getLabel(labelStyles);
          this.get("appendLabelFunction")(label, this.get("labelFunction").apply(this, [val, this.get("labelFormat")]));
          props.labelWidth = label.offsetWidth;
          props.labelHeight = label.offsetHeight;
          this._removeChildren(label);
          Y.Event.purgeElement(label, true);
          label.parentNode.removeChild(label);
          props.x = 0;
          props.y = 0;
          layout._setRotationCoords(props);
          matrix.translate(props.x, props.y);
          this._simulateRotateWithTransformOrigin(matrix, props.rot, props.transformOrigin, props.labelWidth, props.labelHeight);
          return matrix.getContentRect(props.labelWidth, props.labelHeight);
      },
  
      /**
       * Removes all DOM elements from an HTML element. Used to clear out labels during detruction
       * phase.
       *
       * @method _removeChildren
       * @private
       */
      _removeChildren: function(node)
      {
          if(node.hasChildNodes())
          {
              var child;
              while(node.firstChild)
              {
                  child = node.firstChild;
                  this._removeChildren(child);
                  node.removeChild(child);
              }
          }
      },
  
      /**
       * Destructor implementation Axis class. Removes all labels and the Graphic instance from the widget.
       *
       * @method destructor
       * @protected
       */
      destructor: function()
      {
          var cb = this.get("contentBox").getDOMNode(),
              labels = this.get("labels"),
              graphic = this.get("graphic"),
              label,
              len = labels ? labels.length : 0;
          if(len > 0)
          {
              while(labels.length > 0)
              {
                  label = labels.shift();
                  this._removeChildren(label);
                  cb.removeChild(label);
                  label = null;
              }
          }
          if(graphic)
          {
              graphic.destroy();
          }
      },
  
      /**
       * Length in pixels of largest text bounding box. Used to calculate the height of the axis.
       *
       * @property maxLabelSize
       * @type Number
       * @protected
       */
      _maxLabelSize: 0,
  
      /**
       * Updates the content of text field. This method writes a value into a text field using
       * `appendChild`. If the value is a `String`, it is converted to a `TextNode` first.
       *
       * @method _setText
       * @param label {HTMLElement} label to be updated
       * @param val {String} value with which to update the label
       * @private
       */
      _setText: function(textField, val)
      {
          textField.innerHTML = "";
          if(Y_Lang.isNumber(val))
          {
              val = val + "";
          }
          else if(!val)
          {
              val = "";
          }
          if(IS_STRING(val))
          {
              val = DOCUMENT.createTextNode(val);
          }
          textField.appendChild(val);
      },
  
      /**
       * Returns the total number of majorUnits that will appear on an axis.
       *
       * @method getTotalMajorUnits
       * @return Number
       */
      getTotalMajorUnits: function()
      {
          var units,
              majorUnit = this.get("styles").majorUnit,
              len;
          if(majorUnit.determinant === "count")
          {
              units = majorUnit.count;
          }
          else if(majorUnit.determinant === "distance")
          {
              len = this.getLength();
              units = (len/majorUnit.distance) + 1;
          }
          return units;
      },
  
      /**
       * Returns the distance between major units on an axis.
       *
       * @method getMajorUnitDistance
       * @param {Number} len Number of ticks
       * @param {Number} uiLen Size of the axis.
       * @param {Object} majorUnit Hash of properties used to determine the majorUnit
       * @return Number
       */
      getMajorUnitDistance: function(len, uiLen, majorUnit)
      {
          var dist;
          if(majorUnit.determinant === "count")
          {
              if(!this.get("calculateEdgeOffset"))
              {
                  len = len - 1;
              }
              dist = uiLen/len;
          }
          else if(majorUnit.determinant === "distance")
          {
              dist = majorUnit.distance;
          }
          return dist;
      },
  
      /**
       * Checks to see if data extends beyond the range of the axis. If so,
       * that data will need to be hidden. This method is internal, temporary and subject
       * to removal in the future.
       *
       * @method _hasDataOverflow
       * @protected
       * @return Boolean
       */
      _hasDataOverflow: function()
      {
          if(this.get("setMin") || this.get("setMax"))
          {
              return true;
          }
          return false;
      },
  
      /**
       * Returns a string corresponding to the first label on an
       * axis.
       *
       * @method getMinimumValue
       * @return String
       */
      getMinimumValue: function()
      {
          return this.get("minimum");
      },
  
      /**
       * Returns a string corresponding to the last label on an
       * axis.
       *
       * @method getMaximumValue
       * @return String
       */
      getMaximumValue: function()
      {
          return this.get("maximum");
      }
  }, {
      ATTRS:
      {
          /**
           * When set, defines the width of a vertical axis instance. By default, vertical axes automatically size based
           * on their contents. When the width attribute is set, the axis will not calculate its width. When the width
           * attribute is explicitly set, axis labels will postion themselves off of the the inner edge of the axis and the
           * title, if present, will position itself off of the outer edge. If a specified width is less than the sum of
           * the axis' contents, excess content will overflow.
           *
           * @attribute width
           * @type Number
           */
          width: {
              lazyAdd: false,
  
              getter: function()
              {
                  if(this._explicitWidth)
                  {
                      return this._explicitWidth;
                  }
                  return this._calculatedWidth;
              },
  
              setter: function(val)
              {
                  this._explicitWidth = val;
                  return val;
              }
          },
  
          /**
           * When set, defines the height of a horizontal axis instance. By default, horizontal axes automatically size based
           * on their contents. When the height attribute is set, the axis will not calculate its height. When the height
           * attribute is explicitly set, axis labels will postion themselves off of the the inner edge of the axis and the
           * title, if present, will position itself off of the outer edge. If a specified height is less than the sum of
           * the axis' contents, excess content will overflow.
           *
           * @attribute height
           * @type Number
           */
          height: {
              lazyAdd: false,
  
              getter: function()
              {
                  if(this._explicitHeight)
                  {
                      return this._explicitHeight;
                  }
                  return this._calculatedHeight;
              },
  
              setter: function(val)
              {
                  this._explicitHeight = val;
                  return val;
              }
          },
  
          /**
           * Calculated value of an axis' width. By default, the value is used internally for vertical axes. If the `width`
           * attribute is explicitly set, this value will be ignored.
           *
           * @attribute calculatedWidth
           * @type Number
           * @private
           */
          calculatedWidth: {
              getter: function()
              {
                  return this._calculatedWidth;
              },
  
              setter: function(val)
              {
                  this._calculatedWidth = val;
                  return val;
              }
          },
  
          /**
           * Calculated value of an axis' height. By default, the value is used internally for horizontal axes. If the `height`
           * attribute is explicitly set, this value will be ignored.
           *
           * @attribute calculatedHeight
           * @type Number
           * @private
           */
          calculatedHeight: {
              getter: function()
              {
                  return this._calculatedHeight;
              },
  
              setter: function(val)
              {
                  this._calculatedHeight = val;
                  return val;
              }
          },
  
          /**
           * Difference between the first/last tick and edge of axis.
           *
           * @attribute edgeOffset
           * @type Number
           * @protected
           */
          edgeOffset:
          {
              value: 0
          },
  
          /**
           * The graphic in which the axis line and ticks will be rendered.
           *
           * @attribute graphic
           * @type Graphic
           */
          graphic: {},
  
          /**
           *  @attribute path
           *  @type Shape
           *  @readOnly
           *  @private
           */
          path: {
              readOnly: true,
  
              getter: function()
              {
                  if(!this._path)
                  {
                      var graphic = this.get("graphic");
                      if(graphic)
                      {
                          this._path = graphic.addShape({type:"path"});
                      }
                  }
                  return this._path;
              }
          },
  
          /**
           *  @attribute tickPath
           *  @type Shape
           *  @readOnly
           *  @private
           */
          tickPath: {
              readOnly: true,
  
              getter: function()
              {
                  if(!this._tickPath)
                  {
                      var graphic = this.get("graphic");
                      if(graphic)
                      {
                          this._tickPath = graphic.addShape({type:"path"});
                      }
                  }
                  return this._tickPath;
              }
          },
  
          /**
           * Contains the contents of the axis.
           *
           * @attribute node
           * @type HTMLElement
           */
          node: {},
  
          /**
           * Direction of the axis.
           *
           * @attribute position
           * @type String
           */
          position: {
              lazyAdd: false,
  
              setter: function(val)
              {
                  var LayoutClass = this._layoutClasses[val];
                  if(val && val !== "none")
                  {
                      this._layout = new LayoutClass();
                  }
                  return val;
              }
          },
  
          /**
           * Distance determined by the tick styles used to calculate the distance between the axis
           * line in relation to the top of the axis.
           *
           * @attribute topTickOffset
           * @type Number
           */
          topTickOffset: {
              value: 0
          },
  
          /**
           * Distance determined by the tick styles used to calculate the distance between the axis
           * line in relation to the bottom of the axis.
           *
           * @attribute bottomTickOffset
           * @type Number
           */
          bottomTickOffset: {
              value: 0
          },
  
          /**
           * Distance determined by the tick styles used to calculate the distance between the axis
           * line in relation to the left of the axis.
           *
           * @attribute leftTickOffset
           * @type Number
           */
          leftTickOffset: {
              value: 0
          },
  
          /**
           * Distance determined by the tick styles used to calculate the distance between the axis
           * line in relation to the right side of the axis.
           *
           * @attribute rightTickOffset
           * @type Number
           */
          rightTickOffset: {
              value: 0
          },
  
          /**
           * Collection of labels used to render the axis.
           *
           * @attribute labels
           * @type Array
           */
          labels: {
              readOnly: true,
              getter: function()
              {
                  return this._labels;
              }
          },
  
          /**
           * Collection of points used for placement of labels and ticks along the axis.
           *
           * @attribute tickPoints
           * @type Array
           */
          tickPoints: {
              readOnly: true,
  
              getter: function()
              {
                  if(this.get("position") === "none")
                  {
                      return this.get("styles").majorUnit.count;
                  }
                  return this._tickPoints;
              }
          },
  
          /**
           * Indicates whether the axis overlaps the graph. If an axis is the inner most axis on a given
           * position and the tick position is inside or cross, the axis will need to overlap the graph.
           *
           * @attribute overlapGraph
           * @type Boolean
           */
          overlapGraph: {
              value:true,
  
              validator: function(val)
              {
                  return Y_Lang.isBoolean(val);
              }
          },
  
          /**
           * Length in pixels of largest text bounding box. Used to calculate the height of the axis.
           *
           * @attribute maxLabelSize
           * @type Number
           * @protected
           */
          maxLabelSize: {
              getter: function()
              {
                  return this._maxLabelSize;
              },
  
              setter: function(val)
              {
                  this._maxLabelSize = val;
                  return val;
              }
          },
  
          /**
           *  Title for the axis. When specified, the title will display. The position of the title is determined by the axis position.
           *  <dl>
           *      <dt>top</dt><dd>Appears above the axis and it labels. The default rotation is 0.</dd>
           *      <dt>right</dt><dd>Appears to the right of the axis and its labels. The default rotation is 90.</dd>
           *      <dt>bottom</dt><dd>Appears below the axis and its labels. The default rotation is 0.</dd>
           *      <dt>left</dt><dd>Appears to the left of the axis and its labels. The default rotation is -90.</dd>
           *  </dl>
           *
           *  @attribute title
           *  @type String
           */
          title: {
              value: null
          },
  
          /**
           * Function used to append an axis value to an axis label. This function has the following signature:
           *  <dl>
           *      <dt>textField</dt><dd>The axis label to be appended. (`HTMLElement`)</dd>
           *      <dt>val</dt><dd>The value to attach to the text field. This method will accept an `HTMLELement`
           *      or a `String`. This method does not use (`HTMLElement` | `String`)</dd>
           *  </dl>
           * The default method appends a value to the `HTMLElement` using the `appendChild` method. If the given
           * value is a `String`, the method will convert the the value to a `textNode` before appending to the
           * `HTMLElement`. This method will not convert an `HTMLString` to an `HTMLElement`.
           *
           * @attribute appendLabelFunction
           * @type Function
           */
          appendLabelFunction: {
              valueFn: function()
              {
                  return this._setText;
              }
          },
  
          /**
           * Function used to append a title value to the title object. This function has the following signature:
           *  <dl>
           *      <dt>textField</dt><dd>The title text field to be appended. (`HTMLElement`)</dd>
           *      <dt>val</dt><dd>The value to attach to the text field. This method will accept an `HTMLELement`
           *      or a `String`. This method does not use (`HTMLElement` | `String`)</dd>
           *  </dl>
           * The default method appends a value to the `HTMLElement` using the `appendChild` method. If the given
           * value is a `String`, the method will convert the the value to a `textNode` before appending to the
           * `HTMLElement` element. This method will not convert an `HTMLString` to an `HTMLElement`.
           *
           * @attribute appendTitleFunction
           * @type Function
           */
          appendTitleFunction: {
              valueFn: function()
              {
                  return this._setText;
              }
          },
  
          /**
           * An array containing the unformatted values of the axis labels. By default, TimeAxis, NumericAxis and
           * StackedAxis labelValues are determined by the majorUnit style. By default, CategoryAxis labels are
           * determined by the values of the dataProvider.
           * <p>When the labelValues attribute is explicitly set, the labelValues are dictated by the set value and
           * the position of ticks and labels are determined by where those values would fall on the axis. </p>
           *
           * @attribute labelValues
           * @type Array
           */
          labelValues: {
              lazyAdd: false,
  
              setter: function(val)
              {
                  var opts = arguments[2];
                  if(!val || (opts && opts.src && opts.src === "internal"))
                  {
                      this._labelValuesExplicitlySet = false;
                  }
                  else
                  {
                      this._labelValuesExplicitlySet = true;
                  }
                  return val;
              }
          },
  
          /**
           * Suppresses the creation of the the first visible label and tick.
           *
           * @attribute hideFirstMajorUnit
           * @type Boolean
           */
          hideFirstMajorUnit: {
              value: false
          },
  
          /**
           * Suppresses the creation of the the last visible label and tick.
           *
           * @attribute hideLastMajorUnit
           * @type Boolean
           */
          hideLastMajorUnit: {
              value: false
          }
  
          /**
           * Style properties used for drawing an axis. This attribute is inherited from `Renderer`. Below are the default values:
           *  <dl>
           *      <dt>majorTicks</dt><dd>Properties used for drawing ticks.
           *          <dl>
           *              <dt>display</dt><dd>Position of the tick. Possible values are `inside`, `outside`, `cross` and `none`.
           *              The default value is `inside`.</dd>
           *              <dt>length</dt><dd>The length (in pixels) of the tick. The default value is 4.</dd>
           *              <dt>color</dt><dd>The color of the tick. The default value is `#dad8c9`</dd>
           *              <dt>weight</dt><dd>Number indicating the width of the tick. The default value is 1.</dd>
           *              <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
           *          </dl>
           *      </dd>
           *      <dt>line</dt><dd>Properties used for drawing the axis line.
           *          <dl>
           *              <dt>weight</dt><dd>Number indicating the width of the axis line. The default value is 1.</dd>
           *              <dt>color</dt><dd>The color of the axis line. The default value is `#dad8c9`.</dd>
           *              <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
           *          </dl>
           *      </dd>
           *      <dt>majorUnit</dt><dd>Properties used to calculate the `majorUnit` for the axis.
           *          <dl>
           *              <dt>determinant</dt><dd>The algorithm used for calculating distance between ticks. The possible options are
           *              `count` and `distance`. If the `determinant` is `count`, the axis ticks will spaced so that a specified number
           *              of ticks appear on the axis. If the `determinant` is `distance`, the axis ticks will spaced out according to
           *              the specified distance. The default value is `count`.</dd>
           *              <dt>count</dt><dd>Number of ticks to appear on the axis when the `determinant` is `count`. The default value is 11.</dd>
           *              <dt>distance</dt><dd>The distance (in pixels) between ticks when the `determinant` is `distance`. The default
           *              value is 75.</dd>
           *          </dl>
           *      </dd>
           *      <dt>label</dt><dd>Properties and styles applied to the axis labels.
           *          <dl>
           *              <dt>color</dt><dd>The color of the labels. The default value is `#808080`.</dd>
           *              <dt>alpha</dt><dd>Number between 0 and 1 indicating the opacity of the labels. The default value is 1.</dd>
           *              <dt>fontSize</dt><dd>The font-size of the labels. The default value is 85%</dd>
           *              <dt>rotation</dt><dd>The rotation, in degrees (between -90 and 90) of the labels. The default value is 0.</dd>
           *              <dt>offset</td><dd>A number between 0 and 1 indicating the relationship of the label to a tick. For a horizontal axis
           *              label, a value of 0 will position the label's left side even to the the tick. A position of 1 would position the
           *              right side of the label with the tick. A position of 0.5 would center the label horizontally with the tick. For a
           *              vertical axis, a value of 0 would position the top of the label with the tick, a value of 1 would position the bottom
           *              of the label with the tick and a value 0 would center the label vertically with the tick. The default value is 0.5.</dd>
           *              <dt>margin</dt><dd>The distance between the label and the axis/tick. Depending on the position of the `Axis`,
           *              only one of the properties used.
           *                  <dl>
           *                      <dt>top</dt><dd>Pixel value used for an axis with a `position` of `bottom`. The default value is 4.</dd>
           *                      <dt>right</dt><dd>Pixel value used for an axis with a `position` of `left`. The default value is 4.</dd>
           *                      <dt>bottom</dt><dd>Pixel value used for an axis with a `position` of `top`. The default value is 4.</dd>
           *                      <dt>left</dt><dd>Pixel value used for an axis with a `position` of `right`. The default value is 4.</dd>
           *                  </dl>
           *              </dd>
           *          </dl>
           *      </dd>
           *  </dl>
           *
           * @attribute styles
           * @type Object
           */
      }
  });
  Y.AxisType = Y.Base.create("baseAxis", Y.Axis, [], {});
  
  
  }, 'patched-v3.16.0', {"requires": ["dom", "widget", "widget-position", "widget-stack", "graphics", "axis-base"]});
  