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