#

API Docs for: 3.10.3
Show: Inherited Protected Private Deprecated

# File: charts/js/Graph.js

    /**
     * Graph manages and contains series instances for a `CartesianChart`
     * instance.
     *
     * @class Graph
     * @constructor
     * @extends Widget
     * @uses Renderer
     * @submodule charts-base
     */
    Y.Graph = Y.Base.create("graph", Y.Widget, [Y.Renderer], {
        /**
         * @method bindUI
         * @private
         */
        bindUI: function()
        {
            var bb = this.get("boundingBox");
            bb.setStyle("position", "absolute");
            this.after("widthChange", this._sizeChangeHandler);
            this.after("heightChange", this._sizeChangeHandler);
            this.after("stylesChange", this._updateStyles);
            this.after("groupMarkersChange", this._drawSeries);
        },

        /**
         * @method syncUI
         * @private
         */
        syncUI: function()
        {
            var background,
                cb,
                bg,
                sc = this.get("seriesCollection"),
                series,
                i = 0,
                len = sc ? sc.length : 0,
                hgl = this.get("horizontalGridlines"),
                vgl = this.get("verticalGridlines");
            if(this.get("showBackground"))
            {
                background = this.get("background");
                cb = this.get("contentBox");
                bg = this.get("styles").background;
                bg.stroke = bg.border;
                bg.stroke.opacity = bg.stroke.alpha;
                bg.fill.opacity = bg.fill.alpha;
                bg.width = this.get("width");
                bg.height = this.get("height");
                bg.type = bg.shape;
                background.set(bg);
            }
            for(; i < len; ++i)
            {
                series = sc[i];
                if(series instanceof Y.SeriesBase)
                {
                    series.render();
                }
            }
            if(hgl && hgl instanceof Y.Gridlines)
            {
                hgl.draw();
            }
            if(vgl && vgl instanceof Y.Gridlines)
            {
                vgl.draw();
            }
        },

        /**
         * Object of arrays containing series mapped to a series type.
         *
         * @property seriesTypes
         * @type Object
         * @private
         */
        seriesTypes: null,

        /**
         * Returns a series instance based on an index.
         *
         * @method getSeriesByIndex
         * @param {Number} val index of the series
         * @return CartesianSeries
         */
        getSeriesByIndex: function(val)
        {
            var col = this.get("seriesCollection"),
                series;
            if(col && col.length > val)
            {
                series = col[val];
            }
            return series;
        },

        /**
         * Returns a series instance based on a key value.
         *
         * @method getSeriesByKey
         * @param {String} val key value of the series
         * @return CartesianSeries
         */
        getSeriesByKey: function(val)
        {
            var obj = this._seriesDictionary,
                series;
            if(obj && obj.hasOwnProperty(val))
            {
                series = obj[val];
            }
            return series;
        },

        /**
         * Adds dispatcher to a `_dispatcher` used to
         * to ensure all series have redrawn before for firing event.
         *
         * @method addDispatcher
         * @param {CartesianSeries} val series instance to add
         * @protected
         */
        addDispatcher: function(val)
        {
            if(!this._dispatchers)
            {
                this._dispatchers = [];
            }
            this._dispatchers.push(val);
        },

        /**
         * Collection of series to be displayed in the graph.
         *
         * @property _seriesCollection
         * @type Array
         * @private
         */
        _seriesCollection: null,

        /**
         * Object containing key value pairs of `CartesianSeries` instances.
         *
         * @property _seriesDictionary
         * @type Object
         * @private
         */
        _seriesDictionary: null,

        /**
         * Parses series instances to be displayed in the graph.
         *
         * @method _parseSeriesCollection
         * @param {Array} Collection of `CartesianSeries` instances or objects container `CartesianSeries` attributes values.
         * @private
         */
        _parseSeriesCollection: function(val)
        {
            if(!val)
            {
                return;
            }
            var len = val.length,
                i = 0,
                series,
                seriesKey;
            this._seriesCollection = [];
            this._seriesDictionary = {};
            this.seriesTypes = [];
            for(; i < len; ++i)
            {
                series = val[i];
                if(!(series instanceof Y.CartesianSeries) && !(series instanceof Y.PieSeries))
                {
                    this._createSeries(series);
                    continue;
                }
                this._addSeries(series);
            }
            len = this._seriesCollection.length;
            for(i = 0; i < len; ++i)
            {
                series = this.get("seriesCollection")[i];
                seriesKey = series.get("direction") === "horizontal" ? "yKey" : "xKey";
                this._seriesDictionary[series.get(seriesKey)] = series;
            }
        },

        /**
         * Adds a series to the graph.
         *
         * @method _addSeries
         * @param {CartesianSeries} series Series to add to the graph.
         * @private
         */
        _addSeries: function(series)
        {
            var type = series.get("type"),
                seriesCollection = this.get("seriesCollection"),
                graphSeriesLength = seriesCollection.length,
                seriesTypes = this.seriesTypes,
                typeSeriesCollection;
            if(!series.get("graph"))
            {
                series.set("graph", this);
            }
            seriesCollection.push(series);
            if(!seriesTypes.hasOwnProperty(type))
            {
                this.seriesTypes[type] = [];
            }
            typeSeriesCollection = this.seriesTypes[type];
            series.set("graphOrder", graphSeriesLength);
            series.set("order", typeSeriesCollection.length);
            typeSeriesCollection.push(series);
            series.set("seriesTypeCollection", typeSeriesCollection);
            this.addDispatcher(series);
            series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
            this.fire("seriesAdded", series);
        },

        /**
         * Creates a `CartesianSeries` instance from an object containing attribute key value pairs. The key value pairs include
         * attributes for the specific series and a type value which defines the type of series to be used.
         *
         * @method createSeries
         * @param {Object} seriesData Series attribute key value pairs.
         * @private
         */
        _createSeries: function(seriesData)
        {
            var type = seriesData.type,
                seriesCollection = this.get("seriesCollection"),
                seriesTypes = this.seriesTypes,
                typeSeriesCollection,
                SeriesClass,
                series;
                seriesData.graph = this;
            if(!seriesTypes.hasOwnProperty(type))
            {
                seriesTypes[type] = [];
            }
            typeSeriesCollection = seriesTypes[type];
            seriesData.graph = this;
            seriesData.order = typeSeriesCollection.length;
            seriesData.graphOrder = seriesCollection.length;
            SeriesClass = this._getSeries(seriesData.type);
            series = new SeriesClass(seriesData);
            this.addDispatcher(series);
            series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
            typeSeriesCollection.push(series);
            seriesCollection.push(series);
            series.set("seriesTypeCollection", typeSeriesCollection);
            if(this.get("rendered"))
            {
                series.render();
            }
        },

        /**
         * String reference for pre-defined `Series` classes.
         *
         * @property _seriesMap
         * @type Object
         * @private
         */
        _seriesMap: {
            line : Y.LineSeries,
            column : Y.ColumnSeries,
            bar : Y.BarSeries,
            area :  Y.AreaSeries,
            candlestick : Y.CandlestickSeries,
            ohlc : Y.OHLCSeries,
            stackedarea : Y.StackedAreaSeries,
            stackedline : Y.StackedLineSeries,
            stackedcolumn : Y.StackedColumnSeries,
            stackedbar : Y.StackedBarSeries,
            markerseries : Y.MarkerSeries,
            spline : Y.SplineSeries,
            areaspline : Y.AreaSplineSeries,
            stackedspline : Y.StackedSplineSeries,
            stackedareaspline : Y.StackedAreaSplineSeries,
            stackedmarkerseries : Y.StackedMarkerSeries,
            pie : Y.PieSeries,
            combo : Y.ComboSeries,
            stackedcombo : Y.StackedComboSeries,
            combospline : Y.ComboSplineSeries,
            stackedcombospline : Y.StackedComboSplineSeries
        },

        /**
         * Returns a specific `CartesianSeries` class based on key value from a look up table of a direct reference to a
         * class. When specifying a key value, the following options are available:
         *
         *  <table>
         *      <tr><th>Key Value</th><th>Class</th></tr>
         *      <tr><td>line</td><td>Y.LineSeries</td></tr>
         *      <tr><td>column</td><td>Y.ColumnSeries</td></tr>
         *      <tr><td>bar</td><td>Y.BarSeries</td></tr>
         *      <tr><td>area</td><td>Y.AreaSeries</td></tr>
         *      <tr><td>stackedarea</td><td>Y.StackedAreaSeries</td></tr>
         *      <tr><td>stackedline</td><td>Y.StackedLineSeries</td></tr>
         *      <tr><td>stackedcolumn</td><td>Y.StackedColumnSeries</td></tr>
         *      <tr><td>stackedbar</td><td>Y.StackedBarSeries</td></tr>
         *      <tr><td>markerseries</td><td>Y.MarkerSeries</td></tr>
         *      <tr><td>spline</td><td>Y.SplineSeries</td></tr>
         *      <tr><td>areaspline</td><td>Y.AreaSplineSeries</td></tr>
         *      <tr><td>stackedspline</td><td>Y.StackedSplineSeries</td></tr>
         *      <tr><td>stackedareaspline</td><td>Y.StackedAreaSplineSeries</td></tr>
         *      <tr><td>stackedmarkerseries</td><td>Y.StackedMarkerSeries</td></tr>
         *      <tr><td>pie</td><td>Y.PieSeries</td></tr>
         *      <tr><td>combo</td><td>Y.ComboSeries</td></tr>
         *      <tr><td>stackedcombo</td><td>Y.StackedComboSeries</td></tr>
         *      <tr><td>combospline</td><td>Y.ComboSplineSeries</td></tr>
         *      <tr><td>stackedcombospline</td><td>Y.StackedComboSplineSeries</td></tr>
         *  </table>
         *
         * When referencing a class directly, you can specify any of the above classes or any custom class that extends
         * `CartesianSeries` or `PieSeries`.
         *
         * @method _getSeries
         * @param {String | Object} type Series type.
         * @return CartesianSeries
         * @private
         */
        _getSeries: function(type)
        {
            var seriesClass;
            if(Y_Lang.isString(type))
            {
                seriesClass = this._seriesMap[type];
            }
            else
            {
                seriesClass = type;
            }
            return seriesClass;
        },

        /**
         * Event handler for marker events.
         *
         * @method _markerEventHandler
         * @param {Object} e Event object.
         * @private
         */
        _markerEventHandler: function(e)
        {
            var type = e.type,
                markerNode = e.currentTarget,
                strArr = markerNode.getAttribute("id").split("_"),
                series = this.getSeriesByIndex(strArr[1]),
                index = strArr[2];
            series.updateMarkerState(type, index);
        },

        /**
         * Collection of `CartesianSeries` instances to be redrawn.
         *
         * @property _dispatchers
         * @type Array
         * @private
         */
        _dispatchers: null,

        /**
         * Updates the `Graph` styles.
         *
         * @method _updateStyles
         * @private
         */
        _updateStyles: function()
        {
            var styles = this.get("styles").background,
                border = styles.border;
                border.opacity = border.alpha;
                styles.stroke = border;
                styles.fill.opacity = styles.fill.alpha;
            this.get("background").set(styles);
            this._sizeChangeHandler();
        },

        /**
         * Event handler for size changes.
         *
         * @method _sizeChangeHandler
         * @param {Object} e Event object.
         * @private
         */
        _sizeChangeHandler: function()
        {
            var hgl = this.get("horizontalGridlines"),
                vgl = this.get("verticalGridlines"),
                w = this.get("width"),
                h = this.get("height"),
                bg = this.get("styles").background,
                weight,
                background;
            if(bg && bg.border)
            {
                weight = bg.border.weight || 0;
            }
            if(this.get("showBackground"))
            {
                background = this.get("background");
                if(w && h)
                {
                    background.set("width", w);
                    background.set("height", h);
                }
            }
            if(this._gridlines)
            {
                this._gridlines.clear();
            }
            if(hgl && hgl instanceof Y.Gridlines)
            {
                hgl.draw();
            }
            if(vgl && vgl instanceof Y.Gridlines)
            {
                vgl.draw();
            }
            this._drawSeries();
        },

        /**
         * Draws each series.
         *
         * @method _drawSeries
         * @private
         */
        _drawSeries: function()
        {
            if(this._drawing)
            {
                this._callLater = true;
                return;
            }
            var sc,
                i,
                len,
                graphic = this.get("graphic");
            graphic.set("autoDraw", false);
            graphic.set("width", this.get("width"));
            graphic.set("height", this.get("height"));
            this._callLater = false;
            this._drawing = true;
            sc = this.get("seriesCollection");
            i = 0;
            len = sc ? sc.length : 0;
            for(; i < len; ++i)
            {
                sc[i].draw();
                if((!sc[i].get("xcoords") || !sc[i].get("ycoords")) && !sc[i] instanceof Y.PieSeries)
                {
                    this._callLater = true;
                    break;
                }
            }
            this._drawing = false;
            if(this._callLater)
            {
                this._drawSeries();
            }
        },

        /**
         * Event handler for series drawingComplete event.
         *
         * @method _drawingCompleteHandler
         * @param {Object} e Event object.
         * @private
         */
        _drawingCompleteHandler: function(e)
        {
            var series = e.currentTarget,
                graphic,
                index = Y.Array.indexOf(this._dispatchers, series);
            if(index > -1)
            {
                this._dispatchers.splice(index, 1);
            }
            if(this._dispatchers.length < 1)
            {
                graphic = this.get("graphic");
                if(!graphic.get("autoDraw"))
                {
                    graphic._redraw();
                }
                this.fire("chartRendered");
            }
        },

        /**
         * Gets the default value for the `styles` attribute. Overrides
         * base implementation.
         *
         * @method _getDefaultStyles
         * @return Object
         * @protected
         */
        _getDefaultStyles: function()
        {
            var defs = {
                background: {
                    shape: "rect",
                    fill:{
                        color:"#faf9f2"
                    },
                    border: {
                        color:"#dad8c9",
                        weight: 1
                    }
                }
            };
            return defs;
        },

        /**
         * Destructor implementation Graph class. Removes all Graphic instances from the widget.
         *
         * @method destructor
         * @protected
         */
        destructor: function()
        {
            if(this._graphic)
            {
                this._graphic.destroy();
                this._graphic = null;
            }
            if(this._background)
            {
                this._background.get("graphic").destroy();
                this._background = null;
            }
            if(this._gridlines)
            {
                this._gridlines.get("graphic").destroy();
                this._gridlines = null;
            }
        }
    }, {
        ATTRS: {
            /**
             * The x-coordinate for the graph.
             *
             * @attribute x
             * @type Number
             * @protected
             */
            x: {
                setter: function(val)
                {
                    this.get("boundingBox").setStyle("left", val + "px");
                    return val;
                }
            },

            /**
             * The y-coordinate for the graph.
             *
             * @attribute y
             * @type Number
             * @protected
             */
            y: {
                setter: function(val)
                {
                    this.get("boundingBox").setStyle("top", val + "px");
                    return val;
                }
            },

            /**
             * Reference to the chart instance using the graph.
             *
             * @attribute chart
             * @type ChartBase
             * @readOnly
             */
            chart: {
                getter: function() {
                    var chart = this._state.chart || this;
                    return chart;
                }
            },

            /**
             * Collection of series. When setting the `seriesCollection` the array can contain a combination of either
             * `CartesianSeries` instances or object literals with properties that will define a series.
             *
             * @attribute seriesCollection
             * @type CartesianSeries
             */
            seriesCollection: {
                getter: function()
                {
                    return this._seriesCollection;
                },

                setter: function(val)
                {
                    this._parseSeriesCollection(val);
                    return this._seriesCollection;
                }
            },

            /**
             * Indicates whether the `Graph` has a background.
             *
             * @attribute showBackground
             * @type Boolean
             * @default true
             */
            showBackground: {
                value: true
            },

            /**
             * Read-only hash lookup for all series on in the `Graph`.
             *
             * @attribute seriesDictionary
             * @type Object
             * @readOnly
             */
            seriesDictionary: {
                readOnly: true,

                getter: function()
                {
                    return this._seriesDictionary;
                }
            },

            /**
             * Reference to the horizontal `Gridlines` instance.
             *
             * @attribute horizontalGridlines
             * @type Gridlines
             * @default null
             */
            horizontalGridlines: {
                value: null,

                setter: function(val)
                {
                    var cfg,
                        key,
                        gl = this.get("horizontalGridlines");
                    if(gl && gl instanceof Y.Gridlines)
                    {
                        gl.remove();
                    }
                    if(val instanceof Y.Gridlines)
                    {
                        gl = val;
                        val.set("graph", this);
                        return val;
                    }
                    else if(val)
                    {
                        cfg = {
                            direction: "horizonal",
                            graph: this
                        };
                        for(key in val)
                        {
                            if(val.hasOwnProperty(key))
                            {
                                cfg[key] = val[key];
                            }
                        }
                        gl = new Y.Gridlines(cfg);
                        return gl;
                    }
                }
            },

            /**
             * Reference to the vertical `Gridlines` instance.
             *
             * @attribute verticalGridlines
             * @type Gridlines
             * @default null
             */
            verticalGridlines: {
                value: null,

                setter: function(val)
                {
                    var cfg,
                        key,
                        gl = this.get("verticalGridlines");
                    if(gl && gl instanceof Y.Gridlines)
                    {
                        gl.remove();
                    }
                    if(val instanceof Y.Gridlines)
                    {
                        gl = val;
                        val.set("graph", this);
                        return val;
                    }
                    else if(val)
                    {
                        cfg = {
                            direction: "vertical",
                            graph: this
                        };
                        for(key in val)
                        {
                            if(val.hasOwnProperty(key))
                            {
                                cfg[key] = val[key];
                            }
                        }
                        gl = new Y.Gridlines(cfg);
                        return gl;
                    }
                }
            },

            /**
             * Reference to graphic instance used for the background.
             *
             * @attribute background
             * @type Graphic
             * @readOnly
             */
            background: {
                getter: function()
                {
                    if(!this._background)
                    {
                        this._backgroundGraphic = new Y.Graphic({render:this.get("contentBox")});
                        this._backgroundGraphic.get("node").style.zIndex = 0;
                        this._background = this._backgroundGraphic.addShape({type: "rect"});
                    }
                    return this._background;
                }
            },

            /**
             * Reference to graphic instance used for gridlines.
             *
             * @attribute gridlines
             * @type Graphic
             * @readOnly
             */
            gridlines: {
                readOnly: true,

                getter: function()
                {
                    if(!this._gridlines)
                    {
                        this._gridlinesGraphic = new Y.Graphic({render:this.get("contentBox")});
                        this._gridlinesGraphic.get("node").style.zIndex = 1;
                        this._gridlines = this._gridlinesGraphic.addShape({type: "path"});
                    }
                    return this._gridlines;
                }
            },

            /**
             * Reference to graphic instance used for series.
             *
             * @attribute graphic
             * @type Graphic
             * @readOnly
             */
            graphic: {
                readOnly: true,

                getter: function()
                {
                    if(!this._graphic)
                    {
                        this._graphic = new Y.Graphic({render:this.get("contentBox")});
                        this._graphic.get("node").style.zIndex = 2;
                        this._graphic.set("autoDraw", false);
                    }
                    return this._graphic;
                }
            },

            /**
             * Indicates whether or not markers for a series will be grouped and rendered in a single complex shape instance.
             *
             * @attribute groupMarkers
             * @type Boolean
             */
            groupMarkers: {
                value: false
            }

            /**
             * Style properties used for drawing a background. Below are the default values:
             *  <dl>
             *      <dt>background</dt><dd>An object containing the following values:
             *          <dl>
             *              <dt>fill</dt><dd>Defines the style properties for the fill. Contains the following values:
             *                  <dl>
             *                      <dt>color</dt><dd>Color of the fill. The default value is #faf9f2.</dd>
             *                      <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background fill.
             *                      The default value is 1.</dd>
             *                  </dl>
             *              </dd>
             *              <dt>border</dt><dd>Defines the style properties for the border. Contains the following values:
             *                  <dl>
             *                      <dt>color</dt><dd>Color of the border. The default value is #dad8c9.</dd>
             *                      <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background border.
             *                      The default value is 1.</dd>
             *                      <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
             *                  </dl>
             *              </dd>
             *          </dl>
             *      </dd>
             *  </dl>
             *
             * @attribute styles
             * @type Object
             */
        }
    });