- /**
- * 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
- */
- }
- });
-
-