AutorÃa | Ultima modificación | Ver Log |
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:* <ul>* <li>{{#crossLink "LineSeries"}}{{/crossLink}}</li>* <li>{{#crossLink "MarkerSeries"}}{{/crossLink}}</li>* <li>{{#crossLink "AreaSeries"}}{{/crossLink}}</li>* <li>{{#crossLink "SplineSeries"}}{{/crossLink}}</li>* <li>{{#crossLink "AreaSplineSeries"}}{{/crossLink}}</li>* <li>{{#crossLink "ComboSeries"}}{{/crossLink}}</li>* <li>{{#crossLink "ComboSplineSeries"}}{{/crossLink}}</li>* <li>{{#crossLink "Histogram"}}{{/crossLink}}</li>* </ul>** @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"}}});}, '3.18.1', {"requires": ["series-base"]});