[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/charts-base/ -> charts-base-debug.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('charts-base', function (Y, NAME) {
   9  
  10  /**
  11   * Provides functionality for creating charts.
  12   *
  13   * @module charts
  14   * @submodule charts-base
  15   */
  16  var CONFIG = Y.config,
  17      WINDOW = CONFIG.win,
  18      DOCUMENT = CONFIG.doc,
  19      Y_Lang = Y.Lang,
  20      IS_STRING = Y_Lang.isString,
  21      _getClassName = Y.ClassNameManager.getClassName,
  22      SERIES_MARKER = _getClassName("seriesmarker");
  23  
  24  /**
  25   * Gridlines draws gridlines on a Graph.
  26   *
  27   * @class Gridlines
  28   * @constructor
  29   * @extends Base
  30   * @uses Renderer
  31   * @param {Object} config (optional) Configuration parameters.
  32   * @submodule charts-base
  33   */
  34  Y.Gridlines = Y.Base.create("gridlines", Y.Base, [Y.Renderer], {
  35      /**
  36       * Reference to the `Path` element used for drawing Gridlines.
  37       *
  38       * @property _path
  39       * @type Path
  40       * @private
  41       */
  42      _path: null,
  43  
  44      /**
  45       * Removes the Gridlines.
  46       *
  47       * @method remove
  48       * @private
  49       */
  50      remove: function()
  51      {
  52          var path = this._path;
  53          if(path)
  54          {
  55              path.destroy();
  56          }
  57      },
  58  
  59      /**
  60       * Draws the gridlines
  61       *
  62       * @method draw
  63       * @protected
  64       */
  65      draw: function()
  66      {
  67          if(this.get("axis") && this.get("graph"))
  68          {
  69              this._drawGridlines();
  70          }
  71      },
  72  
  73      /**
  74       * Algorithm for drawing gridlines
  75       *
  76       * @method _drawGridlines
  77       * @private
  78       */
  79      _drawGridlines: function()
  80      {
  81          var path,
  82              axis = this.get("axis"),
  83              axisPosition = axis.get("position"),
  84              points,
  85              i = 0,
  86              l,
  87              direction = this.get("direction"),
  88              graph = this.get("graph"),
  89              w = graph.get("width"),
  90              h = graph.get("height"),
  91              line = this.get("styles").line,
  92              color = line.color,
  93              weight = line.weight,
  94              alpha = line.alpha,
  95              count = this.get("count"),
  96              length,
  97              lineFunction;
  98          if(isFinite(w) && isFinite(h) && w > 0 && h > 0)
  99          {
 100              if(count && Y.Lang.isNumber(count))
 101              {
 102                  points = this._getPoints(count, w, h);
 103              }
 104              else if(axisPosition !== "none" && axis && axis.get("tickPoints"))
 105              {
 106                  points = axis.get("tickPoints");
 107              }
 108              else
 109              {
 110                  points = this._getPoints(axis.get("styles").majorUnit.count, w, h);
 111              }
 112              l = points.length;
 113              path = graph.get("gridlines");
 114              path.set("width", w);
 115              path.set("height", h);
 116              path.set("stroke", {
 117                  weight: weight,
 118                  color: color,
 119                  opacity: alpha
 120              });
 121              if(direction === "vertical")
 122              {
 123                  lineFunction = this._verticalLine;
 124                  length = h;
 125              }
 126              else
 127              {
 128                  lineFunction = this._horizontalLine;
 129                  length = w;
 130              }
 131              for(i = 0; i < l; i = i + 1)
 132              {
 133                  lineFunction(path, points[i], length);
 134              }
 135              path.end();
 136          }
 137      },
 138  
 139      /**
 140       * Calculates the coordinates for the gridlines based on a count.
 141       *
 142       * @method _getPoints
 143       * @param {Number} count Number of gridlines
 144       * @return Array
 145       * @private
 146       */
 147      _getPoints: function(count, w, h)
 148      {
 149          var i,
 150              points = [],
 151              multiplier,
 152              divisor = count - 1;
 153          for(i = 0; i < count; i = i + 1)
 154          {
 155              multiplier = i/divisor;
 156              points[i] = {
 157                  x: w * multiplier,
 158                  y: h * multiplier
 159              };
 160          }
 161          return points;
 162      },
 163  
 164      /**
 165       * Algorithm for horizontal lines.
 166       *
 167       * @method _horizontalLine
 168       * @param {Path} path Reference to path element
 169       * @param {Object} pt Coordinates corresponding to a major unit of an axis.
 170       * @param {Number} w Width of the Graph
 171       * @private
 172       */
 173      _horizontalLine: function(path, pt, w)
 174      {
 175          path.moveTo(0, pt.y);
 176          path.lineTo(w, pt.y);
 177      },
 178  
 179      /**
 180       * Algorithm for vertical lines.
 181       *
 182       * @method _verticalLine
 183       * @param {Path} path Reference to path element
 184       * @param {Object} pt Coordinates corresponding to a major unit of an axis.
 185       * @param {Number} h Height of the Graph
 186       * @private
 187       */
 188      _verticalLine: function(path, pt, h)
 189      {
 190          path.moveTo(pt.x, 0);
 191          path.lineTo(pt.x, h);
 192      },
 193  
 194      /**
 195       * Gets the default value for the `styles` attribute. Overrides
 196       * base implementation.
 197       *
 198       * @method _getDefaultStyles
 199       * @return Object
 200       * @protected
 201       */
 202      _getDefaultStyles: function()
 203      {
 204          var defs = {
 205              line: {
 206                  color:"#f0efe9",
 207                  weight: 1,
 208                  alpha: 1
 209              }
 210          };
 211          return defs;
 212      }
 213  
 214  },
 215  {
 216      ATTRS: {
 217          /**
 218           * Indicates the direction of the gridline.
 219           *
 220           * @attribute direction
 221           * @type String
 222           */
 223          direction: {},
 224  
 225          /**
 226           * Indicate the `Axis` in which to bind
 227           * the gridlines.
 228           *
 229           * @attribute axis
 230           * @type Axis
 231           */
 232          axis: {},
 233  
 234          /**
 235           * Indicates the `Graph` in which the gridlines
 236           * are drawn.
 237           *
 238           * @attribute graph
 239           * @type Graph
 240           */
 241          graph: {},
 242  
 243          /**
 244           * Indicates the number of gridlines to display. If no value is set, gridlines will equal the number of ticks in
 245           * the corresponding axis.
 246           *
 247           * @attribute count
 248           * @type Number
 249           */
 250          count: {}
 251      }
 252  });
 253  /**
 254   * Graph manages and contains series instances for a `CartesianChart`
 255   * instance.
 256   *
 257   * @class Graph
 258   * @constructor
 259   * @extends Widget
 260   * @uses Renderer
 261   * @submodule charts-base
 262   */
 263  Y.Graph = Y.Base.create("graph", Y.Widget, [Y.Renderer], {
 264      /**
 265       * @method bindUI
 266       * @private
 267       */
 268      bindUI: function()
 269      {
 270          var bb = this.get("boundingBox");
 271          bb.setStyle("position", "absolute");
 272          this.after("widthChange", this._sizeChangeHandler);
 273          this.after("heightChange", this._sizeChangeHandler);
 274          this.after("stylesChange", this._updateStyles);
 275          this.after("groupMarkersChange", this._drawSeries);
 276      },
 277  
 278      /**
 279       * @method syncUI
 280       * @private
 281       */
 282      syncUI: function()
 283      {
 284          var background,
 285              cb,
 286              bg,
 287              sc = this.get("seriesCollection"),
 288              series,
 289              i = 0,
 290              len = sc ? sc.length : 0,
 291              hgl = this.get("horizontalGridlines"),
 292              vgl = this.get("verticalGridlines");
 293          if(this.get("showBackground"))
 294          {
 295              background = this.get("background");
 296              cb = this.get("contentBox");
 297              bg = this.get("styles").background;
 298              bg.stroke = bg.border;
 299              bg.stroke.opacity = bg.stroke.alpha;
 300              bg.fill.opacity = bg.fill.alpha;
 301              bg.width = this.get("width");
 302              bg.height = this.get("height");
 303              bg.type = bg.shape;
 304              background.set(bg);
 305          }
 306          for(; i < len; ++i)
 307          {
 308              series = sc[i];
 309              if(series instanceof Y.SeriesBase)
 310              {
 311                  series.render();
 312              }
 313          }
 314          if(hgl && hgl instanceof Y.Gridlines)
 315          {
 316              hgl.draw();
 317          }
 318          if(vgl && vgl instanceof Y.Gridlines)
 319          {
 320              vgl.draw();
 321          }
 322      },
 323  
 324      /**
 325       * Object of arrays containing series mapped to a series type.
 326       *
 327       * @property seriesTypes
 328       * @type Object
 329       * @private
 330       */
 331      seriesTypes: null,
 332  
 333      /**
 334       * Returns a series instance based on an index.
 335       *
 336       * @method getSeriesByIndex
 337       * @param {Number} val index of the series
 338       * @return CartesianSeries
 339       */
 340      getSeriesByIndex: function(val)
 341      {
 342          var col = this.get("seriesCollection"),
 343              series;
 344          if(col && col.length > val)
 345          {
 346              series = col[val];
 347          }
 348          return series;
 349      },
 350  
 351      /**
 352       * Returns a series instance based on a key value.
 353       *
 354       * @method getSeriesByKey
 355       * @param {String} val key value of the series
 356       * @return CartesianSeries
 357       */
 358      getSeriesByKey: function(val)
 359      {
 360          var obj = this._seriesDictionary,
 361              series;
 362          if(obj && obj.hasOwnProperty(val))
 363          {
 364              series = obj[val];
 365          }
 366          return series;
 367      },
 368  
 369      /**
 370       * Adds dispatcher to a `_dispatcher` used to
 371       * to ensure all series have redrawn before for firing event.
 372       *
 373       * @method addDispatcher
 374       * @param {CartesianSeries} val series instance to add
 375       * @protected
 376       */
 377      addDispatcher: function(val)
 378      {
 379          if(!this._dispatchers)
 380          {
 381              this._dispatchers = [];
 382          }
 383          this._dispatchers.push(val);
 384      },
 385  
 386      /**
 387       * Collection of series to be displayed in the graph.
 388       *
 389       * @property _seriesCollection
 390       * @type Array
 391       * @private
 392       */
 393      _seriesCollection: null,
 394  
 395      /**
 396       * Object containing key value pairs of `CartesianSeries` instances.
 397       *
 398       * @property _seriesDictionary
 399       * @type Object
 400       * @private
 401       */
 402      _seriesDictionary: null,
 403  
 404      /**
 405       * Parses series instances to be displayed in the graph.
 406       *
 407       * @method _parseSeriesCollection
 408       * @param {Array} Collection of `CartesianSeries` instances or objects container `CartesianSeries` attributes values.
 409       * @private
 410       */
 411      _parseSeriesCollection: function(val)
 412      {
 413          if(!val)
 414          {
 415              return;
 416          }
 417          var len = val.length,
 418              i = 0,
 419              series,
 420              seriesKey;
 421          this._seriesCollection = [];
 422          this._seriesDictionary = {};
 423          this.seriesTypes = [];
 424          for(; i < len; ++i)
 425          {
 426              series = val[i];
 427              if(!(series instanceof Y.CartesianSeries) && !(series instanceof Y.PieSeries))
 428              {
 429                  this._createSeries(series);
 430                  continue;
 431              }
 432              this._addSeries(series);
 433          }
 434          len = this._seriesCollection.length;
 435          for(i = 0; i < len; ++i)
 436          {
 437              series = this.get("seriesCollection")[i];
 438              seriesKey = series.get("direction") === "horizontal" ? "yKey" : "xKey";
 439              this._seriesDictionary[series.get(seriesKey)] = series;
 440          }
 441      },
 442  
 443      /**
 444       * Adds a series to the graph.
 445       *
 446       * @method _addSeries
 447       * @param {CartesianSeries} series Series to add to the graph.
 448       * @private
 449       */
 450      _addSeries: function(series)
 451      {
 452          var type = series.get("type"),
 453              seriesCollection = this.get("seriesCollection"),
 454              graphSeriesLength = seriesCollection.length,
 455              seriesTypes = this.seriesTypes,
 456              typeSeriesCollection;
 457          if(!series.get("graph"))
 458          {
 459              series.set("graph", this);
 460          }
 461          seriesCollection.push(series);
 462          if(!seriesTypes.hasOwnProperty(type))
 463          {
 464              this.seriesTypes[type] = [];
 465          }
 466          typeSeriesCollection = this.seriesTypes[type];
 467          series.set("graphOrder", graphSeriesLength);
 468          series.set("order", typeSeriesCollection.length);
 469          typeSeriesCollection.push(series);
 470          series.set("seriesTypeCollection", typeSeriesCollection);
 471          this.addDispatcher(series);
 472          series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
 473          this.fire("seriesAdded", series);
 474      },
 475  
 476      /**
 477       * Creates a `CartesianSeries` instance from an object containing attribute key value pairs. The key value pairs include
 478       * attributes for the specific series and a type value which defines the type of series to be used.
 479       *
 480       * @method createSeries
 481       * @param {Object} seriesData Series attribute key value pairs.
 482       * @private
 483       */
 484      _createSeries: function(seriesData)
 485      {
 486          var type = seriesData.type,
 487              seriesCollection = this.get("seriesCollection"),
 488              seriesTypes = this.seriesTypes,
 489              typeSeriesCollection,
 490              SeriesClass,
 491              series;
 492              seriesData.graph = this;
 493          if(!seriesTypes.hasOwnProperty(type))
 494          {
 495              seriesTypes[type] = [];
 496          }
 497          typeSeriesCollection = seriesTypes[type];
 498          seriesData.graph = this;
 499          seriesData.order = typeSeriesCollection.length;
 500          seriesData.graphOrder = seriesCollection.length;
 501          SeriesClass = this._getSeries(seriesData.type);
 502          series = new SeriesClass(seriesData);
 503          this.addDispatcher(series);
 504          series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
 505          typeSeriesCollection.push(series);
 506          seriesCollection.push(series);
 507          series.set("seriesTypeCollection", typeSeriesCollection);
 508          if(this.get("rendered"))
 509          {
 510              series.render();
 511          }
 512      },
 513  
 514      /**
 515       * String reference for pre-defined `Series` classes.
 516       *
 517       * @property _seriesMap
 518       * @type Object
 519       * @private
 520       */
 521      _seriesMap: {
 522          line : Y.LineSeries,
 523          column : Y.ColumnSeries,
 524          bar : Y.BarSeries,
 525          area :  Y.AreaSeries,
 526          candlestick : Y.CandlestickSeries,
 527          ohlc : Y.OHLCSeries,
 528          stackedarea : Y.StackedAreaSeries,
 529          stackedline : Y.StackedLineSeries,
 530          stackedcolumn : Y.StackedColumnSeries,
 531          stackedbar : Y.StackedBarSeries,
 532          markerseries : Y.MarkerSeries,
 533          spline : Y.SplineSeries,
 534          areaspline : Y.AreaSplineSeries,
 535          stackedspline : Y.StackedSplineSeries,
 536          stackedareaspline : Y.StackedAreaSplineSeries,
 537          stackedmarkerseries : Y.StackedMarkerSeries,
 538          pie : Y.PieSeries,
 539          combo : Y.ComboSeries,
 540          stackedcombo : Y.StackedComboSeries,
 541          combospline : Y.ComboSplineSeries,
 542          stackedcombospline : Y.StackedComboSplineSeries
 543      },
 544  
 545      /**
 546       * Returns a specific `CartesianSeries` class based on key value from a look up table of a direct reference to a
 547       * class. When specifying a key value, the following options are available:
 548       *
 549       *  <table>
 550       *      <tr><th>Key Value</th><th>Class</th></tr>
 551       *      <tr><td>line</td><td>Y.LineSeries</td></tr>
 552       *      <tr><td>column</td><td>Y.ColumnSeries</td></tr>
 553       *      <tr><td>bar</td><td>Y.BarSeries</td></tr>
 554       *      <tr><td>area</td><td>Y.AreaSeries</td></tr>
 555       *      <tr><td>stackedarea</td><td>Y.StackedAreaSeries</td></tr>
 556       *      <tr><td>stackedline</td><td>Y.StackedLineSeries</td></tr>
 557       *      <tr><td>stackedcolumn</td><td>Y.StackedColumnSeries</td></tr>
 558       *      <tr><td>stackedbar</td><td>Y.StackedBarSeries</td></tr>
 559       *      <tr><td>markerseries</td><td>Y.MarkerSeries</td></tr>
 560       *      <tr><td>spline</td><td>Y.SplineSeries</td></tr>
 561       *      <tr><td>areaspline</td><td>Y.AreaSplineSeries</td></tr>
 562       *      <tr><td>stackedspline</td><td>Y.StackedSplineSeries</td></tr>
 563       *      <tr><td>stackedareaspline</td><td>Y.StackedAreaSplineSeries</td></tr>
 564       *      <tr><td>stackedmarkerseries</td><td>Y.StackedMarkerSeries</td></tr>
 565       *      <tr><td>pie</td><td>Y.PieSeries</td></tr>
 566       *      <tr><td>combo</td><td>Y.ComboSeries</td></tr>
 567       *      <tr><td>stackedcombo</td><td>Y.StackedComboSeries</td></tr>
 568       *      <tr><td>combospline</td><td>Y.ComboSplineSeries</td></tr>
 569       *      <tr><td>stackedcombospline</td><td>Y.StackedComboSplineSeries</td></tr>
 570       *  </table>
 571       *
 572       * When referencing a class directly, you can specify any of the above classes or any custom class that extends
 573       * `CartesianSeries` or `PieSeries`.
 574       *
 575       * @method _getSeries
 576       * @param {String | Object} type Series type.
 577       * @return CartesianSeries
 578       * @private
 579       */
 580      _getSeries: function(type)
 581      {
 582          var seriesClass;
 583          if(Y_Lang.isString(type))
 584          {
 585              seriesClass = this._seriesMap[type];
 586          }
 587          else
 588          {
 589              seriesClass = type;
 590          }
 591          return seriesClass;
 592      },
 593  
 594      /**
 595       * Event handler for marker events.
 596       *
 597       * @method _markerEventHandler
 598       * @param {Object} e Event object.
 599       * @private
 600       */
 601      _markerEventHandler: function(e)
 602      {
 603          var type = e.type,
 604              markerNode = e.currentTarget,
 605              strArr = markerNode.getAttribute("id").split("_"),
 606              series = this.getSeriesByIndex(strArr[1]),
 607              index = strArr[2];
 608          series.updateMarkerState(type, index);
 609      },
 610  
 611      /**
 612       * Collection of `CartesianSeries` instances to be redrawn.
 613       *
 614       * @property _dispatchers
 615       * @type Array
 616       * @private
 617       */
 618      _dispatchers: null,
 619  
 620      /**
 621       * Updates the `Graph` styles.
 622       *
 623       * @method _updateStyles
 624       * @private
 625       */
 626      _updateStyles: function()
 627      {
 628          var styles = this.get("styles").background,
 629              border = styles.border;
 630              border.opacity = border.alpha;
 631              styles.stroke = border;
 632              styles.fill.opacity = styles.fill.alpha;
 633          this.get("background").set(styles);
 634          this._sizeChangeHandler();
 635      },
 636  
 637      /**
 638       * Event handler for size changes.
 639       *
 640       * @method _sizeChangeHandler
 641       * @param {Object} e Event object.
 642       * @private
 643       */
 644      _sizeChangeHandler: function()
 645      {
 646          var hgl = this.get("horizontalGridlines"),
 647              vgl = this.get("verticalGridlines"),
 648              w = this.get("width"),
 649              h = this.get("height"),
 650              bg = this.get("styles").background,
 651              weight,
 652              background;
 653          if(bg && bg.border)
 654          {
 655              weight = bg.border.weight || 0;
 656          }
 657          if(this.get("showBackground"))
 658          {
 659              background = this.get("background");
 660              if(w && h)
 661              {
 662                  background.set("width", w);
 663                  background.set("height", h);
 664              }
 665          }
 666          if(this._gridlines)
 667          {
 668              this._gridlines.clear();
 669          }
 670          if(hgl && hgl instanceof Y.Gridlines)
 671          {
 672              hgl.draw();
 673          }
 674          if(vgl && vgl instanceof Y.Gridlines)
 675          {
 676              vgl.draw();
 677          }
 678          this._drawSeries();
 679      },
 680  
 681      /**
 682       * Draws each series.
 683       *
 684       * @method _drawSeries
 685       * @private
 686       */
 687      _drawSeries: function()
 688      {
 689          if(this._drawing)
 690          {
 691              this._callLater = true;
 692              return;
 693          }
 694          var sc,
 695              i,
 696              len,
 697              graphic = this.get("graphic");
 698          graphic.set("autoDraw", false);
 699          graphic.set("width", this.get("width"));
 700          graphic.set("height", this.get("height"));
 701          this._callLater = false;
 702          this._drawing = true;
 703          sc = this.get("seriesCollection");
 704          i = 0;
 705          len = sc ? sc.length : 0;
 706          for(; i < len; ++i)
 707          {
 708              sc[i].draw();
 709              if((!sc[i].get("xcoords") || !sc[i].get("ycoords")) && !sc[i] instanceof Y.PieSeries)
 710              {
 711                  this._callLater = true;
 712                  break;
 713              }
 714          }
 715          this._drawing = false;
 716          if(this._callLater)
 717          {
 718              this._drawSeries();
 719          }
 720      },
 721  
 722      /**
 723       * Event handler for series drawingComplete event.
 724       *
 725       * @method _drawingCompleteHandler
 726       * @param {Object} e Event object.
 727       * @private
 728       */
 729      _drawingCompleteHandler: function(e)
 730      {
 731          var series = e.currentTarget,
 732              graphic,
 733              index = Y.Array.indexOf(this._dispatchers, series);
 734          if(index > -1)
 735          {
 736              this._dispatchers.splice(index, 1);
 737          }
 738          if(this._dispatchers.length < 1)
 739          {
 740              graphic = this.get("graphic");
 741              if(!graphic.get("autoDraw"))
 742              {
 743                  graphic._redraw();
 744              }
 745              this.fire("chartRendered");
 746          }
 747      },
 748  
 749      /**
 750       * Gets the default value for the `styles` attribute. Overrides
 751       * base implementation.
 752       *
 753       * @method _getDefaultStyles
 754       * @return Object
 755       * @protected
 756       */
 757      _getDefaultStyles: function()
 758      {
 759          var defs = {
 760              background: {
 761                  shape: "rect",
 762                  fill:{
 763                      color:"#faf9f2"
 764                  },
 765                  border: {
 766                      color:"#dad8c9",
 767                      weight: 1
 768                  }
 769              }
 770          };
 771          return defs;
 772      },
 773  
 774      /**
 775       * Destructor implementation Graph class. Removes all Graphic instances from the widget.
 776       *
 777       * @method destructor
 778       * @protected
 779       */
 780      destructor: function()
 781      {
 782          if(this._graphic)
 783          {
 784              this._graphic.destroy();
 785              this._graphic = null;
 786          }
 787          if(this._background)
 788          {
 789              this._background.get("graphic").destroy();
 790              this._background = null;
 791          }
 792          if(this._gridlines)
 793          {
 794              this._gridlines.get("graphic").destroy();
 795              this._gridlines = null;
 796          }
 797      }
 798  }, {
 799      ATTRS: {
 800          /**
 801           * The x-coordinate for the graph.
 802           *
 803           * @attribute x
 804           * @type Number
 805           * @protected
 806           */
 807          x: {
 808              setter: function(val)
 809              {
 810                  this.get("boundingBox").setStyle("left", val + "px");
 811                  return val;
 812              }
 813          },
 814  
 815          /**
 816           * The y-coordinate for the graph.
 817           *
 818           * @attribute y
 819           * @type Number
 820           * @protected
 821           */
 822          y: {
 823              setter: function(val)
 824              {
 825                  this.get("boundingBox").setStyle("top", val + "px");
 826                  return val;
 827              }
 828          },
 829  
 830          /**
 831           * Reference to the chart instance using the graph.
 832           *
 833           * @attribute chart
 834           * @type ChartBase
 835           * @readOnly
 836           */
 837          chart: {
 838              getter: function() {
 839                  var chart = this._state.chart || this;
 840                  return chart;
 841              }
 842          },
 843  
 844          /**
 845           * Collection of series. When setting the `seriesCollection` the array can contain a combination of either
 846           * `CartesianSeries` instances or object literals with properties that will define a series.
 847           *
 848           * @attribute seriesCollection
 849           * @type CartesianSeries
 850           */
 851          seriesCollection: {
 852              getter: function()
 853              {
 854                  return this._seriesCollection;
 855              },
 856  
 857              setter: function(val)
 858              {
 859                  this._parseSeriesCollection(val);
 860                  return this._seriesCollection;
 861              }
 862          },
 863  
 864          /**
 865           * Indicates whether the `Graph` has a background.
 866           *
 867           * @attribute showBackground
 868           * @type Boolean
 869           * @default true
 870           */
 871          showBackground: {
 872              value: true
 873          },
 874  
 875          /**
 876           * Read-only hash lookup for all series on in the `Graph`.
 877           *
 878           * @attribute seriesDictionary
 879           * @type Object
 880           * @readOnly
 881           */
 882          seriesDictionary: {
 883              readOnly: true,
 884  
 885              getter: function()
 886              {
 887                  return this._seriesDictionary;
 888              }
 889          },
 890  
 891          /**
 892           * Reference to the horizontal `Gridlines` instance.
 893           *
 894           * @attribute horizontalGridlines
 895           * @type Gridlines
 896           * @default null
 897           */
 898          horizontalGridlines: {
 899              value: null,
 900  
 901              setter: function(val)
 902              {
 903                  var cfg,
 904                      key,
 905                      gl = this.get("horizontalGridlines");
 906                  if(gl && gl instanceof Y.Gridlines)
 907                  {
 908                      gl.remove();
 909                  }
 910                  if(val instanceof Y.Gridlines)
 911                  {
 912                      gl = val;
 913                      val.set("graph", this);
 914                      return val;
 915                  }
 916                  else if(val)
 917                  {
 918                      cfg = {
 919                          direction: "horizonal",
 920                          graph: this
 921                      };
 922                      for(key in val)
 923                      {
 924                          if(val.hasOwnProperty(key))
 925                          {
 926                              cfg[key] = val[key];
 927                          }
 928                      }
 929                      gl = new Y.Gridlines(cfg);
 930                      return gl;
 931                  }
 932              }
 933          },
 934  
 935          /**
 936           * Reference to the vertical `Gridlines` instance.
 937           *
 938           * @attribute verticalGridlines
 939           * @type Gridlines
 940           * @default null
 941           */
 942          verticalGridlines: {
 943              value: null,
 944  
 945              setter: function(val)
 946              {
 947                  var cfg,
 948                      key,
 949                      gl = this.get("verticalGridlines");
 950                  if(gl && gl instanceof Y.Gridlines)
 951                  {
 952                      gl.remove();
 953                  }
 954                  if(val instanceof Y.Gridlines)
 955                  {
 956                      gl = val;
 957                      val.set("graph", this);
 958                      return val;
 959                  }
 960                  else if(val)
 961                  {
 962                      cfg = {
 963                          direction: "vertical",
 964                          graph: this
 965                      };
 966                      for(key in val)
 967                      {
 968                          if(val.hasOwnProperty(key))
 969                          {
 970                              cfg[key] = val[key];
 971                          }
 972                      }
 973                      gl = new Y.Gridlines(cfg);
 974                      return gl;
 975                  }
 976              }
 977          },
 978  
 979          /**
 980           * Reference to graphic instance used for the background.
 981           *
 982           * @attribute background
 983           * @type Graphic
 984           * @readOnly
 985           */
 986          background: {
 987              getter: function()
 988              {
 989                  if(!this._background)
 990                  {
 991                      this._backgroundGraphic = new Y.Graphic({render:this.get("contentBox")});
 992                      this._backgroundGraphic.get("node").style.zIndex = 0;
 993                      this._background = this._backgroundGraphic.addShape({type: "rect"});
 994                  }
 995                  return this._background;
 996              }
 997          },
 998  
 999          /**
1000           * Reference to graphic instance used for gridlines.
1001           *
1002           * @attribute gridlines
1003           * @type Graphic
1004           * @readOnly
1005           */
1006          gridlines: {
1007              readOnly: true,
1008  
1009              getter: function()
1010              {
1011                  if(!this._gridlines)
1012                  {
1013                      this._gridlinesGraphic = new Y.Graphic({render:this.get("contentBox")});
1014                      this._gridlinesGraphic.get("node").style.zIndex = 1;
1015                      this._gridlines = this._gridlinesGraphic.addShape({type: "path"});
1016                  }
1017                  return this._gridlines;
1018              }
1019          },
1020  
1021          /**
1022           * Reference to graphic instance used for series.
1023           *
1024           * @attribute graphic
1025           * @type Graphic
1026           * @readOnly
1027           */
1028          graphic: {
1029              readOnly: true,
1030  
1031              getter: function()
1032              {
1033                  if(!this._graphic)
1034                  {
1035                      this._graphic = new Y.Graphic({render:this.get("contentBox")});
1036                      this._graphic.get("node").style.zIndex = 2;
1037                      this._graphic.set("autoDraw", false);
1038                  }
1039                  return this._graphic;
1040              }
1041          },
1042  
1043          /**
1044           * Indicates whether or not markers for a series will be grouped and rendered in a single complex shape instance.
1045           *
1046           * @attribute groupMarkers
1047           * @type Boolean
1048           */
1049          groupMarkers: {
1050              value: false
1051          }
1052  
1053          /**
1054           * Style properties used for drawing a background. Below are the default values:
1055           *  <dl>
1056           *      <dt>background</dt><dd>An object containing the following values:
1057           *          <dl>
1058           *              <dt>fill</dt><dd>Defines the style properties for the fill. Contains the following values:
1059           *                  <dl>
1060           *                      <dt>color</dt><dd>Color of the fill. The default value is #faf9f2.</dd>
1061           *                      <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background fill.
1062           *                      The default value is 1.</dd>
1063           *                  </dl>
1064           *              </dd>
1065           *              <dt>border</dt><dd>Defines the style properties for the border. Contains the following values:
1066           *                  <dl>
1067           *                      <dt>color</dt><dd>Color of the border. The default value is #dad8c9.</dd>
1068           *                      <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background border.
1069           *                      The default value is 1.</dd>
1070           *                      <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
1071           *                  </dl>
1072           *              </dd>
1073           *          </dl>
1074           *      </dd>
1075           *  </dl>
1076           *
1077           * @attribute styles
1078           * @type Object
1079           */
1080      }
1081  });
1082  /**
1083   * The ChartBase class is an abstract class used to create charts.
1084   *
1085   * @class ChartBase
1086   * @constructor
1087   * @submodule charts-base
1088   */
1089  function ChartBase() {}
1090  
1091  ChartBase.ATTRS = {
1092      /**
1093       * Data used to generate the chart.
1094       *
1095       * @attribute dataProvider
1096       * @type Array
1097       */
1098      dataProvider: {
1099          lazyAdd: false,
1100  
1101          valueFn: function()
1102          {
1103              var defDataProvider = [];
1104              if(!this._wereSeriesKeysExplicitlySet())
1105              {
1106                  this.set("seriesKeys", this._buildSeriesKeys(defDataProvider), {src: "internal"});
1107              }
1108              return defDataProvider;
1109          },
1110  
1111          setter: function(val)
1112          {
1113              var dataProvider = this._setDataValues(val);
1114              if(!this._wereSeriesKeysExplicitlySet())
1115              {
1116                  this.set("seriesKeys", this._buildSeriesKeys(dataProvider), {src: "internal"});
1117              }
1118              return dataProvider;
1119          }
1120      },
1121  
1122      /**
1123       * A collection of keys that map to the series axes. If no keys are set,
1124       * they will be generated automatically depending on the data structure passed into
1125       * the chart.
1126       *
1127       * @attribute seriesKeys
1128       * @type Array
1129       */
1130      seriesKeys: {
1131          lazyAdd: false,
1132  
1133          setter: function(val)
1134          {
1135              var opts = arguments[2];
1136              if(!val || (opts && opts.src && opts.src === "internal"))
1137              {
1138                  this._seriesKeysExplicitlySet = false;
1139              }
1140              else
1141              {
1142                  this._seriesKeysExplicitlySet = true;
1143              }
1144              return val;
1145          }
1146      },
1147  
1148      /**
1149       * Sets the `aria-label` for the chart.
1150       *
1151       * @attribute ariaLabel
1152       * @type String
1153       */
1154      ariaLabel: {
1155          value: "Chart Application",
1156  
1157          setter: function(val)
1158          {
1159              var cb = this.get("contentBox");
1160              if(cb)
1161              {
1162                  cb.setAttribute("aria-label", val);
1163              }
1164              return val;
1165          }
1166      },
1167  
1168      /**
1169       * Sets the aria description for the chart.
1170       *
1171       * @attribute ariaDescription
1172       * @type String
1173       */
1174      ariaDescription: {
1175          value: "Use the up and down keys to navigate between series. Use the left and right keys to navigate through items in a series.",
1176  
1177          setter: function(val)
1178          {
1179              if(this._description)
1180              {
1181                  this._description.set("text", val);
1182              }
1183              return val;
1184          }
1185      },
1186  
1187      /**
1188       * Reference to the default tooltip available for the chart.
1189       * <p>Contains the following properties:</p>
1190       *  <dl>
1191       *      <dt>node</dt><dd>Reference to the actual dom node</dd>
1192       *      <dt>showEvent</dt><dd>Event that should trigger the tooltip</dd>
1193       *      <dt>hideEvent</dt><dd>Event that should trigger the removal of a tooltip (can be an event or an array of events)</dd>
1194       *      <dt>styles</dt><dd>A hash of style properties that will be applied to the tooltip node</dd>
1195       *      <dt>show</dt><dd>Indicates whether or not to show the tooltip</dd>
1196       *      <dt>markerEventHandler</dt><dd>Displays and hides tooltip based on marker events</dd>
1197       *      <dt>planarEventHandler</dt><dd>Displays and hides tooltip based on planar events</dd>
1198       *      <dt>markerLabelFunction</dt><dd>Reference to the function used to format a marker event triggered tooltip's text.
1199       *      The method contains the following arguments:
1200       *  <dl>
1201       *      <dt>categoryItem</dt><dd>An object containing the following:
1202       *  <dl>
1203       *      <dt>axis</dt><dd>The axis to which the category is bound.</dd>
1204       *      <dt>displayName</dt><dd>The display name set to the category (defaults to key if not provided).</dd>
1205       *      <dt>key</dt><dd>The key of the category.</dd>
1206       *      <dt>value</dt><dd>The value of the category.</dd>
1207       *  </dl>
1208       *  </dd>
1209       *  <dt>valueItem</dt><dd>An object containing the following:
1210       *      <dl>
1211       *          <dt>axis</dt><dd>The axis to which the item's series is bound.</dd>
1212       *          <dt>displayName</dt><dd>The display name of the series. (defaults to key if not provided)</dd>
1213       *          <dt>key</dt><dd>The key for the series.</dd>
1214       *          <dt>value</dt><dd>The value for the series item.</dd>
1215       *      </dl>
1216       *  </dd>
1217       *  <dt>itemIndex</dt><dd>The index of the item within the series.</dd>
1218       *  <dt>series</dt><dd> The `CartesianSeries` instance of the item.</dd>
1219       *  <dt>seriesIndex</dt><dd>The index of the series in the `seriesCollection`.</dd>
1220       *  </dl>
1221       *  The method returns an `HTMLElement` which is written into the DOM using `appendChild`. If you override this method and choose
1222       *  to return an html string, you will also need to override the tooltip's `setTextFunction` method to accept an html string.
1223       *  </dd>
1224       *  <dt>planarLabelFunction</dt><dd>Reference to the function used to format a planar event triggered tooltip's text
1225       *  <dl>
1226       *      <dt>categoryAxis</dt><dd> `CategoryAxis` Reference to the categoryAxis of the chart.
1227       *      <dt>valueItems</dt><dd>Array of objects for each series that has a data point in the coordinate plane of the event. Each
1228       *      object contains the following data:
1229       *  <dl>
1230       *      <dt>axis</dt><dd>The value axis of the series.</dd>
1231       *      <dt>key</dt><dd>The key for the series.</dd>
1232       *      <dt>value</dt><dd>The value for the series item.</dd>
1233       *      <dt>displayName</dt><dd>The display name of the series. (defaults to key if not provided)</dd>
1234       *  </dl>
1235       *  </dd>
1236       *      <dt>index</dt><dd>The index of the item within its series.</dd>
1237       *      <dt>seriesArray</dt><dd>Array of series instances for each value item.</dd>
1238       *      <dt>seriesIndex</dt><dd>The index of the series in the `seriesCollection`.</dd>
1239       *  </dl>
1240       *  </dd>
1241       *  </dl>
1242       *  The method returns an `HTMLElement` which is written into the DOM using `appendChild`. If you override this method and choose
1243       *  to return an html string, you will also need to override the tooltip's `setTextFunction` method to accept an html string.
1244       *  </dd>
1245       *  <dt>setTextFunction</dt><dd>Method that writes content returned from `planarLabelFunction` or `markerLabelFunction` into the
1246       *  the tooltip node. Has the following signature:
1247       *  <dl>
1248       *      <dt>label</dt><dd>The `HTMLElement` that the content is to be added.</dd>
1249       *      <dt>val</dt><dd>The content to be rendered into tooltip. This can be a `String` or `HTMLElement`. If an HTML string is used,
1250       *      it will be rendered as a string.</dd>
1251       *  </dl>
1252       *  </dd>
1253       *  </dl>
1254       * @attribute tooltip
1255       * @type Object
1256       */
1257      tooltip: {
1258          valueFn: "_getTooltip",
1259  
1260          setter: function(val)
1261          {
1262              return this._updateTooltip(val);
1263          }
1264      },
1265  
1266      /**
1267       * The key value used for the chart's category axis.
1268       *
1269       * @attribute categoryKey
1270       * @type String
1271       * @default category
1272       */
1273      categoryKey: {
1274          value: "category"
1275      },
1276  
1277      /**
1278       * Indicates the type of axis to use for the category axis.
1279       *
1280       *  <dl>
1281       *      <dt>category</dt><dd>Specifies a `CategoryAxis`.</dd>
1282       *      <dt>time</dt><dd>Specifies a `TimeAxis</dd>
1283       *  </dl>
1284       *
1285       * @attribute categoryType
1286       * @type String
1287       * @default category
1288       */
1289      categoryType:{
1290          value:"category"
1291      },
1292  
1293      /**
1294       * Indicates the the type of interactions that will fire events.
1295       *
1296       *  <dl>
1297       *      <dt>marker</dt><dd>Events will be broadcasted when the mouse interacts with individual markers.</dd>
1298       *      <dt>planar</dt><dd>Events will be broadcasted when the mouse intersects the plane of any markers on the chart.</dd>
1299       *      <dt>none</dt><dd>No events will be broadcasted.</dd>
1300       *  </dl>
1301       *
1302       * @attribute interactionType
1303       * @type String
1304       * @default marker
1305       */
1306      interactionType: {
1307          value: "marker"
1308      },
1309  
1310      /**
1311       * Reference to all the axes in the chart.
1312       *
1313       * @attribute axesCollection
1314       * @type Array
1315       */
1316      axesCollection: {},
1317  
1318      /**
1319       * Reference to graph instance.
1320       *
1321       * @attribute graph
1322       * @type Graph
1323       */
1324      graph: {
1325          valueFn: "_getGraph"
1326      },
1327  
1328      /**
1329       * Indicates whether or not markers for a series will be grouped and rendered in a single complex shape instance.
1330       *
1331       * @attribute groupMarkers
1332       * @type Boolean
1333       */
1334      groupMarkers: {
1335          value: false
1336      }
1337  };
1338  
1339  ChartBase.prototype = {
1340  
1341      /**
1342       * Utility method to determine if `seriesKeys` was explicitly provided
1343       * (for example during construction, or set by the user), as opposed to
1344       * being derived from the dataProvider for example.
1345       *
1346       * @method _wereSeriesKeysExplicitlySet
1347       * @private
1348       * @return boolean true if the `seriesKeys` attribute was explicitly set.
1349       */
1350      _wereSeriesKeysExplicitlySet : function()
1351      {
1352          var seriesKeys = this.get("seriesKeys");
1353          return seriesKeys && this._seriesKeysExplicitlySet;
1354      },
1355  
1356      /**
1357       * Handles groupMarkers change event.
1358       *
1359       * @method _groupMarkersChangeHandler
1360       * @param {Object} e Event object.
1361       * @private
1362       */
1363      _groupMarkersChangeHandler: function(e)
1364      {
1365          var graph = this.get("graph"),
1366              useGroupMarkers = e.newVal;
1367          if(graph)
1368          {
1369              graph.set("groupMarkers", useGroupMarkers);
1370          }
1371      },
1372  
1373      /**
1374       * Handler for itemRendered event.
1375       *
1376       * @method _itemRendered
1377       * @param {Object} e Event object.
1378       * @private
1379       */
1380      _itemRendered: function(e)
1381      {
1382          this._itemRenderQueue = this._itemRenderQueue.splice(1 + Y.Array.indexOf(this._itemRenderQueue, e.currentTarget), 1);
1383          if(this._itemRenderQueue.length < 1)
1384          {
1385              this._redraw();
1386          }
1387      },
1388  
1389      /**
1390       * Default value function for the `Graph` attribute.
1391       *
1392       * @method _getGraph
1393       * @return Graph
1394       * @private
1395       */
1396      _getGraph: function()
1397      {
1398          var graph = new Y.Graph({
1399              chart:this,
1400              groupMarkers: this.get("groupMarkers")
1401          });
1402          graph.after("chartRendered", Y.bind(function() {
1403              this.fire("chartRendered");
1404          }, this));
1405          return graph;
1406      },
1407  
1408      /**
1409       * Returns a series instance by index or key value.
1410       *
1411       * @method getSeries
1412       * @param val
1413       * @return CartesianSeries
1414       */
1415      getSeries: function(val)
1416      {
1417          var series = null,
1418              graph = this.get("graph");
1419          if(graph)
1420          {
1421              if(Y_Lang.isNumber(val))
1422              {
1423                  series = graph.getSeriesByIndex(val);
1424              }
1425              else
1426              {
1427                  series = graph.getSeriesByKey(val);
1428              }
1429          }
1430          return series;
1431      },
1432  
1433      /**
1434       * Returns an `Axis` instance by key reference. If the axis was explicitly set through the `axes` attribute,
1435       * the key will be the same as the key used in the `axes` object. For default axes, the key for
1436       * the category axis is the value of the `categoryKey` (`category`). For the value axis, the default
1437       * key is `values`.
1438       *
1439       * @method getAxisByKey
1440       * @param {String} val Key reference used to look up the axis.
1441       * @return Axis
1442       */
1443      getAxisByKey: function(val)
1444      {
1445          var axis,
1446              axes = this.get("axes");
1447          if(axes && axes.hasOwnProperty(val))
1448          {
1449              axis = axes[val];
1450          }
1451          return axis;
1452      },
1453  
1454      /**
1455       * Returns the category axis for the chart.
1456       *
1457       * @method getCategoryAxis
1458       * @return Axis
1459       */
1460      getCategoryAxis: function()
1461      {
1462          var axis,
1463              key = this.get("categoryKey"),
1464              axes = this.get("axes");
1465          if(axes.hasOwnProperty(key))
1466          {
1467              axis = axes[key];
1468          }
1469          return axis;
1470      },
1471  
1472      /**
1473       * Default direction of the chart.
1474       *
1475       * @property _direction
1476       * @type String
1477       * @default horizontal
1478       * @private
1479       */
1480      _direction: "horizontal",
1481  
1482      /**
1483       * Storage for the `dataProvider` attribute.
1484       *
1485       * @property _dataProvider
1486       * @type Array
1487       * @private
1488       */
1489      _dataProvider: null,
1490  
1491      /**
1492       * Setter method for `dataProvider` attribute.
1493       *
1494       * @method _setDataValues
1495       * @param {Array} val Array to be set as `dataProvider`.
1496       * @return Array
1497       * @private
1498       */
1499      _setDataValues: function(val)
1500      {
1501          if(Y_Lang.isArray(val[0]))
1502          {
1503              var hash,
1504                  dp = [],
1505                  cats = val[0],
1506                  i = 0,
1507                  l = cats.length,
1508                  n,
1509                  sl = val.length;
1510              for(; i < l; ++i)
1511              {
1512                  hash = {category:cats[i]};
1513                  for(n = 1; n < sl; ++n)
1514                  {
1515                      hash["series" + n] = val[n][i];
1516                  }
1517                  dp[i] = hash;
1518              }
1519              return dp;
1520          }
1521          return val;
1522      },
1523  
1524      /**
1525       * Storage for `seriesCollection` attribute.
1526       *
1527       * @property _seriesCollection
1528       * @type Array
1529       * @private
1530       */
1531      _seriesCollection: null,
1532  
1533      /**
1534       * Setter method for `seriesCollection` attribute.
1535       *
1536       * @property _setSeriesCollection
1537       * @param {Array} val Array of either `CartesianSeries` instances or objects containing series attribute key value pairs.
1538       * @private
1539       */
1540      _setSeriesCollection: function(val)
1541      {
1542          this._seriesCollection = val;
1543      },
1544      /**
1545       * Helper method that returns the axis class that a key references.
1546       *
1547       * @method _getAxisClass
1548       * @param {String} t The type of axis.
1549       * @return Axis
1550       * @private
1551       */
1552      _getAxisClass: function(t)
1553      {
1554          return this._axisClass[t];
1555      },
1556  
1557      /**
1558       * Key value pairs of axis types.
1559       *
1560       * @property _axisClass
1561       * @type Object
1562       * @private
1563       */
1564      _axisClass: {
1565          stacked: Y.StackedAxis,
1566          numeric: Y.NumericAxis,
1567          category: Y.CategoryAxis,
1568          time: Y.TimeAxis
1569      },
1570  
1571      /**
1572       * Collection of axes.
1573       *
1574       * @property _axes
1575       * @type Array
1576       * @private
1577       */
1578      _axes: null,
1579  
1580      /**
1581       * @method initializer
1582       * @private
1583       */
1584      initializer: function()
1585      {
1586          this._itemRenderQueue = [];
1587          this._seriesIndex = -1;
1588          this._itemIndex = -1;
1589          this.after("dataProviderChange", this._dataProviderChangeHandler);
1590      },
1591  
1592      /**
1593       * @method renderUI
1594       * @private
1595       */
1596      renderUI: function()
1597      {
1598          var tt = this.get("tooltip"),
1599              bb = this.get("boundingBox"),
1600              cb = this.get("contentBox");
1601          //move the position = absolute logic to a class file
1602          bb.setStyle("position", "absolute");
1603          cb.setStyle("position", "absolute");
1604          this._addAxes();
1605          this._addSeries();
1606          if(tt && tt.show)
1607          {
1608              this._addTooltip();
1609          }
1610          this._setAriaElements(bb, cb);
1611      },
1612  
1613      /**
1614       * Creates an aria `live-region`, `aria-label` and `aria-describedby` for the Chart.
1615       *
1616       * @method _setAriaElements
1617       * @param {Node} cb Reference to the Chart's `contentBox` attribute.
1618       * @private
1619       */
1620      _setAriaElements: function(bb, cb)
1621      {
1622          var description = this._getAriaOffscreenNode(),
1623              id = this.get("id") + "_description",
1624              liveRegion = this._getAriaOffscreenNode();
1625          cb.set("tabIndex", 0);
1626          cb.set("role", "img");
1627          cb.setAttribute("aria-label", this.get("ariaLabel"));
1628          cb.setAttribute("aria-describedby", id);
1629          description.set("id", id);
1630          description.set("tabIndex", -1);
1631          description.set("text", this.get("ariaDescription"));
1632          liveRegion.set("id", "live-region");
1633          liveRegion.set("aria-live", "polite");
1634          liveRegion.set("aria-atomic", "true");
1635          liveRegion.set("role", "status");
1636          bb.setAttribute("role", "application");
1637          bb.appendChild(description);
1638          bb.appendChild(liveRegion);
1639          this._description = description;
1640          this._liveRegion = liveRegion;
1641      },
1642  
1643      /**
1644       * Sets a node offscreen for use as aria-description or aria-live-regin.
1645       *
1646       * @method _setOffscreen
1647       * @return Node
1648       * @private
1649       */
1650      _getAriaOffscreenNode: function()
1651      {
1652          var node = Y.Node.create("<div></div>"),
1653              ie = Y.UA.ie,
1654              clipRect = (ie && ie < 8) ? "rect(1px 1px 1px 1px)" : "rect(1px, 1px, 1px, 1px)";
1655          node.setStyle("position", "absolute");
1656          node.setStyle("height", "1px");
1657          node.setStyle("width", "1px");
1658          node.setStyle("overflow", "hidden");
1659          node.setStyle("clip", clipRect);
1660          return node;
1661      },
1662  
1663      /**
1664       * @method syncUI
1665       * @private
1666       */
1667      syncUI: function()
1668      {
1669          this._redraw();
1670      },
1671  
1672      /**
1673       * @method bindUI
1674       * @private
1675       */
1676      bindUI: function()
1677      {
1678          this.after("tooltipChange", Y.bind(this._tooltipChangeHandler, this));
1679          this.after("widthChange", this._sizeChanged);
1680          this.after("heightChange", this._sizeChanged);
1681          this.after("groupMarkersChange", this._groupMarkersChangeHandler);
1682          var tt = this.get("tooltip"),
1683              hideEvent = "mouseout",
1684              showEvent = "mouseover",
1685              cb = this.get("contentBox"),
1686              interactionType = this.get("interactionType"),
1687              i = 0,
1688              len,
1689              markerClassName = "." + SERIES_MARKER,
1690              isTouch = ((WINDOW && ("ontouchstart" in WINDOW)) && !(Y.UA.chrome && Y.UA.chrome < 6));
1691          Y.on("keydown", Y.bind(function(e) {
1692              var key = e.keyCode,
1693                  numKey = parseFloat(key),
1694                  msg;
1695              if(numKey > 36 && numKey < 41)
1696              {
1697                  e.halt();
1698                  msg = this._getAriaMessage(numKey);
1699                  this._liveRegion.set("text", msg);
1700              }
1701          }, this), this.get("contentBox"));
1702          if(interactionType === "marker")
1703          {
1704              //if touch capabilities, toggle tooltip on touchend. otherwise, the tooltip attribute's hideEvent/showEvent types.
1705              hideEvent = tt.hideEvent;
1706              showEvent = tt.showEvent;
1707              if(isTouch)
1708              {
1709                  Y.delegate("touchend", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
1710                  //hide active tooltip if the chart is touched
1711                  Y.on("touchend", Y.bind(function(e) {
1712                      //only halt the event if it originated from the chart
1713                      if(cb.contains(e.target))
1714                      {
1715                          e.halt(true);
1716                      }
1717                      if(this._activeMarker)
1718                      {
1719                          this._activeMarker = null;
1720                          this.hideTooltip(e);
1721                      }
1722                  }, this));
1723              }
1724              else
1725              {
1726                  Y.delegate("mouseenter", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
1727                  Y.delegate("mousedown", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
1728                  Y.delegate("mouseup", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
1729                  Y.delegate("mouseleave", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
1730                  Y.delegate("click", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
1731                  Y.delegate("mousemove", Y.bind(this._positionTooltip, this), cb, markerClassName);
1732              }
1733          }
1734          else if(interactionType === "planar")
1735          {
1736              if(isTouch)
1737              {
1738                  this._overlay.on("touchend", Y.bind(this._planarEventDispatcher, this));
1739              }
1740              else
1741              {
1742                  this._overlay.on("mousemove", Y.bind(this._planarEventDispatcher, this));
1743                  this.on("mouseout", this.hideTooltip);
1744              }
1745          }
1746          if(tt)
1747          {
1748              this.on("markerEvent:touchend", Y.bind(function(e) {
1749                  var marker = e.series.get("markers")[e.index];
1750                  if(this._activeMarker && marker === this._activeMarker)
1751                  {
1752                      this._activeMarker = null;
1753                      this.hideTooltip(e);
1754                  }
1755                  else
1756                  {
1757  
1758                      this._activeMarker = marker;
1759                      tt.markerEventHandler.apply(this, [e]);
1760                  }
1761              }, this));
1762              if(hideEvent && showEvent && hideEvent === showEvent)
1763              {
1764                  this.on(interactionType + "Event:" + hideEvent, this.toggleTooltip);
1765              }
1766              else
1767              {
1768                  if(showEvent)
1769                  {
1770                      this.on(interactionType + "Event:" + showEvent, tt[interactionType + "EventHandler"]);
1771                  }
1772                  if(hideEvent)
1773                  {
1774                      if(Y_Lang.isArray(hideEvent))
1775                      {
1776                          len = hideEvent.length;
1777                          for(; i < len; ++i)
1778                          {
1779                              this.on(interactionType + "Event:" + hideEvent[i], this.hideTooltip);
1780                          }
1781                      }
1782                      this.on(interactionType + "Event:" + hideEvent, this.hideTooltip);
1783                  }
1784              }
1785          }
1786      },
1787  
1788      /**
1789       * Event handler for marker events.
1790       *
1791       * @method _markerEventDispatcher
1792       * @param {Object} e Event object.
1793       * @private
1794       */
1795      _markerEventDispatcher: function(e)
1796      {
1797          var type = e.type,
1798              cb = this.get("contentBox"),
1799              markerNode = e.currentTarget,
1800              strArr = markerNode.getAttribute("id").split("_"),
1801              index = strArr.pop(),
1802              seriesIndex = strArr.pop(),
1803              series = this.getSeries(parseInt(seriesIndex, 10)),
1804              items = this.getSeriesItems(series, index),
1805              isTouch = e && e.hasOwnProperty("changedTouches"),
1806              pageX = isTouch ? e.changedTouches[0].pageX : e.pageX,
1807              pageY = isTouch ? e.changedTouches[0].pageY : e.pageY,
1808              x = pageX - cb.getX(),
1809              y = pageY - cb.getY();
1810          if(type === "mouseenter")
1811          {
1812              type = "mouseover";
1813          }
1814          else if(type === "mouseleave")
1815          {
1816              type = "mouseout";
1817          }
1818          series.updateMarkerState(type, index);
1819          e.halt();
1820          /**
1821           * Broadcasts when `interactionType` is set to `marker` and a series marker has received a mouseover event.
1822           *
1823           *
1824           * @event markerEvent:mouseover
1825           * @preventable false
1826           * @param {EventFacade} e Event facade with the following additional
1827           *   properties:
1828           *  <dl>
1829           *      <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
1830           *      <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
1831           *      <dt>node</dt><dd>The dom node of the marker.</dd>
1832           *      <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
1833           *      <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
1834           *      <dt>series</dt><dd>Reference to the series of the marker.</dd>
1835           *      <dt>index</dt><dd>Index of the marker in the series.</dd>
1836           *      <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
1837           *  </dl>
1838           */
1839          /**
1840           * Broadcasts when `interactionType` is set to `marker` and a series marker has received a mouseout event.
1841           *
1842           * @event markerEvent:mouseout
1843           * @preventable false
1844           * @param {EventFacade} e Event facade with the following additional
1845           *   properties:
1846           *  <dl>
1847           *      <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
1848           *      <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
1849           *      <dt>node</dt><dd>The dom node of the marker.</dd>
1850           *      <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
1851           *      <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
1852           *      <dt>series</dt><dd>Reference to the series of the marker.</dd>
1853           *      <dt>index</dt><dd>Index of the marker in the series.</dd>
1854           *      <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
1855           *  </dl>
1856           */
1857          /**
1858           * Broadcasts when `interactionType` is set to `marker` and a series marker has received a mousedown event.
1859           *
1860           * @event markerEvent:mousedown
1861           * @preventable false
1862           * @param {EventFacade} e Event facade with the following additional
1863           *   properties:
1864           *  <dl>
1865           *      <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
1866           *      <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
1867           *      <dt>node</dt><dd>The dom node of the marker.</dd>
1868           *      <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
1869           *      <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
1870           *      <dt>series</dt><dd>Reference to the series of the marker.</dd>
1871           *      <dt>index</dt><dd>Index of the marker in the series.</dd>
1872           *      <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
1873           *  </dl>
1874           */
1875          /**
1876           * Broadcasts when `interactionType` is set to `marker` and a series marker has received a mouseup event.
1877           *
1878           * @event markerEvent:mouseup
1879           * @preventable false
1880           * @param {EventFacade} e Event facade with the following additional
1881           *   properties:
1882           *  <dl>
1883           *      <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
1884           *      <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
1885           *      <dt>node</dt><dd>The dom node of the marker.</dd>
1886           *      <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
1887           *      <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
1888           *      <dt>series</dt><dd>Reference to the series of the marker.</dd>
1889           *      <dt>index</dt><dd>Index of the marker in the series.</dd>
1890           *      <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
1891           *  </dl>
1892           */
1893          /**
1894           * Broadcasts when `interactionType` is set to `marker` and a series marker has received a click event.
1895           *
1896           * @event markerEvent:click
1897           * @preventable false
1898           * @param {EventFacade} e Event facade with the following additional
1899           *   properties:
1900           *  <dl>
1901           *      <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
1902           *      <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
1903           *      <dt>node</dt><dd>The dom node of the marker.</dd>
1904           *      <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
1905           *      <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
1906           *      <dt>pageX</dt><dd>The x location of the event on the page (including scroll)</dd>
1907           *      <dt>pageY</dt><dd>The y location of the event on the page (including scroll)</dd>
1908           *      <dt>series</dt><dd>Reference to the series of the marker.</dd>
1909           *      <dt>index</dt><dd>Index of the marker in the series.</dd>
1910           *      <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
1911           *      <dt>originEvent</dt><dd>Underlying dom event.</dd>
1912           *  </dl>
1913           */
1914          this.fire("markerEvent:" + type, {
1915              originEvent: e,
1916              pageX:pageX,
1917              pageY:pageY,
1918              categoryItem:items.category,
1919              valueItem:items.value,
1920              node:markerNode,
1921              x:x,
1922              y:y,
1923              series:series,
1924              index:index,
1925              seriesIndex:seriesIndex
1926          });
1927      },
1928  
1929      /**
1930       * Event handler for dataProviderChange.
1931       *
1932       * @method _dataProviderChangeHandler
1933       * @param {Object} e Event object.
1934       * @private
1935       */
1936      _dataProviderChangeHandler: function(e)
1937      {
1938          var dataProvider = e.newVal,
1939              axes,
1940              i,
1941              axis;
1942          this._seriesIndex = -1;
1943          this._itemIndex = -1;
1944          if(this instanceof Y.CartesianChart)
1945          {
1946              this.set("axes", this.get("axes"));
1947              this.set("seriesCollection", this.get("seriesCollection"));
1948          }
1949          axes = this.get("axes");
1950          if(axes)
1951          {
1952              for(i in axes)
1953              {
1954                  if(axes.hasOwnProperty(i))
1955                  {
1956                      axis = axes[i];
1957                      if(axis instanceof Y.Axis)
1958                      {
1959                          if(axis.get("position") !== "none")
1960                          {
1961                              this._addToAxesRenderQueue(axis);
1962                          }
1963                          axis.set("dataProvider", dataProvider);
1964                      }
1965                  }
1966              }
1967          }
1968      },
1969  
1970      /**
1971       * Event listener for toggling the tooltip. If a tooltip is visible, hide it. If not, it
1972       * will create and show a tooltip based on the event object.
1973       *
1974       * @method toggleTooltip
1975       * @param {Object} e Event object.
1976       */
1977      toggleTooltip: function(e)
1978      {
1979          var tt = this.get("tooltip");
1980          if(tt.visible)
1981          {
1982              this.hideTooltip();
1983          }
1984          else
1985          {
1986              tt.markerEventHandler.apply(this, [e]);
1987          }
1988      },
1989  
1990      /**
1991       * Shows a tooltip
1992       *
1993       * @method _showTooltip
1994       * @param {String} msg Message to dispaly in the tooltip.
1995       * @param {Number} x x-coordinate
1996       * @param {Number} y y-coordinate
1997       * @private
1998       */
1999      _showTooltip: function(msg, x, y)
2000      {
2001          var tt = this.get("tooltip"),
2002              node = tt.node;
2003          if(msg)
2004          {
2005              tt.visible = true;
2006              tt.setTextFunction(node, msg);
2007              node.setStyle("top", y + "px");
2008              node.setStyle("left", x + "px");
2009              node.setStyle("visibility", "visible");
2010          }
2011      },
2012  
2013      /**
2014       * Positions the tooltip
2015       *
2016       * @method _positionTooltip
2017       * @param {Object} e Event object.
2018       * @private
2019       */
2020      _positionTooltip: function(e)
2021      {
2022          var tt = this.get("tooltip"),
2023              node = tt.node,
2024              cb = this.get("contentBox"),
2025              x = (e.pageX + 10) - cb.getX(),
2026              y = (e.pageY + 10) - cb.getY();
2027          if(node)
2028          {
2029              node.setStyle("left", x + "px");
2030              node.setStyle("top", y + "px");
2031          }
2032      },
2033  
2034      /**
2035       * Hides the default tooltip
2036       *
2037       * @method hideTooltip
2038       */
2039      hideTooltip: function()
2040      {
2041          var tt = this.get("tooltip"),
2042              node = tt.node;
2043          tt.visible = false;
2044          node.set("innerHTML", "");
2045          node.setStyle("left", -10000);
2046          node.setStyle("top", -10000);
2047          node.setStyle("visibility", "hidden");
2048      },
2049  
2050      /**
2051       * Adds a tooltip to the dom.
2052       *
2053       * @method _addTooltip
2054       * @private
2055       */
2056      _addTooltip: function()
2057      {
2058          var tt = this.get("tooltip"),
2059              id = this.get("id") + "_tooltip",
2060              cb = this.get("contentBox"),
2061              oldNode = DOCUMENT.getElementById(id);
2062          if(oldNode)
2063          {
2064              cb.removeChild(oldNode);
2065          }
2066          tt.node.set("id", id);
2067          tt.node.setStyle("visibility", "hidden");
2068          cb.appendChild(tt.node);
2069      },
2070  
2071      /**
2072       * Updates the tooltip attribute.
2073       *
2074       * @method _updateTooltip
2075       * @param {Object} val Object containing properties for the tooltip.
2076       * @return Object
2077       * @private
2078       */
2079      _updateTooltip: function(val)
2080      {
2081          var tt = this.get("tooltip") || this._getTooltip(),
2082              i,
2083              styles,
2084              node,
2085              props = {
2086                  markerLabelFunction:"markerLabelFunction",
2087                  planarLabelFunction:"planarLabelFunction",
2088                  setTextFunction:"setTextFunction",
2089                  showEvent:"showEvent",
2090                  hideEvent:"hideEvent",
2091                  markerEventHandler:"markerEventHandler",
2092                  planarEventHandler:"planarEventHandler",
2093                  show:"show"
2094              };
2095          if(Y_Lang.isObject(val))
2096          {
2097              styles = val.styles;
2098              if(val.node && tt.node)
2099              {
2100                  tt.node.destroy(true);
2101                  node = Y.one(val.node);
2102              }
2103              else
2104              {
2105                  node = tt.node;
2106              }
2107              if(styles)
2108              {
2109                  for(i in styles)
2110                  {
2111                      if(styles.hasOwnProperty(i))
2112                      {
2113                          node.setStyle(i, styles[i]);
2114                      }
2115                  }
2116              }
2117              for(i in props)
2118              {
2119                  if(val.hasOwnProperty(i))
2120                  {
2121                      tt[i] = val[i];
2122                  }
2123              }
2124              tt.node = node;
2125          }
2126          return tt;
2127      },
2128  
2129      /**
2130       * Default getter for `tooltip` attribute.
2131       *
2132       * @method _getTooltip
2133       * @return Object
2134       * @private
2135       */
2136      _getTooltip: function()
2137      {
2138          var node = DOCUMENT.createElement("div"),
2139              tooltipClass = _getClassName("chart-tooltip"),
2140              tt = {
2141                  setTextFunction: this._setText,
2142                  markerLabelFunction: this._tooltipLabelFunction,
2143                  planarLabelFunction: this._planarLabelFunction,
2144                  show: true,
2145                  hideEvent: "mouseout",
2146                  showEvent: "mouseover",
2147                  markerEventHandler: function(e)
2148                  {
2149                      var tt = this.get("tooltip"),
2150                      msg = tt.markerLabelFunction.apply(this, [e.categoryItem, e.valueItem, e.index, e.series, e.seriesIndex]);
2151                      this._showTooltip(msg, e.x + 10, e.y + 10);
2152                  },
2153                  planarEventHandler: function(e)
2154                  {
2155                      var tt = this.get("tooltip"),
2156                          msg ,
2157                          categoryAxis = this.get("categoryAxis");
2158                      msg = tt.planarLabelFunction.apply(this, [categoryAxis, e.valueItem, e.index, e.items, e.seriesIndex]);
2159                      this._showTooltip(msg, e.x + 10, e.y + 10);
2160                  }
2161              };
2162          node = Y.one(node);
2163          node.set("id", this.get("id") + "_tooltip");
2164          node.setStyle("fontSize", "85%");
2165          node.setStyle("opacity", "0.83");
2166          node.setStyle("position", "absolute");
2167          node.setStyle("paddingTop", "2px");
2168          node.setStyle("paddingRight", "5px");
2169          node.setStyle("paddingBottom", "4px");
2170          node.setStyle("paddingLeft", "2px");
2171          node.setStyle("backgroundColor", "#fff");
2172          node.setStyle("border", "1px solid #dbdccc");
2173          node.setStyle("pointerEvents", "none");
2174          node.setStyle("zIndex", 3);
2175          node.setStyle("whiteSpace", "noWrap");
2176          node.setStyle("visibility", "hidden");
2177          node.addClass(tooltipClass);
2178          tt.node = Y.one(node);
2179          return tt;
2180      },
2181  
2182      /**
2183       * Formats tooltip text when `interactionType` is `planar`.
2184       *
2185       * @method _planarLabelFunction
2186       * @param {Axis} categoryAxis Reference to the categoryAxis of the chart.
2187       * @param {Array} valueItems Array of objects for each series that has a data point in the coordinate plane of the event.
2188       * Each object contains the following data:
2189       *  <dl>
2190       *      <dt>axis</dt><dd>The value axis of the series.</dd>
2191       *      <dt>key</dt><dd>The key for the series.</dd>
2192       *      <dt>value</dt><dd>The value for the series item.</dd>
2193       *      <dt>displayName</dt><dd>The display name of the series. (defaults to key if not provided)</dd>
2194       *  </dl>
2195       *  @param {Number} index The index of the item within its series.
2196       *  @param {Array} seriesArray Array of series instances for each value item.
2197       *  @param {Number} seriesIndex The index of the series in the `seriesCollection`.
2198       *  @return {HTMLElement}
2199       * @private
2200       */
2201      _planarLabelFunction: function(categoryAxis, valueItems, index, seriesArray)
2202      {
2203          var msg = DOCUMENT.createElement("div"),
2204              valueItem,
2205              i = 0,
2206              len = seriesArray.length,
2207              axis,
2208              categoryValue,
2209              seriesValue,
2210              series;
2211          if(categoryAxis)
2212          {
2213              categoryValue = categoryAxis.get("labelFunction").apply(
2214                  this,
2215                  [categoryAxis.getKeyValueAt(this.get("categoryKey"), index), categoryAxis.get("labelFormat")]
2216              );
2217              if(!Y_Lang.isObject(categoryValue))
2218              {
2219                  categoryValue = DOCUMENT.createTextNode(categoryValue);
2220              }
2221              msg.appendChild(categoryValue);
2222          }
2223  
2224          for(; i < len; ++i)
2225          {
2226              series = seriesArray[i];
2227              if(series.get("visible"))
2228              {
2229                  valueItem = valueItems[i];
2230                  axis = valueItem.axis;
2231                  seriesValue =  axis.get("labelFunction").apply(
2232                      this,
2233                      [axis.getKeyValueAt(valueItem.key, index), axis.get("labelFormat")]
2234                  );
2235                  msg.appendChild(DOCUMENT.createElement("br"));
2236                  msg.appendChild(DOCUMENT.createTextNode(valueItem.displayName));
2237                  msg.appendChild(DOCUMENT.createTextNode(": "));
2238                  if(!Y_Lang.isObject(seriesValue))
2239                  {
2240                      seriesValue = DOCUMENT.createTextNode(seriesValue);
2241                  }
2242                  msg.appendChild(seriesValue);
2243              }
2244          }
2245          return msg;
2246      },
2247  
2248      /**
2249       * Formats tooltip text when `interactionType` is `marker`.
2250       *
2251       * @method _tooltipLabelFunction
2252       * @param {Object} categoryItem An object containing the following:
2253       *  <dl>
2254       *      <dt>axis</dt><dd>The axis to which the category is bound.</dd>
2255       *      <dt>displayName</dt><dd>The display name set to the category (defaults to key if not provided)</dd>
2256       *      <dt>key</dt><dd>The key of the category.</dd>
2257       *      <dt>value</dt><dd>The value of the category</dd>
2258       *  </dl>
2259       * @param {Object} valueItem An object containing the following:
2260       *  <dl>
2261       *      <dt>axis</dt><dd>The axis to which the item's series is bound.</dd>
2262       *      <dt>displayName</dt><dd>The display name of the series. (defaults to key if not provided)</dd>
2263       *      <dt>key</dt><dd>The key for the series.</dd>
2264       *      <dt>value</dt><dd>The value for the series item.</dd>
2265       *  </dl>
2266       * @return {HTMLElement}
2267       * @private
2268       */
2269      _tooltipLabelFunction: function(categoryItem, valueItem)
2270      {
2271          var msg = DOCUMENT.createElement("div"),
2272              categoryValue = categoryItem.axis.get("labelFunction").apply(
2273                  this,
2274                  [categoryItem.value, categoryItem.axis.get("labelFormat")]
2275              ),
2276              seriesValue = valueItem.axis.get("labelFunction").apply(
2277                  this,
2278                  [valueItem.value, valueItem.axis.get("labelFormat")]
2279              );
2280          msg.appendChild(DOCUMENT.createTextNode(categoryItem.displayName));
2281          msg.appendChild(DOCUMENT.createTextNode(": "));
2282          if(!Y_Lang.isObject(categoryValue))
2283          {
2284              categoryValue = DOCUMENT.createTextNode(categoryValue);
2285          }
2286          msg.appendChild(categoryValue);
2287          msg.appendChild(DOCUMENT.createElement("br"));
2288          msg.appendChild(DOCUMENT.createTextNode(valueItem.displayName));
2289          msg.appendChild(DOCUMENT.createTextNode(": "));
2290          if(!Y_Lang.isObject(seriesValue))
2291          {
2292              seriesValue = DOCUMENT.createTextNode(seriesValue);
2293          }
2294          msg.appendChild(seriesValue);
2295          return msg;
2296      },
2297  
2298      /**
2299       * Event handler for the tooltipChange.
2300       *
2301       * @method _tooltipChangeHandler
2302       * @param {Object} e Event object.
2303       * @private
2304       */
2305      _tooltipChangeHandler: function()
2306      {
2307          if(this.get("tooltip"))
2308          {
2309              var tt = this.get("tooltip"),
2310                  node = tt.node,
2311                  show = tt.show,
2312                  cb = this.get("contentBox");
2313              if(node && show)
2314              {
2315                  if(!cb.contains(node))
2316                  {
2317                      this._addTooltip();
2318                  }
2319              }
2320          }
2321      },
2322  
2323      /**
2324       * Updates the content of text field. This method writes a value into a text field using
2325       * `appendChild`. If the value is a `String`, it is converted to a `TextNode` first.
2326       *
2327       * @method _setText
2328       * @param label {HTMLElement} label to be updated
2329       * @param val {String} value with which to update the label
2330       * @private
2331       */
2332      _setText: function(textField, val)
2333      {
2334          textField.empty();
2335          if(Y_Lang.isNumber(val))
2336          {
2337              val = val + "";
2338          }
2339          else if(!val)
2340          {
2341              val = "";
2342          }
2343          if(IS_STRING(val))
2344          {
2345              val = DOCUMENT.createTextNode(val);
2346          }
2347          textField.appendChild(val);
2348      },
2349  
2350      /**
2351       * Returns all the keys contained in a  `dataProvider`.
2352       *
2353       * @method _getAllKeys
2354       * @param {Array} dp Collection of objects to be parsed.
2355       * @return Object
2356       */
2357      _getAllKeys: function(dp)
2358      {
2359          var i = 0,
2360              len = dp.length,
2361              item,
2362              key,
2363              keys = {};
2364          for(; i < len; ++i)
2365          {
2366              item = dp[i];
2367              for(key in item)
2368              {
2369                  if(item.hasOwnProperty(key))
2370                  {
2371                      keys[key] = true;
2372                  }
2373              }
2374          }
2375          return keys;
2376      },
2377  
2378      /**
2379       * Constructs seriesKeys if not explicitly specified.
2380       *
2381       * @method _buildSeriesKeys
2382       * @param {Array} dataProvider The dataProvider for the chart.
2383       * @return Array
2384       * @private
2385       */
2386      _buildSeriesKeys: function(dataProvider)
2387      {
2388          var allKeys,
2389              catKey = this.get("categoryKey"),
2390              keys = [],
2391              i;
2392          if(this._seriesKeysExplicitlySet)
2393          {
2394              return this._seriesKeys;
2395          }
2396          allKeys = this._getAllKeys(dataProvider);
2397          for(i in allKeys)
2398          {
2399              if(allKeys.hasOwnProperty(i) && i !== catKey)
2400              {
2401                  keys.push(i);
2402              }
2403          }
2404          return keys;
2405      }
2406  };
2407  Y.ChartBase = ChartBase;
2408  /**
2409   * The CartesianChart class creates a chart with horizontal and vertical axes.
2410   *
2411   * @class CartesianChart
2412   * @extends ChartBase
2413   * @constructor
2414   * @submodule charts-base
2415   */
2416  Y.CartesianChart = Y.Base.create("cartesianChart", Y.Widget, [Y.ChartBase, Y.Renderer], {
2417      /**
2418       * @method renderUI
2419       * @private
2420       */
2421      renderUI: function()
2422      {
2423          var bb = this.get("boundingBox"),
2424              cb = this.get("contentBox"),
2425              tt = this.get("tooltip"),
2426              overlayClass = _getClassName("overlay");
2427          //move the position = absolute logic to a class file
2428          bb.setStyle("position", "absolute");
2429          cb.setStyle("position", "absolute");
2430          this._addAxes();
2431          this._addGridlines();
2432          this._addSeries();
2433          if(tt && tt.show)
2434          {
2435              this._addTooltip();
2436          }
2437          if(this.get("interactionType") === "planar")
2438          {
2439              this._overlay = Y.Node.create("<div></div>");
2440              this._overlay.set("id", this.get("id") + "_overlay");
2441              this._overlay.setStyle("position", "absolute");
2442              this._overlay.setStyle("background", "#fff");
2443              this._overlay.setStyle("opacity", 0);
2444              this._overlay.addClass(overlayClass);
2445              this._overlay.setStyle("zIndex", 4);
2446              cb.append(this._overlay);
2447          }
2448          this._setAriaElements(bb, cb);
2449          this._redraw();
2450      },
2451  
2452      /**
2453       * When `interactionType` is set to `planar`, listens for mouse move events and fires `planarEvent:mouseover` or `planarEvent:mouseout`
2454       * depending on the position of the mouse in relation to data points on the `Chart`.
2455       *
2456       * @method _planarEventDispatcher
2457       * @param {Object} e Event object.
2458       * @private
2459       */
2460      _planarEventDispatcher: function(e)
2461      {
2462          var graph = this.get("graph"),
2463              bb = this.get("boundingBox"),
2464              cb = graph.get("contentBox"),
2465              isTouch = e && e.hasOwnProperty("changedTouches"),
2466              pageX = isTouch ? e.changedTouches[0].pageX : e.pageX,
2467              pageY = isTouch ? e.changedTouches[0].pageY : e.pageY,
2468              posX = pageX - bb.getX(),
2469              posY = pageY - bb.getY(),
2470              offset = {
2471                  x: pageX - cb.getX(),
2472                  y: pageY - cb.getY()
2473              },
2474              sc = graph.get("seriesCollection"),
2475              series,
2476              i = 0,
2477              index,
2478              oldIndex = this._selectedIndex,
2479              item,
2480              items = [],
2481              categoryItems = [],
2482              valueItems = [],
2483              direction = this.get("direction"),
2484              hasMarkers,
2485              catAxis,
2486              valAxis,
2487              coord,
2488              //data columns and area data could be created on a graph level
2489              markerPlane,
2490              len,
2491              coords;
2492          e.halt(true);
2493          if(direction === "horizontal")
2494          {
2495              catAxis = "x";
2496              valAxis = "y";
2497          }
2498          else
2499          {
2500              valAxis = "x";
2501              catAxis = "y";
2502          }
2503          coord = offset[catAxis];
2504          if(sc)
2505          {
2506              len = sc.length;
2507              while(i < len && !markerPlane)
2508              {
2509                  if(sc[i])
2510                  {
2511                      markerPlane = sc[i].get(catAxis + "MarkerPlane");
2512                  }
2513                  i++;
2514              }
2515          }
2516          if(markerPlane)
2517          {
2518              len = markerPlane.length;
2519              for(i = 0; i < len; ++i)
2520              {
2521                  if(coord <= markerPlane[i].end && coord >= markerPlane[i].start)
2522                  {
2523                      index = i;
2524                      break;
2525                  }
2526              }
2527              len = sc.length;
2528              for(i = 0; i < len; ++i)
2529              {
2530                  series = sc[i];
2531                  coords = series.get(valAxis + "coords");
2532                  hasMarkers = series.get("markers");
2533                  if(hasMarkers && !isNaN(oldIndex) && oldIndex > -1)
2534                  {
2535                      series.updateMarkerState("mouseout", oldIndex);
2536                  }
2537                  if(coords && coords[index] > -1)
2538                  {
2539                      if(hasMarkers && !isNaN(index) && index > -1)
2540                      {
2541                          series.updateMarkerState("mouseover", index);
2542                      }
2543                      item = this.getSeriesItems(series, index);
2544                      categoryItems.push(item.category);
2545                      valueItems.push(item.value);
2546                      items.push(series);
2547                  }
2548  
2549              }
2550              this._selectedIndex = index;
2551  
2552              /**
2553               * Broadcasts when `interactionType` is set to `planar` and a series' marker plane has received a mouseover event.
2554               *
2555               *
2556               * @event planarEvent:mouseover
2557               * @preventable false
2558               * @param {EventFacade} e Event facade with the following additional
2559               *   properties:
2560               *  <dl>
2561               *      <dt>categoryItem</dt><dd>An array of hashes, each containing information about the category `Axis` of each marker
2562               *      whose plane has been intersected.</dd>
2563               *      <dt>valueItem</dt><dd>An array of hashes, each containing information about the value `Axis` of each marker whose
2564               *      plane has been intersected.</dd>
2565               *      <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
2566               *      <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
2567               *      <dt>pageX</dt><dd>The x location of the event on the page (including scroll)</dd>
2568               *      <dt>pageY</dt><dd>The y location of the event on the page (including scroll)</dd>
2569               *      <dt>items</dt><dd>An array including all the series which contain a marker whose plane has been intersected.</dd>
2570               *      <dt>index</dt><dd>Index of the markers in their respective series.</dd>
2571               *      <dt>originEvent</dt><dd>Underlying dom event.</dd>
2572               *  </dl>
2573               */
2574              /**
2575               * Broadcasts when `interactionType` is set to `planar` and a series' marker plane has received a mouseout event.
2576               *
2577               * @event planarEvent:mouseout
2578               * @preventable false
2579               * @param {EventFacade} e
2580               */
2581              if(index > -1)
2582              {
2583                  this.fire("planarEvent:mouseover", {
2584                      categoryItem:categoryItems,
2585                      valueItem:valueItems,
2586                      x:posX,
2587                      y:posY,
2588                      pageX:pageX,
2589                      pageY:pageY,
2590                      items:items,
2591                      index:index,
2592                      originEvent:e
2593                  });
2594              }
2595              else
2596              {
2597                  this.fire("planarEvent:mouseout");
2598              }
2599          }
2600      },
2601  
2602      /**
2603       * Indicates the default series type for the chart.
2604       *
2605       * @property _type
2606       * @type {String}
2607       * @private
2608       */
2609      _type: "combo",
2610  
2611      /**
2612       * Queue of axes instances that will be updated. This method is used internally to determine when all axes have been updated.
2613       *
2614       * @property _itemRenderQueue
2615       * @type Array
2616       * @private
2617       */
2618      _itemRenderQueue: null,
2619  
2620      /**
2621       * Adds an `Axis` instance to the `_itemRenderQueue`.
2622       *
2623       * @method _addToAxesRenderQueue
2624       * @param {Axis} axis An `Axis` instance.
2625       * @private
2626       */
2627      _addToAxesRenderQueue: function(axis)
2628      {
2629          if(!this._itemRenderQueue)
2630          {
2631              this._itemRenderQueue = [];
2632          }
2633          if(Y.Array.indexOf(this._itemRenderQueue, axis) < 0)
2634          {
2635              this._itemRenderQueue.push(axis);
2636          }
2637      },
2638  
2639      /**
2640       * Adds axis instance to the appropriate array based on position
2641       *
2642       * @method _addToAxesCollection
2643       * @param {String} position The position of the axis
2644       * @param {Axis} axis The `Axis` instance
2645       */
2646      _addToAxesCollection: function(position, axis)
2647      {
2648          var axesCollection = this.get(position + "AxesCollection");
2649          if(!axesCollection)
2650          {
2651              axesCollection = [];
2652              this.set(position + "AxesCollection", axesCollection);
2653          }
2654          axesCollection.push(axis);
2655      },
2656  
2657      /**
2658       * Returns the default value for the `seriesCollection` attribute.
2659       *
2660       * @method _getDefaultSeriesCollection
2661       * @param {Array} val Array containing either `CartesianSeries` instances or objects containing data to construct series instances.
2662       * @return Array
2663       * @private
2664       */
2665      _getDefaultSeriesCollection: function()
2666      {
2667          var seriesCollection,
2668              dataProvider = this.get("dataProvider");
2669          if(dataProvider)
2670          {
2671              seriesCollection = this._parseSeriesCollection();
2672          }
2673          return seriesCollection;
2674      },
2675  
2676      /**
2677       * Parses and returns a series collection from an object and default properties.
2678       *
2679       * @method _parseSeriesCollection
2680       * @param {Object} val Object contain properties for series being set.
2681       * @return Object
2682       * @private
2683       */
2684      _parseSeriesCollection: function(val)
2685      {
2686          var dir = this.get("direction"),
2687              seriesStyles = this.get("styles").series,
2688              stylesAreArray = seriesStyles && Y_Lang.isArray(seriesStyles),
2689              stylesIndex,
2690              setStyles,
2691              globalStyles,
2692              sc = [],
2693              catAxis,
2694              valAxis,
2695              tempKeys = [],
2696              series,
2697              seriesKeys = this.get("seriesKeys").concat(),
2698              i,
2699              index,
2700              l,
2701              type = this.get("type"),
2702              key,
2703              catKey,
2704              seriesKey,
2705              graph,
2706              orphans = [],
2707              categoryKey = this.get("categoryKey"),
2708              showMarkers = this.get("showMarkers"),
2709              showAreaFill = this.get("showAreaFill"),
2710              showLines = this.get("showLines");
2711          val = val ? val.concat() : [];
2712          if(dir === "vertical")
2713          {
2714              catAxis = "yAxis";
2715              catKey = "yKey";
2716              valAxis = "xAxis";
2717              seriesKey = "xKey";
2718          }
2719          else
2720          {
2721              catAxis = "xAxis";
2722              catKey = "xKey";
2723              valAxis = "yAxis";
2724              seriesKey = "yKey";
2725          }
2726          l = val.length;
2727          while(val && val.length > 0)
2728          {
2729              series = val.shift();
2730              key = this._getBaseAttribute(series, seriesKey);
2731              if(key)
2732              {
2733                  index = Y.Array.indexOf(seriesKeys, key);
2734                  if(index > -1)
2735                  {
2736                      seriesKeys.splice(index, 1);
2737                      tempKeys.push(key);
2738                      sc.push(series);
2739                  }
2740                  else
2741                  {
2742                      orphans.push(series);
2743                  }
2744              }
2745              else
2746              {
2747                  orphans.push(series);
2748              }
2749          }
2750          while(orphans.length > 0)
2751          {
2752              series = orphans.shift();
2753              if(seriesKeys.length > 0)
2754              {
2755                  key = seriesKeys.shift();
2756                  this._setBaseAttribute(series, seriesKey, key);
2757                  tempKeys.push(key);
2758                  sc.push(series);
2759              }
2760              else if(series instanceof Y.CartesianSeries)
2761              {
2762                  series.destroy(true);
2763              }
2764          }
2765          if(seriesKeys.length > 0)
2766          {
2767              tempKeys = tempKeys.concat(seriesKeys);
2768          }
2769          l = tempKeys.length;
2770          for(i = 0; i < l; ++i)
2771          {
2772              series = sc[i] || {type:type};
2773              if(series instanceof Y.CartesianSeries)
2774              {
2775                  this._parseSeriesAxes(series);
2776              }
2777              else
2778              {
2779                  series[catKey] = series[catKey] || categoryKey;
2780                  series[seriesKey] = series[seriesKey] || seriesKeys.shift();
2781                  series[catAxis] = this._getCategoryAxis();
2782                  series[valAxis] = this._getSeriesAxis(series[seriesKey]);
2783  
2784                  series.type = series.type || type;
2785                  series.direction = series.direction || dir;
2786  
2787                  if(series.type === "combo" ||
2788                      series.type === "stackedcombo" ||
2789                      series.type === "combospline" ||
2790                      series.type === "stackedcombospline")
2791                  {
2792                      if(showAreaFill !== null)
2793                      {
2794                          series.showAreaFill = (series.showAreaFill !== null && series.showAreaFill !== undefined) ?
2795                                                 series.showAreaFill : showAreaFill;
2796                      }
2797                      if(showMarkers !== null)
2798                      {
2799                          series.showMarkers = (series.showMarkers !== null && series.showMarkers !== undefined) ? series.showMarkers : showMarkers;
2800                      }
2801                      if(showLines !== null)
2802                      {
2803                          series.showLines = (series.showLines !== null && series.showLines !== undefined) ? series.showLines : showLines;
2804                      }
2805                  }
2806                  if(seriesStyles)
2807                  {
2808                      stylesIndex = stylesAreArray ? i : series[seriesKey];
2809                      globalStyles = seriesStyles[stylesIndex];
2810                      if(globalStyles)
2811                      {
2812                          setStyles = series.styles;
2813                          if(setStyles)
2814                          {
2815                              series.styles = this._mergeStyles(setStyles, globalStyles);
2816                          }
2817                          else
2818                          {
2819                              series.styles = globalStyles;
2820                          }
2821                      }
2822                  }
2823                  sc[i] = series;
2824              }
2825          }
2826          if(sc)
2827          {
2828              graph = this.get("graph");
2829              graph.set("seriesCollection", sc);
2830              sc = graph.get("seriesCollection");
2831          }
2832          return sc;
2833      },
2834  
2835      /**
2836       * Parse and sets the axes for a series instance.
2837       *
2838       * @method _parseSeriesAxes
2839       * @param {CartesianSeries} series A `CartesianSeries` instance.
2840       * @private
2841       */
2842      _parseSeriesAxes: function(series)
2843      {
2844          var axes = this.get("axes"),
2845              xAxis = series.get("xAxis"),
2846              yAxis = series.get("yAxis"),
2847              YAxis = Y.Axis,
2848              axis;
2849          if(xAxis && !(xAxis instanceof YAxis) && Y_Lang.isString(xAxis) && axes.hasOwnProperty(xAxis))
2850          {
2851              axis = axes[xAxis];
2852              if(axis instanceof YAxis)
2853              {
2854                  series.set("xAxis", axis);
2855              }
2856          }
2857          if(yAxis && !(yAxis instanceof YAxis) && Y_Lang.isString(yAxis) && axes.hasOwnProperty(yAxis))
2858          {
2859              axis = axes[yAxis];
2860              if(axis instanceof YAxis)
2861              {
2862                  series.set("yAxis", axis);
2863              }
2864          }
2865  
2866      },
2867  
2868      /**
2869       * Returns the category axis instance for the chart.
2870       *
2871       * @method _getCategoryAxis
2872       * @return Axis
2873       * @private
2874       */
2875      _getCategoryAxis: function()
2876      {
2877          var axis,
2878              axes = this.get("axes"),
2879              categoryAxisName = this.get("categoryAxisName") || this.get("categoryKey");
2880          axis = axes[categoryAxisName];
2881          return axis;
2882      },
2883  
2884      /**
2885       * Returns the value axis for a series.
2886       *
2887       * @method _getSeriesAxis
2888       * @param {String} key The key value used to determine the axis instance.
2889       * @return Axis
2890       * @private
2891       */
2892      _getSeriesAxis:function(key, axisName)
2893      {
2894          var axes = this.get("axes"),
2895              i,
2896              keys,
2897              axis;
2898          if(axes)
2899          {
2900              if(axisName && axes.hasOwnProperty(axisName))
2901              {
2902                  axis = axes[axisName];
2903              }
2904              else
2905              {
2906                  for(i in axes)
2907                  {
2908                      if(axes.hasOwnProperty(i))
2909                      {
2910                          keys = axes[i].get("keys");
2911                          if(keys && keys.hasOwnProperty(key))
2912                          {
2913                              axis = axes[i];
2914                              break;
2915                          }
2916                      }
2917                  }
2918              }
2919          }
2920          return axis;
2921      },
2922  
2923      /**
2924       * Gets an attribute from an object, using a getter for Base objects and a property for object
2925       * literals. Used for determining attributes from series/axis references which can be an actual class instance
2926       * or a hash of properties that will be used to create a class instance.
2927       *
2928       * @method _getBaseAttribute
2929       * @param {Object} item Object or instance in which the attribute resides.
2930       * @param {String} key Attribute whose value will be returned.
2931       * @return Object
2932       * @private
2933       */
2934      _getBaseAttribute: function(item, key)
2935      {
2936          if(item instanceof Y.Base)
2937          {
2938              return item.get(key);
2939          }
2940          if(item.hasOwnProperty(key))
2941          {
2942              return item[key];
2943          }
2944          return null;
2945      },
2946  
2947      /**
2948       * Sets an attribute on an object, using a setter of Base objects and a property for object
2949       * literals. Used for setting attributes on a Base class, either directly or to be stored in an object literal
2950       * for use at instantiation.
2951       *
2952       * @method _setBaseAttribute
2953       * @param {Object} item Object or instance in which the attribute resides.
2954       * @param {String} key Attribute whose value will be assigned.
2955       * @param {Object} value Value to be assigned to the attribute.
2956       * @private
2957       */
2958      _setBaseAttribute: function(item, key, value)
2959      {
2960          if(item instanceof Y.Base)
2961          {
2962              item.set(key, value);
2963          }
2964          else
2965          {
2966              item[key] = value;
2967          }
2968      },
2969  
2970      /**
2971       * Creates `Axis` instances.
2972       *
2973       * @method _setAxes
2974       * @param {Object} val Object containing `Axis` instances or objects in which to construct `Axis` instances.
2975       * @return Object
2976       * @private
2977       */
2978      _setAxes: function(val)
2979      {
2980          var hash = this._parseAxes(val),
2981              axes = {},
2982              axesAttrs = {
2983                  edgeOffset: "edgeOffset",
2984                  calculateEdgeOffset: "calculateEdgeOffset",
2985                  position: "position",
2986                  overlapGraph:"overlapGraph",
2987                  labelValues: "labelValues",
2988                  hideFirstMajorUnit: "hideFirstMajorUnit",
2989                  hideLastMajorUnit: "hideLastMajorUnit",
2990                  labelFunction:"labelFunction",
2991                  labelFunctionScope:"labelFunctionScope",
2992                  labelFormat:"labelFormat",
2993                  appendLabelFunction: "appendLabelFunction",
2994                  appendTitleFunction: "appendTitleFunction",
2995                  maximum:"maximum",
2996                  minimum:"minimum",
2997                  roundingMethod:"roundingMethod",
2998                  alwaysShowZero:"alwaysShowZero",
2999                  scaleType: "scaleType",
3000                  title:"title",
3001                  width:"width",
3002                  height:"height"
3003              },
3004              dp = this.get("dataProvider"),
3005              ai,
3006              i,
3007              pos,
3008              axis,
3009              axisPosition,
3010              dh,
3011              AxisClass,
3012              config,
3013              axesCollection;
3014          for(i in hash)
3015          {
3016              if(hash.hasOwnProperty(i))
3017              {
3018                  dh = hash[i];
3019                  if(dh instanceof Y.Axis)
3020                  {
3021                      axis = dh;
3022                  }
3023                  else
3024                  {
3025                      axis = null;
3026                      config = {};
3027                      config.dataProvider = dh.dataProvider || dp;
3028                      config.keys = dh.keys;
3029  
3030                      if(dh.hasOwnProperty("roundingUnit"))
3031                      {
3032                          config.roundingUnit = dh.roundingUnit;
3033                      }
3034                      pos = dh.position;
3035                      if(dh.styles)
3036                      {
3037                          config.styles = dh.styles;
3038                      }
3039                      config.position = dh.position;
3040                      for(ai in axesAttrs)
3041                      {
3042                          if(axesAttrs.hasOwnProperty(ai) && dh.hasOwnProperty(ai))
3043                          {
3044                              config[ai] = dh[ai];
3045                          }
3046                      }
3047  
3048                      //only check for existing axis if we constructed the default axes already
3049                      if(val)
3050                      {
3051                          axis = this.getAxisByKey(i);
3052                      }
3053  
3054                      if(axis && axis instanceof Y.Axis)
3055                      {
3056                          axisPosition = axis.get("position");
3057                          if(pos !== axisPosition)
3058                          {
3059                              if(axisPosition !== "none")
3060                              {
3061                                  axesCollection = this.get(axisPosition + "AxesCollection");
3062                                  axesCollection.splice(Y.Array.indexOf(axesCollection, axis), 1);
3063                              }
3064                              if(pos !== "none")
3065                              {
3066                                  this._addToAxesCollection(pos, axis);
3067                              }
3068                          }
3069                          axis.setAttrs(config);
3070                      }
3071                      else
3072                      {
3073                          AxisClass = this._getAxisClass(dh.type);
3074                          axis = new AxisClass(config);
3075                          axis.after("axisRendered", Y.bind(this._itemRendered, this));
3076                      }
3077                  }
3078  
3079                  if(axis)
3080                  {
3081                      axesCollection = this.get(pos + "AxesCollection");
3082                      if(axesCollection && Y.Array.indexOf(axesCollection, axis) > 0)
3083                      {
3084                          axis.set("overlapGraph", false);
3085                      }
3086                      axes[i] = axis;
3087                  }
3088              }
3089          }
3090          return axes;
3091      },
3092  
3093      /**
3094       * Adds axes to the chart.
3095       *
3096       * @method _addAxes
3097       * @private
3098       */
3099      _addAxes: function()
3100      {
3101          var axes = this.get("axes"),
3102              i,
3103              axis,
3104              pos,
3105              w = this.get("width"),
3106              h = this.get("height"),
3107              node = Y.Node.one(this._parentNode);
3108          if(!this._axesCollection)
3109          {
3110              this._axesCollection = [];
3111          }
3112          for(i in axes)
3113          {
3114              if(axes.hasOwnProperty(i))
3115              {
3116                  axis = axes[i];
3117                  if(axis instanceof Y.Axis)
3118                  {
3119                      if(!w)
3120                      {
3121                          this.set("width", node.get("offsetWidth"));
3122                          w = this.get("width");
3123                      }
3124                      if(!h)
3125                      {
3126                          this.set("height", node.get("offsetHeight"));
3127                          h = this.get("height");
3128                      }
3129                      this._addToAxesRenderQueue(axis);
3130                      pos = axis.get("position");
3131                      if(!this.get(pos + "AxesCollection"))
3132                      {
3133                          this.set(pos + "AxesCollection", [axis]);
3134                      }
3135                      else
3136                      {
3137                          this.get(pos + "AxesCollection").push(axis);
3138                      }
3139                      this._axesCollection.push(axis);
3140                      if(axis.get("keys").hasOwnProperty(this.get("categoryKey")))
3141                      {
3142                          this.set("categoryAxis", axis);
3143                      }
3144                      axis.render(this.get("contentBox"));
3145                  }
3146              }
3147          }
3148      },
3149  
3150      /**
3151       * Renders the Graph.
3152       *
3153       * @method _addSeries
3154       * @private
3155       */
3156      _addSeries: function()
3157      {
3158          var graph = this.get("graph");
3159          graph.render(this.get("contentBox"));
3160  
3161      },
3162  
3163      /**
3164       * Adds gridlines to the chart.
3165       *
3166       * @method _addGridlines
3167       * @private
3168       */
3169      _addGridlines: function()
3170      {
3171          var graph = this.get("graph"),
3172              hgl = this.get("horizontalGridlines"),
3173              vgl = this.get("verticalGridlines"),
3174              direction = this.get("direction"),
3175              leftAxesCollection = this.get("leftAxesCollection"),
3176              rightAxesCollection = this.get("rightAxesCollection"),
3177              bottomAxesCollection = this.get("bottomAxesCollection"),
3178              topAxesCollection = this.get("topAxesCollection"),
3179              seriesAxesCollection,
3180              catAxis = this.get("categoryAxis"),
3181              hAxis,
3182              vAxis;
3183          if(this._axesCollection)
3184          {
3185              seriesAxesCollection = this._axesCollection.concat();
3186              seriesAxesCollection.splice(Y.Array.indexOf(seriesAxesCollection, catAxis), 1);
3187          }
3188          if(hgl)
3189          {
3190              if(leftAxesCollection && leftAxesCollection[0])
3191              {
3192                  hAxis = leftAxesCollection[0];
3193              }
3194              else if(rightAxesCollection && rightAxesCollection[0])
3195              {
3196                  hAxis = rightAxesCollection[0];
3197              }
3198              else
3199              {
3200                  hAxis = direction === "horizontal" ? catAxis : seriesAxesCollection[0];
3201              }
3202              if(!this._getBaseAttribute(hgl, "axis") && hAxis)
3203              {
3204                  this._setBaseAttribute(hgl, "axis", hAxis);
3205              }
3206              if(this._getBaseAttribute(hgl, "axis"))
3207              {
3208                  graph.set("horizontalGridlines", hgl);
3209              }
3210          }
3211          if(vgl)
3212          {
3213              if(bottomAxesCollection && bottomAxesCollection[0])
3214              {
3215                  vAxis = bottomAxesCollection[0];
3216              }
3217              else if (topAxesCollection && topAxesCollection[0])
3218              {
3219                  vAxis = topAxesCollection[0];
3220              }
3221              else
3222              {
3223                  vAxis = direction === "vertical" ? catAxis : seriesAxesCollection[0];
3224              }
3225              if(!this._getBaseAttribute(vgl, "axis") && vAxis)
3226              {
3227                  this._setBaseAttribute(vgl, "axis", vAxis);
3228              }
3229              if(this._getBaseAttribute(vgl, "axis"))
3230              {
3231                  graph.set("verticalGridlines", vgl);
3232              }
3233          }
3234      },
3235  
3236      /**
3237       * Default Function for the axes attribute.
3238       *
3239       * @method _getDefaultAxes
3240       * @return Object
3241       * @private
3242       */
3243      _getDefaultAxes: function()
3244      {
3245          var axes;
3246          if(this.get("dataProvider"))
3247          {
3248              axes = this._parseAxes();
3249          }
3250          return axes;
3251      },
3252  
3253      /**
3254       * Generates and returns a key-indexed object containing `Axis` instances or objects used to create `Axis` instances.
3255       *
3256       * @method _parseAxes
3257       * @param {Object} axes Object containing `Axis` instances or `Axis` attributes.
3258       * @return Object
3259       * @private
3260       */
3261      _parseAxes: function(axes)
3262      {
3263          var catKey = this.get("categoryKey"),
3264              axis,
3265              attr,
3266              keys,
3267              newAxes = {},
3268              claimedKeys = [],
3269              newKeys = [],
3270              categoryAxisName = this.get("categoryAxisName") || this.get("categoryKey"),
3271              valueAxisName = this.get("valueAxisName"),
3272              seriesKeys = this.get("seriesKeys").concat(),
3273              i,
3274              l,
3275              ii,
3276              ll,
3277              cIndex,
3278              direction = this.get("direction"),
3279              seriesPosition,
3280              categoryPosition,
3281              valueAxes = [],
3282              seriesAxis = this.get("stacked") ? "stacked" : "numeric";
3283          if(direction === "vertical")
3284          {
3285              seriesPosition = "bottom";
3286              categoryPosition = "left";
3287          }
3288          else
3289          {
3290              seriesPosition = "left";
3291              categoryPosition = "bottom";
3292          }
3293          if(axes)
3294          {
3295              for(i in axes)
3296              {
3297                  if(axes.hasOwnProperty(i))
3298                  {
3299                      axis = axes[i];
3300                      keys = this._getBaseAttribute(axis, "keys");
3301                      attr = this._getBaseAttribute(axis, "type");
3302                      if(attr === "time" || attr === "category")
3303                      {
3304                          categoryAxisName = i;
3305                          this.set("categoryAxisName", i);
3306                          if(Y_Lang.isArray(keys) && keys.length > 0)
3307                          {
3308                              catKey = keys[0];
3309                              this.set("categoryKey", catKey);
3310                          }
3311                          newAxes[i] = axis;
3312                      }
3313                      else if(i === categoryAxisName)
3314                      {
3315                          newAxes[i] = axis;
3316                      }
3317                      else
3318                      {
3319                          newAxes[i] = axis;
3320                          if(i !== valueAxisName && keys && Y_Lang.isArray(keys))
3321                          {
3322                              ll = keys.length;
3323                              for(ii = 0; ii < ll; ++ii)
3324                              {
3325                                  claimedKeys.push(keys[ii]);
3326                              }
3327                              valueAxes.push(newAxes[i]);
3328                          }
3329                          if(!(this._getBaseAttribute(newAxes[i], "type")))
3330                          {
3331                              this._setBaseAttribute(newAxes[i], "type", seriesAxis);
3332                          }
3333                          if(!(this._getBaseAttribute(newAxes[i], "position")))
3334                          {
3335                              this._setBaseAttribute(
3336                                  newAxes[i],
3337                                  "position",
3338                                  this._getDefaultAxisPosition(newAxes[i], valueAxes, seriesPosition)
3339                              );
3340                          }
3341                      }
3342                  }
3343              }
3344          }
3345          cIndex = Y.Array.indexOf(seriesKeys, catKey);
3346          if(cIndex > -1)
3347          {
3348              seriesKeys.splice(cIndex, 1);
3349          }
3350          l = seriesKeys.length;
3351          for(i = 0; i < l; ++i)
3352          {
3353              cIndex = Y.Array.indexOf(claimedKeys, seriesKeys[i]);
3354              if(cIndex > -1)
3355              {
3356                  newKeys = newKeys.concat(claimedKeys.splice(cIndex, 1));
3357              }
3358          }
3359          claimedKeys = newKeys.concat(claimedKeys);
3360          l = claimedKeys.length;
3361          for(i = 0; i < l; i = i + 1)
3362          {
3363              cIndex = Y.Array.indexOf(seriesKeys, claimedKeys[i]);
3364              if(cIndex > -1)
3365              {
3366                  seriesKeys.splice(cIndex, 1);
3367              }
3368          }
3369          if(!newAxes.hasOwnProperty(categoryAxisName))
3370          {
3371              newAxes[categoryAxisName] = {};
3372          }
3373          if(!(this._getBaseAttribute(newAxes[categoryAxisName], "keys")))
3374          {
3375              this._setBaseAttribute(newAxes[categoryAxisName], "keys", [catKey]);
3376          }
3377  
3378          if(!(this._getBaseAttribute(newAxes[categoryAxisName], "position")))
3379          {
3380              this._setBaseAttribute(newAxes[categoryAxisName], "position", categoryPosition);
3381          }
3382  
3383          if(!(this._getBaseAttribute(newAxes[categoryAxisName], "type")))
3384          {
3385              this._setBaseAttribute(newAxes[categoryAxisName], "type", this.get("categoryType"));
3386          }
3387          if(!newAxes.hasOwnProperty(valueAxisName) && seriesKeys && seriesKeys.length > 0)
3388          {
3389              newAxes[valueAxisName] = {keys:seriesKeys};
3390              valueAxes.push(newAxes[valueAxisName]);
3391          }
3392          if(claimedKeys.length > 0)
3393          {
3394              if(seriesKeys.length > 0)
3395              {
3396                  seriesKeys = claimedKeys.concat(seriesKeys);
3397              }
3398              else
3399              {
3400                  seriesKeys = claimedKeys;
3401              }
3402          }
3403          if(newAxes.hasOwnProperty(valueAxisName))
3404          {
3405              if(!(this._getBaseAttribute(newAxes[valueAxisName], "position")))
3406              {
3407                  this._setBaseAttribute(
3408                      newAxes[valueAxisName],
3409                      "position",
3410                      this._getDefaultAxisPosition(newAxes[valueAxisName], valueAxes, seriesPosition)
3411                  );
3412              }
3413              this._setBaseAttribute(newAxes[valueAxisName], "type", seriesAxis);
3414              this._setBaseAttribute(newAxes[valueAxisName], "keys", seriesKeys);
3415          }
3416          if(!this._wereSeriesKeysExplicitlySet())
3417          {
3418              this.set("seriesKeys", seriesKeys, {src: "internal"});
3419          }
3420          return newAxes;
3421      },
3422  
3423      /**
3424       * Determines the position of an axis when one is not specified.
3425       *
3426       * @method _getDefaultAxisPosition
3427       * @param {Axis} axis `Axis` instance.
3428       * @param {Array} valueAxes Array of `Axis` instances.
3429       * @param {String} position Default position depending on the direction of the chart and type of axis.
3430       * @return String
3431       * @private
3432       */
3433      _getDefaultAxisPosition: function(axis, valueAxes, position)
3434      {
3435          var direction = this.get("direction"),
3436              i = Y.Array.indexOf(valueAxes, axis);
3437  
3438          if(valueAxes[i - 1] && valueAxes[i - 1].position)
3439          {
3440              if(direction === "horizontal")
3441              {
3442                  if(valueAxes[i - 1].position === "left")
3443                  {
3444                      position = "right";
3445                  }
3446                  else if(valueAxes[i - 1].position === "right")
3447                  {
3448                      position = "left";
3449                  }
3450              }
3451              else
3452              {
3453                  if (valueAxes[i -1].position === "bottom")
3454                  {
3455                      position = "top";
3456                  }
3457                  else
3458                  {
3459                      position = "bottom";
3460                  }
3461              }
3462          }
3463          return position;
3464      },
3465  
3466  
3467      /**
3468       * Returns an object literal containing a categoryItem and a valueItem for a given series index. Below is the structure of each:
3469       *
3470       * @method getSeriesItems
3471       * @param {CartesianSeries} series Reference to a series.
3472       * @param {Number} index Index of the specified item within a series.
3473       * @return Object An object literal containing the following:
3474       *
3475       *  <dl>
3476       *      <dt>categoryItem</dt><dd>Object containing the following data related to the category axis of the series.
3477       *  <dl>
3478       *      <dt>axis</dt><dd>Reference to the category axis of the series.</dd>
3479       *      <dt>key</dt><dd>Category key for the series.</dd>
3480       *      <dt>value</dt><dd>Value on the axis corresponding to the series index.</dd>
3481       *  </dl>
3482       *      </dd>
3483       *      <dt>valueItem</dt><dd>Object containing the following data related to the category axis of the series.
3484       *  <dl>
3485       *      <dt>axis</dt><dd>Reference to the value axis of the series.</dd>
3486       *      <dt>key</dt><dd>Value key for the series.</dd>
3487       *      <dt>value</dt><dd>Value on the axis corresponding to the series index.</dd>
3488       *  </dl>
3489       *      </dd>
3490       *  </dl>
3491       */
3492      getSeriesItems: function(series, index)
3493      {
3494          var xAxis = series.get("xAxis"),
3495              yAxis = series.get("yAxis"),
3496              xKey = series.get("xKey"),
3497              yKey = series.get("yKey"),
3498              categoryItem,
3499              valueItem;
3500          if(this.get("direction") === "vertical")
3501          {
3502              categoryItem = {
3503                  axis:yAxis,
3504                  key:yKey,
3505                  value:yAxis.getKeyValueAt(yKey, index)
3506              };
3507              valueItem = {
3508                  axis:xAxis,
3509                  key:xKey,
3510                  value: xAxis.getKeyValueAt(xKey, index)
3511              };
3512          }
3513          else
3514          {
3515              valueItem = {
3516                  axis:yAxis,
3517                  key:yKey,
3518                  value:yAxis.getKeyValueAt(yKey, index)
3519              };
3520              categoryItem = {
3521                  axis:xAxis,
3522                  key:xKey,
3523                  value: xAxis.getKeyValueAt(xKey, index)
3524              };
3525          }
3526          categoryItem.displayName = series.get("categoryDisplayName");
3527          valueItem.displayName = series.get("valueDisplayName");
3528          categoryItem.value = categoryItem.axis.getKeyValueAt(categoryItem.key, index);
3529          valueItem.value = valueItem.axis.getKeyValueAt(valueItem.key, index);
3530          return {category:categoryItem, value:valueItem};
3531      },
3532  
3533      /**
3534       * Handler for sizeChanged event.
3535       *
3536       * @method _sizeChanged
3537       * @param {Object} e Event object.
3538       * @private
3539       */
3540      _sizeChanged: function()
3541      {
3542          if(this._axesCollection)
3543          {
3544              var ac = this._axesCollection,
3545                  i = 0,
3546                  l = ac.length;
3547              for(; i < l; ++i)
3548              {
3549                  this._addToAxesRenderQueue(ac[i]);
3550              }
3551              this._redraw();
3552          }
3553      },
3554  
3555      /**
3556       * Returns the maximum distance in pixels that the extends outside the top bounds of all vertical axes.
3557       *
3558       * @method _getTopOverflow
3559       * @param {Array} set1 Collection of axes to check.
3560       * @param {Array} set2 Seconf collection of axes to check.
3561       * @param {Number} width Width of the axes
3562       * @return Number
3563       * @private
3564       */
3565      _getTopOverflow: function(set1, set2, height)
3566      {
3567          var i = 0,
3568              len,
3569              overflow = 0,
3570              axis;
3571          if(set1)
3572          {
3573              len = set1.length;
3574              for(; i < len; ++i)
3575              {
3576                  axis = set1[i];
3577                  overflow = Math.max(
3578                      overflow,
3579                      Math.abs(axis.getMaxLabelBounds().top) - axis.getEdgeOffset(axis.get("styles").majorTicks.count, height)
3580                  );
3581              }
3582          }
3583          if(set2)
3584          {
3585              i = 0;
3586              len = set2.length;
3587              for(; i < len; ++i)
3588              {
3589                  axis = set2[i];
3590                  overflow = Math.max(
3591                      overflow,
3592                      Math.abs(axis.getMaxLabelBounds().top) - axis.getEdgeOffset(axis.get("styles").majorTicks.count, height)
3593                  );
3594              }
3595          }
3596          return overflow;
3597      },
3598  
3599      /**
3600       * Returns the maximum distance in pixels that the extends outside the right bounds of all horizontal axes.
3601       *
3602       * @method _getRightOverflow
3603       * @param {Array} set1 Collection of axes to check.
3604       * @param {Array} set2 Seconf collection of axes to check.
3605       * @param {Number} width Width of the axes
3606       * @return Number
3607       * @private
3608       */
3609      _getRightOverflow: function(set1, set2, width)
3610      {
3611          var i = 0,
3612              len,
3613              overflow = 0,
3614              axis;
3615          if(set1)
3616          {
3617              len = set1.length;
3618              for(; i < len; ++i)
3619              {
3620                  axis = set1[i];
3621                  overflow = Math.max(
3622                      overflow,
3623                      axis.getMaxLabelBounds().right - axis.getEdgeOffset(axis.get("styles").majorTicks.count, width)
3624                  );
3625              }
3626          }
3627          if(set2)
3628          {
3629              i = 0;
3630              len = set2.length;
3631              for(; i < len; ++i)
3632              {
3633                  axis = set2[i];
3634                  overflow = Math.max(
3635                      overflow,
3636                      axis.getMaxLabelBounds().right - axis.getEdgeOffset(axis.get("styles").majorTicks.count, width)
3637                  );
3638              }
3639          }
3640          return overflow;
3641      },
3642  
3643      /**
3644       * Returns the maximum distance in pixels that the extends outside the left bounds of all horizontal axes.
3645       *
3646       * @method _getLeftOverflow
3647       * @param {Array} set1 Collection of axes to check.
3648       * @param {Array} set2 Seconf collection of axes to check.
3649       * @param {Number} width Width of the axes
3650       * @return Number
3651       * @private
3652       */
3653      _getLeftOverflow: function(set1, set2, width)
3654      {
3655          var i = 0,
3656              len,
3657              overflow = 0,
3658              axis;
3659          if(set1)
3660          {
3661              len = set1.length;
3662              for(; i < len; ++i)
3663              {
3664                  axis = set1[i];
3665                  overflow = Math.max(
3666                      overflow,
3667                      Math.abs(axis.getMinLabelBounds().left) - axis.getEdgeOffset(axis.get("styles").majorTicks.count, width)
3668                  );
3669              }
3670          }
3671          if(set2)
3672          {
3673              i = 0;
3674              len = set2.length;
3675              for(; i < len; ++i)
3676              {
3677                  axis = set2[i];
3678                  overflow = Math.max(
3679                      overflow,
3680                      Math.abs(axis.getMinLabelBounds().left) - axis.getEdgeOffset(axis.get("styles").majorTicks.count, width)
3681                  );
3682              }
3683          }
3684          return overflow;
3685      },
3686  
3687      /**
3688       * Returns the maximum distance in pixels that the extends outside the bottom bounds of all vertical axes.
3689       *
3690       * @method _getBottomOverflow
3691       * @param {Array} set1 Collection of axes to check.
3692       * @param {Array} set2 Seconf collection of axes to check.
3693       * @param {Number} height Height of the axes
3694       * @return Number
3695       * @private
3696       */
3697      _getBottomOverflow: function(set1, set2, height)
3698      {
3699          var i = 0,
3700              len,
3701              overflow = 0,
3702              axis;
3703          if(set1)
3704          {
3705              len = set1.length;
3706              for(; i < len; ++i)
3707              {
3708                  axis = set1[i];
3709                  overflow = Math.max(
3710                      overflow,
3711                      axis.getMinLabelBounds().bottom - axis.getEdgeOffset(axis.get("styles").majorTicks.count, height)
3712                  );
3713              }
3714          }
3715          if(set2)
3716          {
3717              i = 0;
3718              len = set2.length;
3719              for(; i < len; ++i)
3720              {
3721                  axis = set2[i];
3722                  overflow = Math.max(
3723                      overflow,
3724                      axis.getMinLabelBounds().bottom - axis.getEdgeOffset(axis.get("styles").majorTicks.count, height)
3725                  );
3726              }
3727          }
3728          return overflow;
3729      },
3730  
3731      /**
3732       * Redraws and position all the components of the chart instance.
3733       *
3734       * @method _redraw
3735       * @private
3736       */
3737      _redraw: function()
3738      {
3739          if(this._drawing)
3740          {
3741              this._callLater = true;
3742              return;
3743          }
3744          this._drawing = true;
3745          this._callLater = false;
3746          var w = this.get("width"),
3747              h = this.get("height"),
3748              leftPaneWidth = 0,
3749              rightPaneWidth = 0,
3750              topPaneHeight = 0,
3751              bottomPaneHeight = 0,
3752              leftAxesCollection = this.get("leftAxesCollection"),
3753              rightAxesCollection = this.get("rightAxesCollection"),
3754              topAxesCollection = this.get("topAxesCollection"),
3755              bottomAxesCollection = this.get("bottomAxesCollection"),
3756              i = 0,
3757              l,
3758              axis,
3759              graphOverflow = "visible",
3760              graph = this.get("graph"),
3761              topOverflow,
3762              bottomOverflow,
3763              leftOverflow,
3764              rightOverflow,
3765              graphWidth,
3766              graphHeight,
3767              graphX,
3768              graphY,
3769              allowContentOverflow = this.get("allowContentOverflow"),
3770              diff,
3771              rightAxesXCoords,
3772              leftAxesXCoords,
3773              topAxesYCoords,
3774              bottomAxesYCoords,
3775              graphRect = {};
3776          if(leftAxesCollection)
3777          {
3778              leftAxesXCoords = [];
3779              l = leftAxesCollection.length;
3780              for(i = l - 1; i > -1; --i)
3781              {
3782                  leftAxesXCoords.unshift(leftPaneWidth);
3783                  leftPaneWidth += leftAxesCollection[i].get("width");
3784              }
3785          }
3786          if(rightAxesCollection)
3787          {
3788              rightAxesXCoords = [];
3789              l = rightAxesCollection.length;
3790              i = 0;
3791              for(i = l - 1; i > -1; --i)
3792              {
3793                  rightPaneWidth += rightAxesCollection[i].get("width");
3794                  rightAxesXCoords.unshift(w - rightPaneWidth);
3795              }
3796          }
3797          if(topAxesCollection)
3798          {
3799              topAxesYCoords = [];
3800              l = topAxesCollection.length;
3801              for(i = l - 1; i > -1; --i)
3802              {
3803                  topAxesYCoords.unshift(topPaneHeight);
3804                  topPaneHeight += topAxesCollection[i].get("height");
3805              }
3806          }
3807          if(bottomAxesCollection)
3808          {
3809              bottomAxesYCoords = [];
3810              l = bottomAxesCollection.length;
3811              for(i = l - 1; i > -1; --i)
3812              {
3813                  bottomPaneHeight += bottomAxesCollection[i].get("height");
3814                  bottomAxesYCoords.unshift(h - bottomPaneHeight);
3815              }
3816          }
3817  
3818          graphWidth = w - (leftPaneWidth + rightPaneWidth);
3819          graphHeight = h - (bottomPaneHeight + topPaneHeight);
3820          graphRect.left = leftPaneWidth;
3821          graphRect.top = topPaneHeight;
3822          graphRect.bottom = h - bottomPaneHeight;
3823          graphRect.right = w - rightPaneWidth;
3824          if(!allowContentOverflow)
3825          {
3826              topOverflow = this._getTopOverflow(leftAxesCollection, rightAxesCollection);
3827              bottomOverflow = this._getBottomOverflow(leftAxesCollection, rightAxesCollection);
3828              leftOverflow = this._getLeftOverflow(bottomAxesCollection, topAxesCollection);
3829              rightOverflow = this._getRightOverflow(bottomAxesCollection, topAxesCollection);
3830  
3831              diff = topOverflow - topPaneHeight;
3832              if(diff > 0)
3833              {
3834                  graphRect.top = topOverflow;
3835                  if(topAxesYCoords)
3836                  {
3837                      i = 0;
3838                      l = topAxesYCoords.length;
3839                      for(; i < l; ++i)
3840                      {
3841                          topAxesYCoords[i] += diff;
3842                      }
3843                  }
3844              }
3845  
3846              diff = bottomOverflow - bottomPaneHeight;
3847              if(diff > 0)
3848              {
3849                  graphRect.bottom = h - bottomOverflow;
3850                  if(bottomAxesYCoords)
3851                  {
3852                      i = 0;
3853                      l = bottomAxesYCoords.length;
3854                      for(; i < l; ++i)
3855                      {
3856                          bottomAxesYCoords[i] -= diff;
3857                      }
3858                  }
3859              }
3860  
3861              diff = leftOverflow - leftPaneWidth;
3862              if(diff > 0)
3863              {
3864                  graphRect.left = leftOverflow;
3865                  if(leftAxesXCoords)
3866                  {
3867                      i = 0;
3868                      l = leftAxesXCoords.length;
3869                      for(; i < l; ++i)
3870                      {
3871                          leftAxesXCoords[i] += diff;
3872                      }
3873                  }
3874              }
3875  
3876              diff = rightOverflow - rightPaneWidth;
3877              if(diff > 0)
3878              {
3879                  graphRect.right = w - rightOverflow;
3880                  if(rightAxesXCoords)
3881                  {
3882                      i = 0;
3883                      l = rightAxesXCoords.length;
3884                      for(; i < l; ++i)
3885                      {
3886                          rightAxesXCoords[i] -= diff;
3887                      }
3888                  }
3889              }
3890          }
3891          graphWidth = graphRect.right - graphRect.left;
3892          graphHeight = graphRect.bottom - graphRect.top;
3893          graphX = graphRect.left;
3894          graphY = graphRect.top;
3895          if(topAxesCollection)
3896          {
3897              l = topAxesCollection.length;
3898              i = 0;
3899              for(; i < l; i++)
3900              {
3901                  axis = topAxesCollection[i];
3902                  if(axis.get("width") !== graphWidth)
3903                  {
3904                      axis.set("width", graphWidth);
3905                  }
3906                  axis.get("boundingBox").setStyle("left", graphX + "px");
3907                  axis.get("boundingBox").setStyle("top", topAxesYCoords[i] + "px");
3908              }
3909              if(axis._hasDataOverflow())
3910              {
3911                  graphOverflow = "hidden";
3912              }
3913          }
3914          if(bottomAxesCollection)
3915          {
3916              l = bottomAxesCollection.length;
3917              i = 0;
3918              for(; i < l; i++)
3919              {
3920                  axis = bottomAxesCollection[i];
3921                  if(axis.get("width") !== graphWidth)
3922                  {
3923                      axis.set("width", graphWidth);
3924                  }
3925                  axis.get("boundingBox").setStyle("left", graphX + "px");
3926                  axis.get("boundingBox").setStyle("top", bottomAxesYCoords[i] + "px");
3927              }
3928              if(axis._hasDataOverflow())
3929              {
3930                  graphOverflow = "hidden";
3931              }
3932          }
3933          if(leftAxesCollection)
3934          {
3935              l = leftAxesCollection.length;
3936              i = 0;
3937              for(; i < l; ++i)
3938              {
3939                  axis = leftAxesCollection[i];
3940                  axis.get("boundingBox").setStyle("top", graphY + "px");
3941                  axis.get("boundingBox").setStyle("left", leftAxesXCoords[i] + "px");
3942                  if(axis.get("height") !== graphHeight)
3943                  {
3944                      axis.set("height", graphHeight);
3945                  }
3946              }
3947              if(axis._hasDataOverflow())
3948              {
3949                  graphOverflow = "hidden";
3950              }
3951          }
3952          if(rightAxesCollection)
3953          {
3954              l = rightAxesCollection.length;
3955              i = 0;
3956              for(; i < l; ++i)
3957              {
3958                  axis = rightAxesCollection[i];
3959                  axis.get("boundingBox").setStyle("top", graphY + "px");
3960                  axis.get("boundingBox").setStyle("left", rightAxesXCoords[i] + "px");
3961                  if(axis.get("height") !== graphHeight)
3962                  {
3963                      axis.set("height", graphHeight);
3964                  }
3965              }
3966              if(axis._hasDataOverflow())
3967              {
3968                  graphOverflow = "hidden";
3969              }
3970          }
3971          this._drawing = false;
3972          if(this._callLater)
3973          {
3974              this._redraw();
3975              return;
3976          }
3977          if(graph)
3978          {
3979              graph.get("boundingBox").setStyle("left", graphX + "px");
3980              graph.get("boundingBox").setStyle("top", graphY + "px");
3981              graph.set("width", graphWidth);
3982              graph.set("height", graphHeight);
3983              graph.get("boundingBox").setStyle("overflow", graphOverflow);
3984          }
3985  
3986          if(this._overlay)
3987          {
3988              this._overlay.setStyle("left", graphX + "px");
3989              this._overlay.setStyle("top", graphY + "px");
3990              this._overlay.setStyle("width", graphWidth + "px");
3991              this._overlay.setStyle("height", graphHeight + "px");
3992          }
3993      },
3994  
3995      /**
3996       * Destructor implementation for the CartesianChart class. Calls destroy on all axes, series and the Graph instance.
3997       * Removes the tooltip and overlay HTML elements.
3998       *
3999       * @method destructor
4000       * @protected
4001       */
4002      destructor: function()
4003      {
4004          var graph = this.get("graph"),
4005              i = 0,
4006              len,
4007              seriesCollection = this.get("seriesCollection"),
4008              axesCollection = this._axesCollection,
4009              tooltip = this.get("tooltip").node;
4010          if(this._description)
4011          {
4012              this._description.empty();
4013              this._description.remove(true);
4014          }
4015          if(this._liveRegion)
4016          {
4017              this._liveRegion.empty();
4018              this._liveRegion.remove(true);
4019          }
4020          len = seriesCollection ? seriesCollection.length : 0;
4021          for(; i < len; ++i)
4022          {
4023              if(seriesCollection[i] instanceof Y.CartesianSeries)
4024              {
4025                  seriesCollection[i].destroy(true);
4026              }
4027          }
4028          len = axesCollection ? axesCollection.length : 0;
4029          for(i = 0; i < len; ++i)
4030          {
4031              if(axesCollection[i] instanceof Y.Axis)
4032              {
4033                  axesCollection[i].destroy(true);
4034              }
4035          }
4036          if(graph)
4037          {
4038              graph.destroy(true);
4039          }
4040          if(tooltip)
4041          {
4042              tooltip.empty();
4043              tooltip.remove(true);
4044          }
4045          if(this._overlay)
4046          {
4047              this._overlay.empty();
4048              this._overlay.remove(true);
4049          }
4050      },
4051  
4052      /**
4053       * Returns the appropriate message based on the key press.
4054       *
4055       * @method _getAriaMessage
4056       * @param {Number} key The keycode that was pressed.
4057       * @return String
4058       */
4059      _getAriaMessage: function(key)
4060      {
4061          var msg = "",
4062              series,
4063              items,
4064              categoryItem,
4065              valueItem,
4066              seriesIndex = this._seriesIndex,
4067              itemIndex = this._itemIndex,
4068              seriesCollection = this.get("seriesCollection"),
4069              len = seriesCollection.length,
4070              dataLength;
4071          if(key % 2 === 0)
4072          {
4073              if(len > 1)
4074              {
4075                  if(key === 38)
4076                  {
4077                      seriesIndex = seriesIndex < 1 ? len - 1 : seriesIndex - 1;
4078                  }
4079                  else if(key === 40)
4080                  {
4081                      seriesIndex = seriesIndex >= len - 1 ? 0 : seriesIndex + 1;
4082                  }
4083                  this._itemIndex = -1;
4084              }
4085              else
4086              {
4087                  seriesIndex = 0;
4088              }
4089              this._seriesIndex = seriesIndex;
4090              series = this.getSeries(parseInt(seriesIndex, 10));
4091              msg = series.get("valueDisplayName") + " series.";
4092          }
4093          else
4094          {
4095              if(seriesIndex > -1)
4096              {
4097                  msg = "";
4098                  series = this.getSeries(parseInt(seriesIndex, 10));
4099              }
4100              else
4101              {
4102                  seriesIndex = 0;
4103                  this._seriesIndex = seriesIndex;
4104                  series = this.getSeries(parseInt(seriesIndex, 10));
4105                  msg = series.get("valueDisplayName") + " series.";
4106              }
4107              dataLength = series._dataLength ? series._dataLength : 0;
4108              if(key === 37)
4109              {
4110                  itemIndex = itemIndex > 0 ? itemIndex - 1 : dataLength - 1;
4111              }
4112              else if(key === 39)
4113              {
4114                  itemIndex = itemIndex >= dataLength - 1 ? 0 : itemIndex + 1;
4115              }
4116              this._itemIndex = itemIndex;
4117              items = this.getSeriesItems(series, itemIndex);
4118              categoryItem = items.category;
4119              valueItem = items.value;
4120              if(categoryItem && valueItem && categoryItem.value && valueItem.value)
4121              {
4122                  msg += categoryItem.displayName +
4123                      ": " +
4124                      categoryItem.axis.formatLabel.apply(this, [categoryItem.value, categoryItem.axis.get("labelFormat")]) +
4125                      ", ";
4126                  msg += valueItem.displayName +
4127                      ": " +
4128                      valueItem.axis.formatLabel.apply(this, [valueItem.value, valueItem.axis.get("labelFormat")]) +
4129                      ", ";
4130              }
4131             else
4132              {
4133                  msg += "No data available.";
4134              }
4135              msg += (itemIndex + 1) + " of " + dataLength + ". ";
4136          }
4137          return msg;
4138      }
4139  }, {
4140      ATTRS: {
4141          /**
4142           * Indicates whether axis labels are allowed to overflow beyond the bounds of the chart's content box.
4143           *
4144           * @attribute allowContentOverflow
4145           * @type Boolean
4146           */
4147          allowContentOverflow: {
4148              value: false
4149          },
4150  
4151          /**
4152           * Style object for the axes.
4153           *
4154           * @attribute axesStyles
4155           * @type Object
4156           * @private
4157           */
4158          axesStyles: {
4159              lazyAdd: false,
4160  
4161              getter: function()
4162              {
4163                  var axes = this.get("axes"),
4164                      i,
4165                      styles = this._axesStyles;
4166                  if(axes)
4167                  {
4168                      for(i in axes)
4169                      {
4170                          if(axes.hasOwnProperty(i) && axes[i] instanceof Y.Axis)
4171                          {
4172                              if(!styles)
4173                              {
4174                                  styles = {};
4175                              }
4176                              styles[i] = axes[i].get("styles");
4177                          }
4178                      }
4179                  }
4180                  return styles;
4181              },
4182  
4183              setter: function(val)
4184              {
4185                  var axes = this.get("axes"),
4186                      i;
4187                  for(i in val)
4188                  {
4189                      if(val.hasOwnProperty(i) && axes.hasOwnProperty(i))
4190                      {
4191                          this._setBaseAttribute(axes[i], "styles", val[i]);
4192                      }
4193                  }
4194                  return val;
4195              }
4196          },
4197  
4198          /**
4199           * Style object for the series
4200           *
4201           * @attribute seriesStyles
4202           * @type Object
4203           * @private
4204           */
4205          seriesStyles: {
4206              lazyAdd: false,
4207  
4208              getter: function()
4209              {
4210                  var styles = this._seriesStyles,
4211                      graph = this.get("graph"),
4212                      dict,
4213                      i;
4214                  if(graph)
4215                  {
4216                      dict = graph.get("seriesDictionary");
4217                      if(dict)
4218                      {
4219                          styles = {};
4220                          for(i in dict)
4221                          {
4222                              if(dict.hasOwnProperty(i))
4223                              {
4224                                  styles[i] = dict[i].get("styles");
4225                              }
4226                          }
4227                      }
4228                  }
4229                  return styles;
4230              },
4231  
4232              setter: function(val)
4233              {
4234                  var i,
4235                      l,
4236                      s;
4237  
4238                  if(Y_Lang.isArray(val))
4239                  {
4240                      s = this.get("seriesCollection");
4241                      i = 0;
4242                      l = val.length;
4243  
4244                      for(; i < l; ++i)
4245                      {
4246                          this._setBaseAttribute(s[i], "styles", val[i]);
4247                      }
4248                  }
4249                  else
4250                  {
4251                      for(i in val)
4252                      {
4253                          if(val.hasOwnProperty(i))
4254                          {
4255                              s = this.getSeries(i);
4256                              this._setBaseAttribute(s, "styles", val[i]);
4257                          }
4258                      }
4259                  }
4260                  return val;
4261              }
4262          },
4263  
4264          /**
4265           * Styles for the graph.
4266           *
4267           * @attribute graphStyles
4268           * @type Object
4269           * @private
4270           */
4271          graphStyles: {
4272              lazyAdd: false,
4273  
4274              getter: function()
4275              {
4276                  var graph = this.get("graph");
4277                  if(graph)
4278                  {
4279                      return(graph.get("styles"));
4280                  }
4281                  return this._graphStyles;
4282              },
4283  
4284              setter: function(val)
4285              {
4286                  var graph = this.get("graph");
4287                  this._setBaseAttribute(graph, "styles", val);
4288                  return val;
4289              }
4290  
4291          },
4292  
4293          /**
4294           * Style properties for the chart. Contains a key indexed hash of the following:
4295           *  <dl>
4296           *      <dt>series</dt><dd>A key indexed hash containing references to the `styles` attribute for each series in the chart.
4297           *      Specific style attributes vary depending on the series:
4298           *      <ul>
4299           *          <li><a href="AreaSeries.html#attr_styles">AreaSeries</a></li>
4300           *          <li><a href="BarSeries.html#attr_styles">BarSeries</a></li>
4301           *          <li><a href="ColumnSeries.html#attr_styles">ColumnSeries</a></li>
4302           *          <li><a href="ComboSeries.html#attr_styles">ComboSeries</a></li>
4303           *          <li><a href="LineSeries.html#attr_styles">LineSeries</a></li>
4304           *          <li><a href="MarkerSeries.html#attr_styles">MarkerSeries</a></li>
4305           *          <li><a href="SplineSeries.html#attr_styles">SplineSeries</a></li>
4306           *      </ul>
4307           *      </dd>
4308           *      <dt>axes</dt><dd>A key indexed hash containing references to the `styles` attribute for each axes in the chart. Specific
4309           *      style attributes can be found in the <a href="Axis.html#attr_styles">Axis</a> class.</dd>
4310           *      <dt>graph</dt><dd>A reference to the `styles` attribute in the chart. Specific style attributes can be found in the
4311           *      <a href="Graph.html#attr_styles">Graph</a> class.</dd>
4312           *  </dl>
4313           *
4314           * @attribute styles
4315           * @type Object
4316           */
4317          styles: {
4318              lazyAdd: false,
4319  
4320              getter: function()
4321              {
4322                  var styles = {
4323                      axes: this.get("axesStyles"),
4324                      series: this.get("seriesStyles"),
4325                      graph: this.get("graphStyles")
4326                  };
4327                  return styles;
4328              },
4329              setter: function(val)
4330              {
4331                  if(val.hasOwnProperty("axes"))
4332                  {
4333                      if(this.get("axesStyles"))
4334                      {
4335                          this.set("axesStyles", val.axes);
4336                      }
4337                      else
4338                      {
4339                          this._axesStyles = val.axes;
4340                      }
4341                  }
4342                  if(val.hasOwnProperty("series"))
4343                  {
4344                      if(this.get("seriesStyles"))
4345                      {
4346                          this.set("seriesStyles", val.series);
4347                      }
4348                      else
4349                      {
4350                          this._seriesStyles = val.series;
4351                      }
4352                  }
4353                  if(val.hasOwnProperty("graph"))
4354                  {
4355                      this.set("graphStyles", val.graph);
4356                  }
4357              }
4358          },
4359  
4360          /**
4361           * Axes to appear in the chart. This can be a key indexed hash of axis instances or object literals
4362           * used to construct the appropriate axes.
4363           *
4364           * @attribute axes
4365           * @type Object
4366           */
4367          axes: {
4368              lazyAdd: false,
4369  
4370              valueFn: "_getDefaultAxes",
4371  
4372              setter: function(val)
4373              {
4374                  if(this.get("dataProvider"))
4375                  {
4376                      val = this._setAxes(val);
4377                  }
4378                  return val;
4379              }
4380          },
4381  
4382          /**
4383           * Collection of series to appear on the chart. This can be an array of Series instances or object literals
4384           * used to construct the appropriate series.
4385           *
4386           * @attribute seriesCollection
4387           * @type Array
4388           */
4389          seriesCollection: {
4390              lazyAdd: false,
4391  
4392              valueFn: "_getDefaultSeriesCollection",
4393  
4394              setter: function(val)
4395              {
4396                  if(this.get("dataProvider"))
4397                  {
4398                      return this._parseSeriesCollection(val);
4399                  }
4400                  return val;
4401              }
4402          },
4403  
4404          /**
4405           * Reference to the left-aligned axes for the chart.
4406           *
4407           * @attribute leftAxesCollection
4408           * @type Array
4409           * @private
4410           */
4411          leftAxesCollection: {},
4412  
4413          /**
4414           * Reference to the bottom-aligned axes for the chart.
4415           *
4416           * @attribute bottomAxesCollection
4417           * @type Array
4418           * @private
4419           */
4420          bottomAxesCollection: {},
4421  
4422          /**
4423           * Reference to the right-aligned axes for the chart.
4424           *
4425           * @attribute rightAxesCollection
4426           * @type Array
4427           * @private
4428           */
4429          rightAxesCollection: {},
4430  
4431          /**
4432           * Reference to the top-aligned axes for the chart.
4433           *
4434           * @attribute topAxesCollection
4435           * @type Array
4436           * @private
4437           */
4438          topAxesCollection: {},
4439  
4440          /**
4441           * Indicates whether or not the chart is stacked.
4442           *
4443           * @attribute stacked
4444           * @type Boolean
4445           */
4446          stacked: {
4447              value: false
4448          },
4449  
4450          /**
4451           * Direction of chart's category axis when there is no series collection specified. Charts can
4452           * be horizontal or vertical. When the chart type is column, the chart is horizontal.
4453           * When the chart type is bar, the chart is vertical.
4454           *
4455           * @attribute direction
4456           * @type String
4457           */
4458          direction: {
4459              getter: function()
4460              {
4461                  var type = this.get("type");
4462                  if(type === "bar")
4463                  {
4464                      return "vertical";
4465                  }
4466                  else if(type === "column")
4467                  {
4468                      return "horizontal";
4469                  }
4470                  return this._direction;
4471              },
4472  
4473              setter: function(val)
4474              {
4475                  this._direction = val;
4476                  return this._direction;
4477              }
4478          },
4479  
4480          /**
4481           * Indicates whether or not an area is filled in a combo chart.
4482           *
4483           * @attribute showAreaFill
4484           * @type Boolean
4485           */
4486          showAreaFill: {},
4487  
4488          /**
4489           * Indicates whether to display markers in a combo chart.
4490           *
4491           * @attribute showMarkers
4492           * @type Boolean
4493           */
4494          showMarkers:{},
4495  
4496          /**
4497           * Indicates whether to display lines in a combo chart.
4498           *
4499           * @attribute showLines
4500           * @type Boolean
4501           */
4502          showLines:{},
4503  
4504          /**
4505           * Indicates the key value used to identify a category axis in the `axes` hash. If
4506           * not specified, the categoryKey attribute value will be used.
4507           *
4508           * @attribute categoryAxisName
4509           * @type String
4510           */
4511          categoryAxisName: {
4512          },
4513  
4514          /**
4515           * Indicates the key value used to identify a the series axis when an axis not generated.
4516           *
4517           * @attribute valueAxisName
4518           * @type String
4519           */
4520          valueAxisName: {
4521              value: "values"
4522          },
4523  
4524          /**
4525           * Reference to the horizontalGridlines for the chart.
4526           *
4527           * @attribute horizontalGridlines
4528           * @type Gridlines
4529           */
4530          horizontalGridlines: {
4531              getter: function()
4532              {
4533                  var graph = this.get("graph");
4534                  if(graph)
4535                  {
4536                      return graph.get("horizontalGridlines");
4537                  }
4538                  return this._horizontalGridlines;
4539              },
4540              setter: function(val)
4541              {
4542                  var graph = this.get("graph");
4543                  if(val && !Y_Lang.isObject(val))
4544                  {
4545                      val = {};
4546                  }
4547                  if(graph)
4548                  {
4549                      graph.set("horizontalGridlines", val);
4550                  }
4551                  else
4552                  {
4553                      this._horizontalGridlines = val;
4554                  }
4555              }
4556          },
4557  
4558          /**
4559           * Reference to the verticalGridlines for the chart.
4560           *
4561           * @attribute verticalGridlines
4562           * @type Gridlines
4563           */
4564          verticalGridlines: {
4565              getter: function()
4566              {
4567                  var graph = this.get("graph");
4568                  if(graph)
4569                  {
4570                      return graph.get("verticalGridlines");
4571                  }
4572                  return this._verticalGridlines;
4573              },
4574              setter: function(val)
4575              {
4576                  var graph = this.get("graph");
4577                  if(val && !Y_Lang.isObject(val))
4578                  {
4579                      val = {};
4580                  }
4581                  if(graph)
4582                  {
4583                      graph.set("verticalGridlines", val);
4584                  }
4585                  else
4586                  {
4587                      this._verticalGridlines = val;
4588                  }
4589              }
4590          },
4591  
4592          /**
4593           * Type of chart when there is no series collection specified.
4594           *
4595           * @attribute type
4596           * @type String
4597           */
4598          type: {
4599              getter: function()
4600              {
4601                  if(this.get("stacked"))
4602                  {
4603                      return "stacked" + this._type;
4604                  }
4605                  return this._type;
4606              },
4607  
4608              setter: function(val)
4609              {
4610                  if(this._type === "bar")
4611                  {
4612                      if(val !== "bar")
4613                      {
4614                          this.set("direction", "horizontal");
4615                      }
4616                  }
4617                  else
4618                  {
4619                      if(val === "bar")
4620                      {
4621                          this.set("direction", "vertical");
4622                      }
4623                  }
4624                  this._type = val;
4625                  return this._type;
4626              }
4627          },
4628  
4629          /**
4630           * Reference to the category axis used by the chart.
4631           *
4632           * @attribute categoryAxis
4633           * @type Axis
4634           */
4635          categoryAxis:{}
4636      }
4637  });
4638  /**
4639   * The PieChart class creates a pie chart
4640   *
4641   * @class PieChart
4642   * @extends ChartBase
4643   * @constructor
4644   * @submodule charts-base
4645   */
4646  Y.PieChart = Y.Base.create("pieChart", Y.Widget, [Y.ChartBase], {
4647      /**
4648       * Calculates and returns a `seriesCollection`.
4649       *
4650       * @method _getSeriesCollection
4651       * @return Array
4652       * @private
4653       */
4654      _getSeriesCollection: function()
4655      {
4656          if(this._seriesCollection)
4657          {
4658              return this._seriesCollection;
4659          }
4660          var axes = this.get("axes"),
4661              sc = [],
4662              seriesKeys,
4663              i = 0,
4664              l,
4665              type = this.get("type"),
4666              key,
4667              catAxis = "categoryAxis",
4668              catKey = "categoryKey",
4669              valAxis = "valueAxis",
4670              seriesKey = "valueKey";
4671          if(axes)
4672          {
4673              seriesKeys = axes.values.get("keyCollection");
4674              key = axes.category.get("keyCollection")[0];
4675              l = seriesKeys.length;
4676              for(; i < l; ++i)
4677              {
4678                  sc[i] = {type:type};
4679                  sc[i][catAxis] = "category";
4680                  sc[i][valAxis] = "values";
4681                  sc[i][catKey] = key;
4682                  sc[i][seriesKey] = seriesKeys[i];
4683              }
4684          }
4685          this._seriesCollection = sc;
4686          return sc;
4687      },
4688  
4689      /**
4690       * Creates `Axis` instances.
4691       *
4692       * @method _parseAxes
4693       * @param {Object} val Object containing `Axis` instances or objects in which to construct `Axis` instances.
4694       * @return Object
4695       * @private
4696       */
4697      _parseAxes: function(hash)
4698      {
4699          if(!this._axes)
4700          {
4701              this._axes = {};
4702          }
4703          var i, pos, axis, dh, config, AxisClass,
4704              type = this.get("type"),
4705              w = this.get("width"),
4706              h = this.get("height"),
4707              node = Y.Node.one(this._parentNode);
4708          if(!w)
4709          {
4710              this.set("width", node.get("offsetWidth"));
4711              w = this.get("width");
4712          }
4713          if(!h)
4714          {
4715              this.set("height", node.get("offsetHeight"));
4716              h = this.get("height");
4717          }
4718          for(i in hash)
4719          {
4720              if(hash.hasOwnProperty(i))
4721              {
4722                  dh = hash[i];
4723                  pos = type === "pie" ? "none" : dh.position;
4724                  AxisClass = this._getAxisClass(dh.type);
4725                  config = {dataProvider:this.get("dataProvider")};
4726                  if(dh.hasOwnProperty("roundingUnit"))
4727                  {
4728                      config.roundingUnit = dh.roundingUnit;
4729                  }
4730                  config.keys = dh.keys;
4731                  config.width = w;
4732                  config.height = h;
4733                  config.position = pos;
4734                  config.styles = dh.styles;
4735                  axis = new AxisClass(config);
4736                  axis.on("axisRendered", Y.bind(this._itemRendered, this));
4737                  this._axes[i] = axis;
4738              }
4739          }
4740      },
4741  
4742      /**
4743       * Adds axes to the chart.
4744       *
4745       * @method _addAxes
4746       * @private
4747       */
4748      _addAxes: function()
4749      {
4750          var axes = this.get("axes"),
4751              i,
4752              axis,
4753              p;
4754          if(!axes)
4755          {
4756              this.set("axes", this._getDefaultAxes());
4757              axes = this.get("axes");
4758          }
4759          if(!this._axesCollection)
4760          {
4761              this._axesCollection = [];
4762          }
4763          for(i in axes)
4764          {
4765              if(axes.hasOwnProperty(i))
4766              {
4767                  axis = axes[i];
4768                  p = axis.get("position");
4769                  if(!this.get(p + "AxesCollection"))
4770                  {
4771                      this.set(p + "AxesCollection", [axis]);
4772                  }
4773                  else
4774                  {
4775                      this.get(p + "AxesCollection").push(axis);
4776                  }
4777                  this._axesCollection.push(axis);
4778              }
4779          }
4780      },
4781  
4782      /**
4783       * Renders the Graph.
4784       *
4785       * @method _addSeries
4786       * @private
4787       */
4788      _addSeries: function()
4789      {
4790          var graph = this.get("graph"),
4791              seriesCollection = this.get("seriesCollection");
4792          this._parseSeriesAxes(seriesCollection);
4793          graph.set("showBackground", false);
4794          graph.set("width", this.get("width"));
4795          graph.set("height", this.get("height"));
4796          graph.set("seriesCollection", seriesCollection);
4797          this._seriesCollection = graph.get("seriesCollection");
4798          graph.render(this.get("contentBox"));
4799      },
4800  
4801      /**
4802       * Parse and sets the axes for the chart.
4803       *
4804       * @method _parseSeriesAxes
4805       * @param {Array} c A collection `PieSeries` instance.
4806       * @private
4807       */
4808      _parseSeriesAxes: function(c)
4809      {
4810          var i = 0,
4811              len = c.length,
4812              s,
4813              axes = this.get("axes"),
4814              axis;
4815          for(; i < len; ++i)
4816          {
4817              s = c[i];
4818              if(s)
4819              {
4820                  //If series is an actual series instance,
4821                  //replace axes attribute string ids with axes
4822                  if(s instanceof Y.PieSeries)
4823                  {
4824                      axis = s.get("categoryAxis");
4825                      if(axis && !(axis instanceof Y.Axis))
4826                      {
4827                          s.set("categoryAxis", axes[axis]);
4828                      }
4829                      axis = s.get("valueAxis");
4830                      if(axis && !(axis instanceof Y.Axis))
4831                      {
4832                          s.set("valueAxis", axes[axis]);
4833                      }
4834                      continue;
4835                  }
4836                  s.categoryAxis = axes.category;
4837                  s.valueAxis = axes.values;
4838                  if(!s.type)
4839                  {
4840                      s.type = this.get("type");
4841                  }
4842              }
4843          }
4844      },
4845  
4846      /**
4847       * Generates and returns a key-indexed object containing `Axis` instances or objects used to create `Axis` instances.
4848       *
4849       * @method _getDefaultAxes
4850       * @return Object
4851       * @private
4852       */
4853      _getDefaultAxes: function()
4854      {
4855          var catKey = this.get("categoryKey"),
4856              seriesKeys = this.get("seriesKeys").concat(),
4857              seriesAxis = "numeric";
4858          return {
4859              values:{
4860                  keys:seriesKeys,
4861                  type:seriesAxis
4862              },
4863              category:{
4864                  keys:[catKey],
4865                  type:this.get("categoryType")
4866              }
4867          };
4868      },
4869  
4870      /**
4871       * Returns an object literal containing a categoryItem and a valueItem for a given series index.
4872       *
4873       * @method getSeriesItem
4874       * @param series Reference to a series.
4875       * @param index Index of the specified item within a series.
4876       * @return Object
4877       */
4878      getSeriesItems: function(series, index)
4879      {
4880          var categoryItem = {
4881                  axis: series.get("categoryAxis"),
4882                  key: series.get("categoryKey"),
4883                  displayName: series.get("categoryDisplayName")
4884              },
4885              valueItem = {
4886                  axis: series.get("valueAxis"),
4887                  key: series.get("valueKey"),
4888                  displayName: series.get("valueDisplayName")
4889              };
4890          categoryItem.value = categoryItem.axis.getKeyValueAt(categoryItem.key, index);
4891          valueItem.value = valueItem.axis.getKeyValueAt(valueItem.key, index);
4892          return {category:categoryItem, value:valueItem};
4893      },
4894  
4895      /**
4896       * Handler for sizeChanged event.
4897       *
4898       * @method _sizeChanged
4899       * @param {Object} e Event object.
4900       * @private
4901       */
4902      _sizeChanged: function()
4903      {
4904          this._redraw();
4905      },
4906  
4907      /**
4908       * Redraws the chart instance.
4909       *
4910       * @method _redraw
4911       * @private
4912       */
4913      _redraw: function()
4914      {
4915          var graph = this.get("graph"),
4916              w = this.get("width"),
4917              h = this.get("height"),
4918              dimension;
4919          if(graph)
4920          {
4921              dimension = Math.min(w, h);
4922              graph.set("width", dimension);
4923              graph.set("height", dimension);
4924          }
4925      },
4926  
4927      /**
4928       * Formats tooltip text for a pie chart.
4929       *
4930       * @method _tooltipLabelFunction
4931       * @param {Object} categoryItem An object containing the following:
4932       *  <dl>
4933       *      <dt>axis</dt><dd>The axis to which the category is bound.</dd>
4934       *      <dt>displayName</dt><dd>The display name set to the category (defaults to key if not provided)</dd>
4935       *      <dt>key</dt><dd>The key of the category.</dd>
4936       *      <dt>value</dt><dd>The value of the category</dd>
4937       *  </dl>
4938       * @param {Object} valueItem An object containing the following:
4939       *  <dl>
4940       *      <dt>axis</dt><dd>The axis to which the item's series is bound.</dd>
4941       *      <dt>displayName</dt><dd>The display name of the series. (defaults to key if not provided)</dd>
4942       *      <dt>key</dt><dd>The key for the series.</dd>
4943       *      <dt>value</dt><dd>The value for the series item.</dd>
4944       *  </dl>
4945       * @param {Number} itemIndex The index of the item within the series.
4946       * @param {CartesianSeries} series The `PieSeries` instance of the item.
4947       * @return {HTMLElement}
4948       * @private
4949       */
4950      _tooltipLabelFunction: function(categoryItem, valueItem, itemIndex, series)
4951      {
4952          var msg = DOCUMENT.createElement("div"),
4953              total = series.getTotalValues(),
4954              pct = Math.round((valueItem.value / total) * 10000)/100;
4955          msg.appendChild(DOCUMENT.createTextNode(categoryItem.displayName +
4956          ": " + categoryItem.axis.get("labelFunction").apply(this, [categoryItem.value, categoryItem.axis.get("labelFormat")])));
4957          msg.appendChild(DOCUMENT.createElement("br"));
4958          msg.appendChild(DOCUMENT.createTextNode(valueItem.displayName +
4959          ": " + valueItem.axis.get("labelFunction").apply(this, [valueItem.value, valueItem.axis.get("labelFormat")])));
4960          msg.appendChild(DOCUMENT.createElement("br"));
4961          msg.appendChild(DOCUMENT.createTextNode(pct + "%"));
4962          return msg;
4963      },
4964  
4965      /**
4966       * Returns the appropriate message based on the key press.
4967       *
4968       * @method _getAriaMessage
4969       * @param {Number} key The keycode that was pressed.
4970       * @return String
4971       */
4972      _getAriaMessage: function(key)
4973      {
4974          var msg = "",
4975              categoryItem,
4976              items,
4977              series,
4978              valueItem,
4979              seriesIndex = 0,
4980              itemIndex = this._itemIndex,
4981              len,
4982              total,
4983              pct,
4984              markers;
4985          series = this.getSeries(parseInt(seriesIndex, 10));
4986          markers = series.get("markers");
4987          len = markers && markers.length ? markers.length : 0;
4988          if(key === 37)
4989          {
4990              itemIndex = itemIndex > 0 ? itemIndex - 1 : len - 1;
4991          }
4992          else if(key === 39)
4993          {
4994              itemIndex = itemIndex >= len - 1 ? 0 : itemIndex + 1;
4995          }
4996          this._itemIndex = itemIndex;
4997          items = this.getSeriesItems(series, itemIndex);
4998          categoryItem = items.category;
4999          valueItem = items.value;
5000          total = series.getTotalValues();
5001          pct = Math.round((valueItem.value / total) * 10000)/100;
5002          if(categoryItem && valueItem)
5003          {
5004              msg += categoryItem.displayName +
5005                  ": " +
5006                  categoryItem.axis.formatLabel.apply(this, [categoryItem.value, categoryItem.axis.get("labelFormat")]) +
5007                  ", ";
5008              msg += valueItem.displayName +
5009                  ": " + valueItem.axis.formatLabel.apply(this, [valueItem.value, valueItem.axis.get("labelFormat")]) +
5010                  ", ";
5011              msg += "Percent of total " + valueItem.displayName + ": " + pct + "%,";
5012          }
5013          else
5014          {
5015              msg += "No data available,";
5016          }
5017          msg += (itemIndex + 1) + " of " + len + ". ";
5018          return msg;
5019      },
5020  
5021      /**
5022       * Destructor implementation for the PieChart class.
5023       *
5024       * @method destructor
5025       * @protected
5026       */
5027      destructor: function()
5028      {
5029          var series,
5030              axis,
5031              tooltip = this.get("tooltip"),
5032              tooltipNode = tooltip.node,
5033              graph = this.get("graph"),
5034              axesCollection = this._axesCollection,
5035              seriesCollection = this.get("seriesCollection");
5036          while(seriesCollection.length > 0)
5037          {
5038              series = seriesCollection.shift();
5039              series.destroy(true);
5040          }
5041          while(axesCollection.length > 0)
5042          {
5043              axis = axesCollection.shift();
5044              if(axis instanceof Y.Axis)
5045              {
5046                  axis.destroy(true);
5047              }
5048          }
5049          if(this._description)
5050          {
5051              this._description.empty();
5052              this._description.remove(true);
5053          }
5054          if(this._liveRegion)
5055          {
5056              this._liveRegion.empty();
5057              this._liveRegion.remove(true);
5058          }
5059          if(graph)
5060          {
5061              graph.destroy(true);
5062          }
5063          if(tooltipNode)
5064          {
5065              tooltipNode.empty();
5066              tooltipNode.remove(true);
5067          }
5068      }
5069  }, {
5070      ATTRS: {
5071          /**
5072           * Sets the aria description for the chart.
5073           *
5074           * @attribute ariaDescription
5075           * @type String
5076           */
5077          ariaDescription: {
5078              value: "Use the left and right keys to navigate through items.",
5079  
5080              setter: function(val)
5081              {
5082                  if(this._description)
5083                  {
5084                      this._description.set("text", val);
5085                  }
5086                  return val;
5087              }
5088          },
5089  
5090          /**
5091           * Axes to appear in the chart.
5092           *
5093           * @attribute axes
5094           * @type Object
5095           */
5096          axes: {
5097              getter: function()
5098              {
5099                  return this._axes;
5100              },
5101  
5102              setter: function(val)
5103              {
5104                  this._parseAxes(val);
5105              }
5106          },
5107  
5108          /**
5109           * Collection of series to appear on the chart. This can be an array of Series instances or object literals
5110           * used to describe a Series instance.
5111           *
5112           * @attribute seriesCollection
5113           * @type Array
5114           */
5115          seriesCollection: {
5116              lazyAdd: false,
5117  
5118              getter: function()
5119              {
5120                  return this._getSeriesCollection();
5121              },
5122  
5123              setter: function(val)
5124              {
5125                  return this._setSeriesCollection(val);
5126              }
5127          },
5128  
5129          /**
5130           * Type of chart when there is no series collection specified.
5131           *
5132           * @attribute type
5133           * @type String
5134           */
5135          type: {
5136              value: "pie"
5137          }
5138      }
5139  });
5140  /**
5141   * The Chart class is the basic application used to create a chart.
5142   *
5143   * @class Chart
5144   * @constructor
5145   * @submodule charts-base
5146   */
5147  function Chart(cfg)
5148  {
5149      if(cfg.type !== "pie")
5150      {
5151          return new Y.CartesianChart(cfg);
5152      }
5153      else
5154      {
5155          return new Y.PieChart(cfg);
5156      }
5157  }
5158  Y.Chart = Chart;
5159  
5160  
5161  }, '3.17.2', {
5162      "requires": [
5163          "dom",
5164          "event-mouseenter",
5165          "event-touch",
5166          "graphics-group",
5167          "axes",
5168          "series-pie",
5169          "series-line",
5170          "series-marker",
5171          "series-area",
5172          "series-spline",
5173          "series-column",
5174          "series-bar",
5175          "series-areaspline",
5176          "series-combo",
5177          "series-combospline",
5178          "series-line-stacked",
5179          "series-marker-stacked",
5180          "series-area-stacked",
5181          "series-spline-stacked",
5182          "series-column-stacked",
5183          "series-bar-stacked",
5184          "series-areaspline-stacked",
5185          "series-combo-stacked",
5186          "series-combospline-stacked"
5187      ]
5188  });


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