[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/axis/ -> axis.js (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1