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