diff -r d334a616c023 -r e16a97fb364a src/cm/media/js/lib/yui/yui3-3.15.0/build/series-cartesian/series-cartesian.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui3-3.15.0/build/series-cartesian/series-cartesian.js Mon Mar 10 15:19:48 2014 +0100 @@ -0,0 +1,947 @@ +YUI.add('series-cartesian', function (Y, NAME) { + +/** + * Provides functionality for creating a cartesian chart series. + * + * @module charts + * @submodule series-cartesian + */ +var Y_Lang = Y.Lang; + +/** + * An abstract class for creating series instances with horizontal and vertical axes. + * CartesianSeries provides the core functionality used by the following classes: + * + * + * @class CartesianSeries + * @extends SeriesBase + * @constructor + * @param {Object} config (optional) Configuration parameters. + * @submodule series-base + */ +Y.CartesianSeries = Y.Base.create("cartesianSeries", Y.SeriesBase, [], { + /** + * Storage for `xDisplayName` attribute. + * + * @property _xDisplayName + * @type String + * @private + */ + _xDisplayName: null, + + /** + * Storage for `yDisplayName` attribute. + * + * @property _yDisplayName + * @type String + * @private + */ + _yDisplayName: null, + + /** + * Th x-coordinate for the left edge of the series. + * + * @property _leftOrigin + * @type String + * @private + */ + _leftOrigin: null, + + /** + * The y-coordinate for the bottom edge of the series. + * + * @property _bottomOrigin + * @type String + * @private + */ + _bottomOrigin: null, + + /** + * Adds event listeners. + * + * @method addListeners + * @private + */ + addListeners: function() + { + var xAxis = this.get("xAxis"), + yAxis = this.get("yAxis"); + if(xAxis) + { + this._xDataReadyHandle = xAxis.after("dataReady", Y.bind(this._xDataChangeHandler, this)); + this._xDataUpdateHandle = xAxis.after("dataUpdate", Y.bind(this._xDataChangeHandler, this)); + } + if(yAxis) + { + this._yDataReadyHandle = yAxis.after("dataReady", Y.bind(this._yDataChangeHandler, this)); + this._yDataUpdateHandle = yAxis.after("dataUpdate", Y.bind(this._yDataChangeHandler, this)); + } + this._xAxisChangeHandle = this.after("xAxisChange", this._xAxisChangeHandler); + this._yAxisChangeHandle = this.after("yAxisChange", this._yAxisChangeHandler); + this._stylesChangeHandle = this.after("stylesChange", function() { + var axesReady = this._updateAxisBase(); + if(axesReady) + { + this.draw(); + } + }); + this._widthChangeHandle = this.after("widthChange", function() { + var axesReady = this._updateAxisBase(); + if(axesReady) + { + this.draw(); + } + }); + this._heightChangeHandle = this.after("heightChange", function() { + var axesReady = this._updateAxisBase(); + if(axesReady) + { + this.draw(); + } + }); + this._visibleChangeHandle = this.after("visibleChange", this._handleVisibleChange); + }, + + /** + * Event handler for the xAxisChange event. + * + * @method _xAxisChangeHandler + * @param {Object} e Event object. + * @private + */ + _xAxisChangeHandler: function() + { + var xAxis = this.get("xAxis"); + xAxis.after("dataReady", Y.bind(this._xDataChangeHandler, this)); + xAxis.after("dataUpdate", Y.bind(this._xDataChangeHandler, this)); + }, + + /** + * Event handler the yAxisChange event. + * + * @method _yAxisChangeHandler + * @param {Object} e Event object. + * @private + */ + _yAxisChangeHandler: function() + { + var yAxis = this.get("yAxis"); + yAxis.after("dataReady", Y.bind(this._yDataChangeHandler, this)); + yAxis.after("dataUpdate", Y.bind(this._yDataChangeHandler, this)); + }, + + /** + * Constant used to generate unique id. + * + * @property GUID + * @type String + * @private + */ + GUID: "yuicartesianseries", + + /** + * Event handler for xDataChange event. + * + * @method _xDataChangeHandler + * @param {Object} event Event object. + * @private + */ + _xDataChangeHandler: function() + { + var axesReady = this._updateAxisBase(); + if(axesReady) + { + this.draw(); + } + }, + + /** + * Event handler for yDataChange event. + * + * @method _yDataChangeHandler + * @param {Object} event Event object. + * @private + */ + _yDataChangeHandler: function() + { + var axesReady = this._updateAxisBase(); + if(axesReady) + { + this.draw(); + } + }, + + /** + * Checks to ensure that both xAxis and yAxis data are available. If so, set the `xData` and `yData` attributes + * and return `true`. Otherwise, return `false`. + * + * @method _updateAxisBase + * @return Boolean + * @private + */ + _updateAxisBase: function() + { + var xAxis = this.get("xAxis"), + yAxis = this.get("yAxis"), + xKey = this.get("xKey"), + yKey = this.get("yKey"), + yData, + xData, + xReady, + yReady, + ready; + if(!xAxis || !yAxis || !xKey || !yKey) + { + ready = false; + } + else + { + xData = xAxis.getDataByKey(xKey); + yData = yAxis.getDataByKey(yKey); + if(Y_Lang.isArray(xKey)) + { + xReady = (xData && Y.Object.size(xData) > 0) ? this._checkForDataByKey(xData, xKey) : false; + } + else + { + xReady = xData ? true : false; + } + if(Y_Lang.isArray(yKey)) + { + yReady = (yData && Y.Object.size(yData) > 0) ? this._checkForDataByKey(yData, yKey) : false; + } + else + { + yReady = yData ? true : false; + } + ready = xReady && yReady; + if(ready) + { + this.set("xData", xData); + this.set("yData", yData); + } + } + return ready; + }, + + /** + * Checks to see if all keys of a data object exist and contain data. + * + * @method _checkForDataByKey + * @param {Object} obj The object to check + * @param {Array} keys The keys to check + * @return Boolean + * @private + */ + _checkForDataByKey: function(obj, keys) + { + var i, + len = keys.length, + hasData = false; + for(i = 0; i < len; i = i + 1) + { + if(obj[keys[i]]) + { + hasData = true; + break; + } + } + return hasData; + }, + + /** + * Draws the series is the xAxis and yAxis data are both available. + * + * @method validate + * @private + */ + validate: function() + { + if((this.get("xData") && this.get("yData")) || this._updateAxisBase()) + { + this.draw(); + } + else + { + this.fire("drawingComplete"); + } + }, + + /** + * Calculates the coordinates for the series. + * + * @method setAreaData + * @protected + */ + setAreaData: function() + { + var w = this.get("width"), + h = this.get("height"), + xAxis = this.get("xAxis"), + yAxis = this.get("yAxis"), + xData = this._copyData(this.get("xData")), + yData = this._copyData(this.get("yData")), + direction = this.get("direction"), + dataLength = direction === "vertical" ? yData.length : xData.length, + xOffset = xAxis.getEdgeOffset(xAxis.getTotalMajorUnits(), w), + yOffset = yAxis.getEdgeOffset(yAxis.getTotalMajorUnits(), h), + padding = this.get("styles").padding, + leftPadding = padding.left, + topPadding = padding.top, + dataWidth = w - (leftPadding + padding.right + xOffset * 2), + dataHeight = h - (topPadding + padding.bottom + yOffset * 2), + xMax = xAxis.get("maximum"), + xMin = xAxis.get("minimum"), + yMax = yAxis.get("maximum"), + yMin = yAxis.get("minimum"), + graphic = this.get("graphic"), + yAxisType = yAxis.get("type"), + reverseYCoords = (yAxisType === "numeric" || yAxisType === "stacked"), + xcoords, + ycoords, + xOriginValue = xAxis.getOrigin(), + yOriginValue = yAxis.getOrigin(); + graphic.set("width", w); + graphic.set("height", h); + xOffset = xOffset + leftPadding; + yOffset = reverseYCoords ? yOffset + dataHeight + topPadding + padding.bottom : topPadding + yOffset; + this._leftOrigin = Math.round(xAxis._getCoordFromValue(xMin, xMax, dataWidth, xOriginValue, xOffset, false)); + this._bottomOrigin = Math.round(yAxis._getCoordFromValue(yMin, yMax, dataHeight, yOriginValue, yOffset, reverseYCoords)); + + xcoords = this._getCoords(xMin, xMax, dataWidth, xData, xAxis, xOffset, false); + ycoords = this._getCoords(yMin, yMax, dataHeight, yData, yAxis, yOffset, reverseYCoords); + this.set("xcoords", xcoords); + this.set("ycoords", ycoords); + this._dataLength = dataLength; + this._setXMarkerPlane(xcoords, dataLength); + this._setYMarkerPlane(ycoords, dataLength); + }, + + /** + * Returns either an array coordinates or an object key valued arrays of coordinates depending on the input. + * If the input data is an array, an array is returned. If the input data is an object, an object will be returned. + * + * @method _getCoords + * @param {Number} min The minimum value of the range of data. + * @param {Number} max The maximum value of the range of data. + * @param {Number} length The length, in pixels, of across which the coordinates will be calculated. + * @param {AxisBase} axis The axis in which the data is bound. + * @param {Number} offset The value in which to offet the first coordinate. + * @param {Boolean} reverse Indicates whether to calculate the coordinates in reverse order. + * @return Array|Object + * @private + */ + _getCoords: function(min, max, length, data, axis, offset, reverse) + { + var coords, + key; + if(Y_Lang.isArray(data)) + { + coords = axis._getCoordsFromValues(min, max, length, data, offset, reverse); + } + else + { + coords = {}; + for(key in data) + { + if(data.hasOwnProperty(key)) + { + coords[key] = this._getCoords.apply(this, [min, max, length, data[key], axis, offset, reverse]); + } + } + } + return coords; + }, + + /** + * Used to cache xData and yData in the setAreaData method. Returns a copy of an + * array if an array is received as the param and returns an object literal of + * array copies if an object literal is received as the param. + * + * @method _copyData + * @param {Array|Object} val The object or array to be copied. + * @return Array|Object + * @private + */ + _copyData: function(val) + { + var copy, + key; + if(Y_Lang.isArray(val)) + { + copy = val.concat(); + } + else + { + copy = {}; + for(key in val) + { + if(val.hasOwnProperty(key)) + { + copy[key] = val[key].concat(); + } + } + } + return copy; + }, + + /** + * Sets the marker plane for the series when the coords argument is an array. + * If the coords argument is an object literal no marker plane is set. + * + * @method _setXMarkerPlane + * @param {Array|Object} coords An array of x coordinates or an object literal + * containing key value pairs mapped to an array of coordinates. + * @param {Number} dataLength The length of data for the series. + * @private + */ + _setXMarkerPlane: function(coords, dataLength) + { + var i = 0, + xMarkerPlane = [], + xMarkerPlaneOffset = this.get("xMarkerPlaneOffset"), + nextX; + if(Y_Lang.isArray(coords)) + { + for(i = 0; i < dataLength; i = i + 1) + { + nextX = coords[i]; + xMarkerPlane.push({start:nextX - xMarkerPlaneOffset, end: nextX + xMarkerPlaneOffset}); + } + this.set("xMarkerPlane", xMarkerPlane); + } + }, + + /** + * Sets the marker plane for the series when the coords argument is an array. + * If the coords argument is an object literal no marker plane is set. + * + * @method _setYMarkerPlane + * @param {Array|Object} coords An array of y coordinates or an object literal + * containing key value pairs mapped to an array of coordinates. + * @param {Number} dataLength The length of data for the series. + * @private + */ + _setYMarkerPlane: function(coords, dataLength) + { + var i = 0, + yMarkerPlane = [], + yMarkerPlaneOffset = this.get("yMarkerPlaneOffset"), + nextY; + if(Y_Lang.isArray(coords)) + { + for(i = 0; i < dataLength; i = i + 1) + { + nextY = coords[i]; + yMarkerPlane.push({start:nextY - yMarkerPlaneOffset, end: nextY + yMarkerPlaneOffset}); + } + this.set("yMarkerPlane", yMarkerPlane); + } + }, + + /** + * Finds the first valid index of an array coordinates. + * + * @method _getFirstValidIndex + * @param {Array} coords An array of x or y coordinates. + * @return Number + * @private + */ + _getFirstValidIndex: function(coords) + { + var coord, + i = -1, + limit = coords.length; + while(!Y_Lang.isNumber(coord) && i < limit) + { + i += 1; + coord = coords[i]; + } + return i; + }, + + /** + * Finds the last valid index of an array coordinates. + * + * @method _getLastValidIndex + * @param {Array} coords An array of x or y coordinates. + * @return Number + * @private + */ + _getLastValidIndex: function(coords) + { + var coord, + i = coords.length, + limit = -1; + while(!Y_Lang.isNumber(coord) && i > limit) + { + i -= 1; + coord = coords[i]; + } + return i; + }, + + /** + * Draws the series. + * + * @method draw + * @protected + */ + draw: function() + { + var w = this.get("width"), + h = this.get("height"), + xcoords, + ycoords; + if(this.get("rendered")) + { + if((isFinite(w) && isFinite(h) && w > 0 && h > 0) && + ((this.get("xData") && this.get("yData")) || + this._updateAxisBase())) + { + if(this._drawing) + { + this._callLater = true; + return; + } + this._drawing = true; + this._callLater = false; + this.setAreaData(); + xcoords = this.get("xcoords"); + ycoords = this.get("ycoords"); + if(xcoords && ycoords && xcoords.length > 0) + { + this.drawSeries(); + } + this._drawing = false; + if(this._callLater) + { + this.draw(); + } + else + { + this._toggleVisible(this.get("visible")); + this.fire("drawingComplete"); + } + } + } + }, + + /** + * Default value for plane offsets when the parent chart's `interactiveType` is `planar`. + * + * @property _defaultPlaneOffset + * @type Number + * @private + */ + _defaultPlaneOffset: 4, + + /** + * Destructor implementation for the CartesianSeries class. + * Calls destroy on all Graphic instances. + * + * @method destructor + * @protected + */ + destructor: function() + { + if(this.get("rendered")) + { + if(this._xDataReadyHandle) + { + this._xDataReadyHandle.detach(); + } + if(this._xDataUpdateHandle) + { + this._xDataUpdateHandle.detach(); + } + if(this._yDataReadyHandle) + { + this._yDataReadyHandle.detach(); + } + if(this._yDataUpdateHandle) + { + this._yDataUpdateHandle.detach(); + } + if(this._xAxisChangeHandle) + { + this._xAxisChangeHandle.detach(); + } + if(this._yAxisChangeHandle) + { + this._yAxisChangeHandle.detach(); + } + } + } + /** + * Event handle for the x-axis' dataReady event. + * + * @property _xDataReadyHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the x-axis dataUpdate event. + * + * @property _xDataUpdateHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the y-axis dataReady event. + * + * @property _yDataReadyHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the y-axis dataUpdate event. + * @property _yDataUpdateHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the xAxisChange event. + * @property _xAxisChangeHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the yAxisChange event. + * @property _yAxisChangeHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the stylesChange event. + * @property _stylesChangeHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the widthChange event. + * @property _widthChangeHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the heightChange event. + * @property _heightChangeHandle + * @type {EventHandle} + * @private + */ + + /** + * Event handle for the visibleChange event. + * @property _visibleChangeHandle + * @type {EventHandle} + * @private + */ +}, { + ATTRS: { + /** + * An array of all series of the same type used within a chart application. + * + * @attribute seriesTypeCollection + * @type Array + */ + seriesTypeCollection: {}, + + /** + * Name used for for displaying data related to the x-coordinate. + * + * @attribute xDisplayName + * @type String + */ + xDisplayName: { + getter: function() + { + return this._xDisplayName || this.get("xKey"); + }, + + setter: function(val) + { + this._xDisplayName = val.toString(); + return val; + } + }, + + /** + * Name used for for displaying data related to the y-coordinate. + * + * @attribute yDisplayName + * @type String + */ + yDisplayName: { + getter: function() + { + return this._yDisplayName || this.get("yKey"); + }, + + setter: function(val) + { + this._yDisplayName = val.toString(); + return val; + } + }, + + /** + * Name used for for displaying category data + * + * @attribute categoryDisplayName + * @type String + * @readOnly + */ + categoryDisplayName: { + lazyAdd: false, + + getter: function() + { + return this.get("direction") === "vertical" ? this.get("yDisplayName") : this.get("xDisplayName"); + }, + + setter: function(val) + { + if(this.get("direction") === "vertical") + { + this._yDisplayName = val; + } + else + { + this._xDisplayName = val; + } + return val; + } + }, + + /** + * Name used for for displaying value data + * + * @attribute valueDisplayName + * @type String + * @readOnly + */ + valueDisplayName: { + lazyAdd: false, + + getter: function() + { + return this.get("direction") === "vertical" ? this.get("xDisplayName") : this.get("yDisplayName"); + }, + + setter: function(val) + { + if(this.get("direction") === "vertical") + { + this._xDisplayName = val; + } + else + { + this._yDisplayName = val; + } + return val; + } + }, + + /** + * Read-only attribute indicating the type of series. + * + * @attribute type + * @type String + * @default cartesian + */ + type: { + value: "cartesian" + }, + + /** + * Order of this instance of this `type`. + * + * @attribute order + * @type Number + */ + order: {}, + + /** + * Order of the instance + * + * @attribute graphOrder + * @type Number + */ + graphOrder: {}, + + /** + * x coordinates for the series. + * + * @attribute xcoords + * @type Array + */ + xcoords: {}, + + /** + * y coordinates for the series + * + * @attribute ycoords + * @type Array + */ + ycoords: {}, + + /** + * Reference to the `Axis` instance used for assigning + * x-values to the graph. + * + * @attribute xAxis + * @type Axis + */ + xAxis: {}, + + /** + * Reference to the `Axis` instance used for assigning + * y-values to the graph. + * + * @attribute yAxis + * @type Axis + */ + yAxis: {}, + + /** + * Indicates which array to from the hash of value arrays in + * the x-axis `Axis` instance. + * + * @attribute xKey + * @type String + */ + xKey: { + setter: function(val) + { + if(Y_Lang.isArray(val)) + { + return val; + } + else + { + return val.toString(); + } + } + }, + + /** + * Indicates which array to from the hash of value arrays in + * the y-axis `Axis` instance. + * + * @attribute yKey + * @type String + */ + yKey: { + setter: function(val) + { + if(Y_Lang.isArray(val)) + { + return val; + } + else + { + return val.toString(); + } + } + }, + + /** + * Array of x values for the series. + * + * @attribute xData + * @type Array + */ + xData: {}, + + /** + * Array of y values for the series. + * + * @attribute yData + * @type Array + */ + yData: {}, + + /** + * Collection of area maps along the xAxis. Used to determine mouseover for multiple + * series. + * + * @attribute xMarkerPlane + * @type Array + */ + xMarkerPlane: {}, + + /** + * Collection of area maps along the yAxis. Used to determine mouseover for multiple + * series. + * + * @attribute yMarkerPlane + * @type Array + */ + yMarkerPlane: {}, + + /** + * Distance from a data coordinate to the left/right for setting a hotspot. + * + * @attribute xMarkerPlaneOffset + * @type Number + */ + xMarkerPlaneOffset: { + getter: function() { + var marker = this.get("styles").marker; + if(marker && marker.width && isFinite(marker.width)) + { + return marker.width * 0.5; + } + return this._defaultPlaneOffset; + } + }, + + /** + * Distance from a data coordinate to the top/bottom for setting a hotspot. + * + * @attribute yMarkerPlaneOffset + * @type Number + */ + yMarkerPlaneOffset: { + getter: function() { + var marker = this.get("styles").marker; + if(marker && marker.height && isFinite(marker.height)) + { + return marker.height * 0.5; + } + return this._defaultPlaneOffset; + } + }, + + /** + * Direction of the series + * + * @attribute direction + * @type String + */ + direction: { + value: "horizontal" + } + } +}); + + +}, '@VERSION@', {"requires": ["series-base"]});