CartesianChart.js revision 117557654069e56f5003be755819b76fe0f77107
/**
* The CartesianChart class creates a chart with horizontal and vertical axes.
*
* @module charts
* @class CartesianChart
* @extends ChartBase
* @constructor
*/
/**
* @method renderUI
* @private
*/
renderUI: function()
{
//move the position = absolute logic to a class file
this._addAxes();
this._addGridlines();
this._addSeries();
{
this._addTooltip();
}
//If there is a style definition. Force them to set.
this.get("styles");
{
}
this._redraw();
},
/**
* When `interactionType` is set to `planar`, listens for mouse move events and fires `planarEvent:mouseover` or `planarEvent:mouseout` depending on the position of the mouse in relation to
* data points on the `Chart`.
*
* @method _planarEventDispatcher
* @param {Object} e Event object.
* @private
*/
_planarEventDispatcher: function(e)
{
offset = {
},
i = 0,
oldIndex = this._selectedIndex,
item,
items = [],
categoryItems = [],
valueItems = [],
//data columns and area data could be created on a graph level
len,
if(direction == "horizontal")
{
catAxis = "x";
valAxis = "y";
}
else
{
valAxis = "x";
catAxis = "y";
}
if(sc)
{
while(i < len && !markerPlane)
{
if(sc[i])
{
}
i++;
}
}
if(markerPlane)
{
for(i = 0; i < len; ++i)
{
{
index = i;
break;
}
}
for(i = 0; i < len; ++i)
{
{
}
{
{
}
}
}
this._selectedIndex = index;
/**
* Broadcasts when `interactionType` is set to `planar` and a series' marker plane has received a mouseover event.
*
*
* @event planarEvent:mouseover
* @preventable false
* @param {EventFacade} e Event facade with the following additional
* properties:
* <dl>
* <dt>categoryItem</dt><dd>An array of hashes, each containing information about the category `Axis` of each marker whose plane has been intersected.</dd>
* <dt>valueItem</dt><dd>An array of hashes, each containing information about the value `Axis` of each marker whose plane has been intersected.</dd>
* <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
* <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
* <dt>pageX</dt><dd>The x location of the event on the page (including scroll)</dd>
* <dt>pageY</dt><dd>The y location of the event on the page (including scroll)</dd>
* <dt>items</dt><dd>An array including all the series which contain a marker whose plane has been intersected.</dd>
* <dt>index</dt><dd>Index of the markers in their respective series.</dd>
* <dt>originEvent</dt><dd>Underlying dom event.</dd>
* </dl>
*/
/**
* Broadcasts when `interactionType` is set to `planar` and a series' marker plane has received a mouseout event.
*
* @event planarEvent:mouseout
* @preventable false
* @param {EventFacade} e
*/
if(index > -1)
{
this.fire("planarEvent:mouseover", {
x:posX,
y:posY,
});
}
else
{
this.fire("planarEvent:mouseout");
}
}
},
/**
* Indicates the default series type for the chart.
*
* @property _type
* @type {String}
* @private
*/
_type: "combo",
/**
* Queue of axes instances that will be updated. This method is used internally to determine when all axes have been updated.
*
* @property _axesRenderQueue
* @type Array
* @private
*/
_axesRenderQueue: null,
/**
* Adds an `Axis` instance to the `_axesRenderQueue`.
*
* @method _addToAxesRenderQueue
* @param {Axis} axis An `Axis` instance.
* @private
*/
_addToAxesRenderQueue: function(axis)
{
if(!this._axesRenderQueue)
{
this._axesRenderQueue = [];
}
{
}
},
/**
* Adds axis instance to the appropriate array based on position
*
* @method _addToAxesCollection
* @param {String} position The position of the axis
* @param {Axis} axis The `Axis` instance
*/
{
if(!axesCollection)
{
axesCollection = [];
}
},
/**
* Returns the default value for the `seriesCollection` attribute.
*
* @method _getDefaultSeriesCollection
* @param {Array} val Array containing either `CartesianSeries` instances or objects containing data to construct series instances.
* @return Array
* @private
*/
_getDefaultSeriesCollection: function(val)
{
tempKeys = [],
i,
l,
key,
if(dir == "vertical")
{
catAxis = "yAxis";
catKey = "yKey";
valAxis = "xAxis";
seriesKey = "xKey";
}
else
{
catAxis = "xAxis";
catKey = "xKey";
valAxis = "yAxis";
seriesKey = "yKey";
}
for(i = 0; i < l; ++i)
{
if(key)
{
if(index > -1)
{
}
}
}
{
}
for(i = 0; i < l; ++i)
{
if(series instanceof Y.CartesianSeries)
{
this._parseSeriesAxes(series);
continue;
}
if((series.type == "combo" || series.type == "stackedcombo" || series.type == "combospline" || series.type == "stackedcombospline"))
{
if(showAreaFill !== null)
{
series.showAreaFill = (series.showAreaFill !== null && series.showAreaFill !== undefined) ? series.showAreaFill : showAreaFill;
}
if(showMarkers !== null)
{
series.showMarkers = (series.showMarkers !== null && series.showMarkers !== undefined) ? series.showMarkers : showMarkers;
}
if(showLines !== null)
{
series.showLines = (series.showLines !== null && series.showLines !== undefined) ? series.showLines : showLines;
}
}
}
if(val)
{
}
return sc;
},
/**
* Parse and sets the axes for a series instance.
*
* @method _parseSeriesAxes
* @param {CartesianSeries} series A `CartesianSeries` instance.
* @private
*/
_parseSeriesAxes: function(series)
{
axis;
{
{
}
}
{
{
}
}
},
/**
* Returns the category axis instance for the chart.
*
* @method _getCategoryAxis
* @return Axis
* @private
*/
_getCategoryAxis: function()
{
var axis,
return axis;
},
/**
* Returns the value axis for a series.
*
* @method _getSeriesAxis
* @param {String} key The key value used to determine the axis instance.
* @return Axis
* @private
*/
{
i,
keys,
axis;
if(axes)
{
{
}
else
{
for(i in axes)
{
if(axes.hasOwnProperty(i))
{
{
break;
}
}
}
}
}
return axis;
},
/**
* Gets an attribute from an object, using a getter for Base objects and a property for object
* literals. Used for determining attributes from series/axis references which can be an actual class instance
* or a hash of properties that will be used to create a class instance.
*
* @method _getBaseAttribute
* @param {Object} item Object or instance in which the attribute resides.
* @param {String} key Attribute whose value will be returned.
* @return Object
* @private
*/
{
{
}
{
}
return null;
},
/**
* Sets an attribute on an object, using a setter of Base objects and a property for object
* literals. Used for setting attributes on a Base class, either directly or to be stored in an object literal
* for use at instantiation.
*
* @method _setBaseAttribute
* @param {Object} item Object or instance in which the attribute resides.
* @param {String} key Attribute whose value will be assigned.
* @param {Object} value Value to be assigned to the attribute.
* @private
*/
{
{
}
else
{
}
},
/**
* Creates `Axis` instances.
*
* @method _parseAxes
* @param {Object} val Object containing `Axis` instances or objects in which to construct `Axis` instances.
* @return Object
* @private
*/
_parseAxes: function(val)
{
axes = {},
axesAttrs = {
edgeOffset: "edgeOffset",
position: "position",
overlapGraph:"overlapGraph",
labelFunction:"labelFunction",
labelFunctionScope:"labelFunctionScope",
labelFormat:"labelFormat",
maximum:"maximum",
minimum:"minimum",
roundingMethod:"roundingMethod",
alwaysShowZero:"alwaysShowZero",
title:"title"
},
ai,
i,
pos,
axis,
dh,
for(i in hash)
{
if(hash.hasOwnProperty(i))
{
{
}
else
{
axis = null;
config = {};
{
}
{
}
{
{
}
}
//only check for existing axis if we constructed the default axes already
if(val)
{
axis = this.getAxisByKey(i);
}
{
if(pos != axisPosition)
{
if(axisPosition != "none")
{
}
if(pos != "none")
{
}
}
}
else
{
}
}
if(axis)
{
{
}
}
}
}
return axes;
},
/**
* Adds axes to the chart.
*
* @method _addAxes
* @private
*/
_addAxes: function()
{
i,
axis,
pos,
w = this.get("width"),
h = this.get("height"),
if(!this._axesCollection)
{
this._axesCollection = [];
}
for(i in axes)
{
if(axes.hasOwnProperty(i))
{
{
if(!w)
{
w = this.get("width");
}
if(!h)
{
h = this.get("height");
}
this._addToAxesRenderQueue(axis);
{
}
else
{
}
{
}
}
}
}
},
/**
* Renders the Graph.
*
* @method _addSeries
* @private
*/
_addSeries: function()
{
},
/**
* Adds gridlines to the chart.
*
* @method _addGridlines
* @private
*/
_addGridlines: function()
{
if(this._axesCollection)
{
}
if(hgl)
{
{
}
{
}
else
{
}
{
}
{
}
}
if(vgl)
{
{
}
{
}
else
{
}
{
}
{
}
}
},
/**
* Returns all the keys contained in a `dataProvider`.
*
* @method _getAllKeys
* @param {Array} dp Collection of objects to be parsed.
* @return Object
*/
_getAllKeys: function(dp)
{
var i = 0,
item,
key,
keys = {};
for(; i < len; ++i)
{
{
{
}
}
}
return keys;
},
/**
* Generates and returns a key-indexed object containing `Axis` instances or objects used to create `Axis` instances.
*
* @method _getDefaultAxes
* @param {Object} axes Object containing `Axis` instances or `Axis` attributes.
* @return Object
* @private
*/
_getDefaultAxes: function(axes)
{
axis,
attr,
keys,
newAxes = {},
claimedKeys = [],
i,
l,
ii,
ll,
dv,
valueAxes = [],
if(direction == "vertical")
{
seriesPosition = "bottom";
categoryPosition = "left";
}
else
{
seriesPosition = "left";
categoryPosition = "bottom";
}
if(axes)
{
for(i in axes)
{
if(axes.hasOwnProperty(i))
{
{
categoryAxisName = i;
this.set("categoryAxisName", i);
{
}
}
else if(i == categoryAxisName)
{
}
else
{
{
{
}
}
{
}
{
this._setBaseAttribute(newAxes[i], "position", this._getDefaultAxisPosition(newAxes[i], valueAxes, seriesPosition));
}
}
}
}
}
{
for(i in dv)
{
{
seriesKeys.push(i);
}
}
}
if(cIndex > -1)
{
}
l = claimedKeys.length;
for(i = 0; i < l; ++i)
{
if(cIndex > -1)
{
}
}
{
newAxes[categoryAxisName] = {};
}
{
}
{
}
{
}
{
}
{
{
}
else
{
}
}
{
{
this._setBaseAttribute(newAxes[valueAxisName], "position", this._getDefaultAxisPosition(newAxes[valueAxisName], valueAxes, seriesPosition));
}
{
}
{
}
}
return newAxes;
},
/**
* Determines the position of an axis when one is not specified.
*
* @method _getDefaultAxisPosition
* @param {Axis} axis `Axis` instance.
* @param {Array} valueAxes Array of `Axis` instances.
* @param {String} position Default position depending on the direction of the chart and type of axis.
* @return String
* @private
*/
{
{
if(direction == "horizontal")
{
{
position = "right";
}
{
position = "left";
}
}
else
{
{
position = "top";
}
else
{
position = "bottom";
}
}
}
return position;
},
/**
* Returns an object literal containing a categoryItem and a valueItem for a given series index. Below is the structure of each:
*
* @method getSeriesItems
* @param {CartesianSeries} series Reference to a series.
* @param {Number} index Index of the specified item within a series.
* @return Object An object literal containing the following:
*
* <dl>
* <dt>categoryItem</dt><dd>Object containing the following data related to the category axis of the series.
* <dl>
* <dt>axis</dt><dd>Reference to the category axis of the series.</dd>
* <dt>key</dt><dd>Category key for the series.</dd>
* <dt>value</dt><dd>Value on the axis corresponding to the series index.</dd>
* </dl>
* </dd>
* <dt>valueItem</dt><dd>Object containing the following data related to the category axis of the series.
* <dl>
* <dt>axis</dt><dd>Reference to the value axis of the series.</dd>
* <dt>key</dt><dd>Value key for the series.</dd>
* <dt>value</dt><dd>Value on the axis corresponding to the series index.</dd>
* </dl>
* </dd>
* </dl>
*/
{
{
categoryItem = {
};
valueItem = {
};
}
else
{
valueItem = {
};
categoryItem = {
};
}
},
/**
* Handler for axisRendered event.
*
* @method _axisRendered
* @param {Object} e Event object.
* @private
*/
_axisRendered: function(e)
{
this._axesRenderQueue = this._axesRenderQueue.splice(1 + Y.Array.indexOf(this._axesRenderQueue, e.currentTarget), 1);
{
this._redraw();
}
},
/**
* Handler for sizeChanged event.
*
* @method _sizeChanged
* @param {Object} e Event object.
* @private
*/
_sizeChanged: function(e)
{
if(this._axesCollection)
{
var ac = this._axesCollection,
i = 0,
for(; i < l; ++i)
{
this._addToAxesRenderQueue(ac[i]);
}
this._redraw();
}
},
/**
* Redraws and position all the components of the chart instance.
*
* @method _redraw
* @private
*/
_redraw: function()
{
if(this._drawing)
{
this._callLater = true;
return;
}
this._drawing = true;
this._callLater = false;
var w = this.get("width"),
h = this.get("height"),
lw = 0,
rw = 0,
th = 0,
bh = 0,
i = 0,
l,
axis,
pos,
pts = [],
graphOverflow = "visible",
if(lc)
{
for(i = l - 1; i > -1; --i)
{
}
}
if(rc)
{
i = 0;
for(i = l - 1; i > -1; --i)
{
}
}
if(tc)
{
for(i = l - 1; i > -1; --i)
{
}
}
if(bc)
{
for(i = l - 1; i > -1; --i)
{
}
}
l = this._axesCollection.length;
i = 0;
for(; i < l; ++i)
{
axis = this._axesCollection[i];
{
{
}
}
{
{
}
}
if(axis._hasDataOverflow())
{
graphOverflow = "hidden";
}
}
this._drawing = false;
if(this._callLater)
{
this._redraw();
return;
}
if(graph)
{
}
if(this._overlay)
{
}
},
/**
* Destructor implementation for the CartesianChart class. Calls destroy on all axes, series and the Graph instance.
* Removes the tooltip and overlay HTML elements.
*
* @method destructor
* @protected
*/
destructor: function()
{
i = 0,
len,
axesCollection = this._axesCollection,
for(; i < len; ++i)
{
if(seriesCollection[i] instanceof Y.CartesianSeries)
{
seriesCollection[i].destroy(true);
}
}
for(i = 0; i < len; ++i)
{
if(axesCollection[i] instanceof Y.Axis)
{
axesCollection[i].destroy(true);
}
}
if(graph)
{
}
if(tooltip)
{
}
if(this._overlay)
{
}
}
}, {
ATTRS: {
/**
* Style object for the axes.
*
* @attribute axesStyles
* @type Object
* @private
*/
axesStyles: {
getter: function()
{
i,
styles = this._axesStyles;
if(axes)
{
for(i in axes)
{
{
if(!styles)
{
styles = {};
}
}
}
}
return styles;
},
{
i;
for(i in val)
{
{
}
}
}
},
/**
* Style object for the series
*
* @attribute seriesStyles
* @type Object
* @private
*/
seriesStyles: {
getter: function()
{
var styles = this._seriesStyles,
dict,
i;
if(graph)
{
if(dict)
{
styles = {};
for(i in dict)
{
if(dict.hasOwnProperty(i))
{
}
}
}
}
return styles;
},
{
var i,
l,
s;
{
s = this.get("seriesCollection");
i = 0;
for(; i < l; ++i)
{
}
}
else
{
for(i in val)
{
if(val.hasOwnProperty(i))
{
s = this.getSeries(i);
}
}
}
}
},
/**
* Styles for the graph.
*
* @attribute graphStyles
* @type Object
* @private
*/
graphStyles: {
getter: function()
{
if(graph)
{
}
return this._graphStyles;
},
{
}
},
/**
* Style properties for the chart. Contains a key indexed hash of the following:
* <dl>
* <dt>series</dt><dd>A key indexed hash containing references to the `styles` attribute for each series in the chart.
* Specific style attributes vary depending on the series:
* <ul>
* <li><a href="AreaSeries.html#attr_styles">AreaSeries</a></li>
* <li><a href="BarSeries.html#attr_styles">BarSeries</a></li>
* <li><a href="ColumnSeries.html#attr_styles">ColumnSeries</a></li>
* <li><a href="ComboSeries.html#attr_styles">ComboSeries</a></li>
* <li><a href="LineSeries.html#attr_styles">LineSeries</a></li>
* <li><a href="MarkerSeries.html#attr_styles">MarkerSeries</a></li>
* <li><a href="SplineSeries.html#attr_styles">SplineSeries</a></li>
* </ul>
* </dd>
* <dt>axes</dt><dd>A key indexed hash containing references to the `styles` attribute for each axes in the chart. Specific
* style attributes can be found in the <a href="Axis.html#attr_styles">Axis</a> class.</dd>
* <dt>graph</dt><dd>A reference to the `styles` attribute in the chart. Specific style attributes can be found in the
* <a href="Graph.html#attr_styles">Graph</a> class.</dd>
* </dl>
*
* @attribute styles
* @type Object
*/
styles: {
getter: function()
{
var styles = {
};
return styles;
},
{
{
if(this.get("axesStyles"))
{
}
else
{
}
}
{
if(this.get("seriesStyles"))
{
}
else
{
}
}
{
}
}
},
/**
* Axes to appear in the chart. This can be a key indexed hash of axis instances or object literals
* used to construct the appropriate axes.
*
* @attribute axes
* @type Object
*/
axes: {
valueFn: "_getDefaultAxes",
{
return this._parseAxes(val);
}
},
/**
* Collection of series to appear on the chart. This can be an array of Series instances or object literals
* used to construct the appropriate series.
*
* @attribute seriesCollection
* @type Array
*/
valueFn: "_getDefaultSeriesCollection",
{
return this._getDefaultSeriesCollection(val);
}
},
/**
* Reference to the left-aligned axes for the chart.
*
* @attribute leftAxesCollection
* @type Array
* @private
*/
leftAxesCollection: {},
/**
* Reference to the bottom-aligned axes for the chart.
*
* @attribute bottomAxesCollection
* @type Array
* @private
*/
bottomAxesCollection: {},
/**
* Reference to the right-aligned axes for the chart.
*
* @attribute rightAxesCollection
* @type Array
* @private
*/
rightAxesCollection: {},
/**
* Reference to the top-aligned axes for the chart.
*
* @attribute topAxesCollection
* @type Array
* @private
*/
topAxesCollection: {},
/**
* Indicates whether or not the chart is stacked.
*
* @attribute stacked
* @type Boolean
*/
stacked: {
value: false
},
/**
* Direction of chart's category axis when there is no series collection specified. Charts can
* be horizontal or vertical. When the chart type is column, the chart is horizontal.
* When the chart type is bar, the chart is vertical.
*
* @attribute direction
* @type String
*/
direction: {
getter: function()
{
if(type == "bar")
{
return "vertical";
}
else if(type == "column")
{
return "horizontal";
}
return this._direction;
},
{
this._direction = val;
return this._direction;
}
},
/**
* Indicates whether or not an area is filled in a combo chart.
*
* @attribute showAreaFill
* @type Boolean
*/
showAreaFill: {},
/**
* Indicates whether to display markers in a combo chart.
*
* @attribute showMarkers
* @type Boolean
*/
showMarkers:{},
/**
* Indicates whether to display lines in a combo chart.
*
* @attribute showLines
* @type Boolean
*/
showLines:{},
/**
* Indicates the key value used to identify a category axis in the `axes` hash. If
* not specified, the categoryKey attribute value will be used.
*
* @attribute categoryAxisName
* @type String
*/
},
/**
* Indicates the key value used to identify a the series axis when an axis not generated.
*
* @attribute valueAxisName
* @type String
*/
value: "values"
},
/**
* Reference to the horizontalGridlines for the chart.
*
* @attribute horizontalGridlines
* @type Gridlines
*/
getter: function()
{
if(graph)
{
}
return this._horizontalGridlines;
},
{
{
val = {};
}
if(graph)
{
}
else
{
this._horizontalGridlines = val;
}
}
},
/**
* Reference to the verticalGridlines for the chart.
*
* @attribute verticalGridlines
* @type Gridlines
*/
getter: function()
{
if(graph)
{
}
return this._verticalGridlines;
},
{
{
val = {};
}
if(graph)
{
}
else
{
this._verticalGridlines = val;
}
}
},
/**
* Type of chart when there is no series collection specified.
*
* @attribute type
* @type String
*/
type: {
getter: function()
{
if(this.get("stacked"))
{
return "stacked" + this._type;
}
return this._type;
},
{
if(this._type == "bar")
{
if(val != "bar")
{
}
}
else
{
if(val == "bar")
{
}
}
return this._type;
}
},
/**
* Reference to the category axis used by the chart.
*
* @attribute categoryAxis
* @type Axis
*/
categoryAxis:{}
}
});