2
YUI 3.10.3 (build 2fb5187)
3
Copyright 2013 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
8
YUI.add('series-cartesian', function (Y, NAME) {
11
* Provides functionality for creating a cartesian chart series.
14
* @submodule series-cartesian
19
* An abstract class for creating series instances with horizontal and vertical axes.
20
* CartesianSeries provides the core functionality used by the following classes:
22
* <li>{{#crossLink "LineSeries"}}{{/crossLink}}</li>
23
* <li>{{#crossLink "MarkerSeries"}}{{/crossLink}}</li>
24
* <li>{{#crossLink "AreaSeries"}}{{/crossLink}}</li>
25
* <li>{{#crossLink "SplineSeries"}}{{/crossLink}}</li>
26
* <li>{{#crossLink "AreaSplineSeries"}}{{/crossLink}}</li>
27
* <li>{{#crossLink "ComboSeries"}}{{/crossLink}}</li>
28
* <li>{{#crossLink "ComboSplineSeries"}}{{/crossLink}}</li>
29
* <li>{{#crossLink "Histogram"}}{{/crossLink}}</li>
32
* @class CartesianSeries
35
* @param {Object} config (optional) Configuration parameters.
36
* @submodule series-base
38
Y.CartesianSeries = Y.Base.create("cartesianSeries", Y.SeriesBase, [], {
40
* Storage for `xDisplayName` attribute.
42
* @property _xDisplayName
49
* Storage for `yDisplayName` attribute.
51
* @property _yDisplayName
58
* Th x-coordinate for the left edge of the series.
60
* @property _leftOrigin
67
* The y-coordinate for the bottom edge of the series.
69
* @property _bottomOrigin
76
* Adds event listeners.
78
* @method addListeners
81
addListeners: function()
83
var xAxis = this.get("xAxis"),
84
yAxis = this.get("yAxis");
87
this._xDataReadyHandle = xAxis.after("dataReady", Y.bind(this._xDataChangeHandler, this));
88
this._xDataUpdateHandle = xAxis.after("dataUpdate", Y.bind(this._xDataChangeHandler, this));
92
this._yDataReadyHandle = yAxis.after("dataReady", Y.bind(this._yDataChangeHandler, this));
93
this._yDataUpdateHandle = yAxis.after("dataUpdate", Y.bind(this._yDataChangeHandler, this));
95
this._xAxisChangeHandle = this.after("xAxisChange", this._xAxisChangeHandler);
96
this._yAxisChangeHandle = this.after("yAxisChange", this._yAxisChangeHandler);
97
this._stylesChangeHandle = this.after("stylesChange", function() {
98
var axesReady = this._updateAxisBase();
104
this._widthChangeHandle = this.after("widthChange", function() {
105
var axesReady = this._updateAxisBase();
111
this._heightChangeHandle = this.after("heightChange", function() {
112
var axesReady = this._updateAxisBase();
118
this._visibleChangeHandle = this.after("visibleChange", this._handleVisibleChange);
122
* Event handler for the xAxisChange event.
124
* @method _xAxisChangeHandler
125
* @param {Object} e Event object.
128
_xAxisChangeHandler: function()
130
var xAxis = this.get("xAxis");
131
xAxis.after("dataReady", Y.bind(this._xDataChangeHandler, this));
132
xAxis.after("dataUpdate", Y.bind(this._xDataChangeHandler, this));
136
* Event handler the yAxisChange event.
138
* @method _yAxisChangeHandler
139
* @param {Object} e Event object.
142
_yAxisChangeHandler: function()
144
var yAxis = this.get("yAxis");
145
yAxis.after("dataReady", Y.bind(this._yDataChangeHandler, this));
146
yAxis.after("dataUpdate", Y.bind(this._yDataChangeHandler, this));
150
* Constant used to generate unique id.
156
GUID: "yuicartesianseries",
159
* Event handler for xDataChange event.
161
* @method _xDataChangeHandler
162
* @param {Object} event Event object.
165
_xDataChangeHandler: function()
167
var axesReady = this._updateAxisBase();
175
* Event handler for yDataChange event.
177
* @method _yDataChangeHandler
178
* @param {Object} event Event object.
181
_yDataChangeHandler: function()
183
var axesReady = this._updateAxisBase();
191
* Checks to ensure that both xAxis and yAxis data are available. If so, set the `xData` and `yData` attributes
192
* and return `true`. Otherwise, return `false`.
194
* @method _updateAxisBase
198
_updateAxisBase: function()
200
var xAxis = this.get("xAxis"),
201
yAxis = this.get("yAxis"),
202
xKey = this.get("xKey"),
203
yKey = this.get("yKey"),
209
if(!xAxis || !yAxis || !xKey || !yKey)
215
xData = xAxis.getDataByKey(xKey);
216
yData = yAxis.getDataByKey(yKey);
217
if(Y_Lang.isArray(xKey))
219
xReady = (xData && Y.Object.size(xData) > 0) ? this._checkForDataByKey(xData, xKey) : false;
223
xReady = xData ? true : false;
225
if(Y_Lang.isArray(yKey))
227
yReady = (yData && Y.Object.size(yData) > 0) ? this._checkForDataByKey(yData, yKey) : false;
231
yReady = yData ? true : false;
233
ready = xReady && yReady;
236
this.set("xData", xData);
237
this.set("yData", yData);
244
* Checks to see if all keys of a data object exist and contain data.
246
* @method _checkForDataByKey
247
* @param {Object} obj The object to check
248
* @param {Array} keys The keys to check
252
_checkForDataByKey: function(obj, keys)
257
for(i = 0; i < len; i = i + 1)
269
* Draws the series is the xAxis and yAxis data are both available.
276
if((this.get("xData") && this.get("yData")) || this._updateAxisBase())
282
this.fire("drawingComplete");
287
* Calculates the coordinates for the series.
289
* @method setAreaData
292
setAreaData: function()
294
var w = this.get("width"),
295
h = this.get("height"),
296
xAxis = this.get("xAxis"),
297
yAxis = this.get("yAxis"),
298
xData = this._copyData(this.get("xData")),
299
yData = this._copyData(this.get("yData")),
300
direction = this.get("direction"),
301
dataLength = direction === "vertical" ? yData.length : xData.length,
302
xOffset = xAxis.getEdgeOffset(xAxis.getTotalMajorUnits(), w),
303
yOffset = yAxis.getEdgeOffset(yAxis.getTotalMajorUnits(), h),
304
padding = this.get("styles").padding,
305
leftPadding = padding.left,
306
topPadding = padding.top,
307
dataWidth = w - (leftPadding + padding.right + xOffset * 2),
308
dataHeight = h - (topPadding + padding.bottom + yOffset * 2),
309
xMax = xAxis.get("maximum"),
310
xMin = xAxis.get("minimum"),
311
yMax = yAxis.get("maximum"),
312
yMin = yAxis.get("minimum"),
313
xScaleFactor = dataWidth / (xMax - xMin),
314
yScaleFactor = dataHeight / (yMax - yMin),
315
graphic = this.get("graphic"),
318
graphic.set("width", w);
319
graphic.set("height", h);
320
//Assuming a vertical graph has a range/category for its vertical axis.
321
if(direction === "vertical")
323
yData = yData.reverse();
325
this._leftOrigin = Math.round(((0 - xMin) * xScaleFactor) + leftPadding + xOffset);
326
this._bottomOrigin = Math.round((dataHeight + topPadding + yOffset));
329
this._bottomOrigin = this._bottomOrigin - ((0 - yMin) * yScaleFactor);
331
xcoords = this._getXCoords(xData, xMin, dataWidth, xScaleFactor, xOffset, dataLength, leftPadding);
332
ycoords = this._getYCoords(yData, yMin, dataHeight, yScaleFactor, yOffset, dataLength, topPadding);
333
this.set("xcoords", xcoords);
334
this.set("ycoords", ycoords);
335
this._dataLength = dataLength;
336
this._setXMarkerPlane(xcoords, dataLength);
337
this._setYMarkerPlane(ycoords, dataLength);
341
* Used to cache xData and yData in the setAreaData method. Returns a copy of an
342
* array if an array is received as the param and returns an object literal of
343
* array copies if an object literal is received as the param.
346
* @param {Array|Object} val The object or array to be copied.
347
* @return Array|Object
350
_copyData: function(val)
354
if(Y_Lang.isArray(val))
363
if(val.hasOwnProperty(key))
365
copy[key] = val[key].concat();
373
* Sets the marker plane for the series when the coords argument is an array.
374
* If the coords argument is an object literal no marker plane is set.
376
* @method _setXMarkerPlane
377
* @param {Array|Object} coords An array of x coordinates or an object literal
378
* containing key value pairs mapped to an array of coordinates.
379
* @param {Number} dataLength The length of data for the series.
382
_setXMarkerPlane: function(coords, dataLength)
386
xMarkerPlaneOffset = this.get("xMarkerPlaneOffset"),
388
if(Y_Lang.isArray(coords))
390
for(i = 0; i < dataLength; i = i + 1)
393
xMarkerPlane.push({start:nextX - xMarkerPlaneOffset, end: nextX + xMarkerPlaneOffset});
395
this.set("xMarkerPlane", xMarkerPlane);
400
* Sets the marker plane for the series when the coords argument is an array.
401
* If the coords argument is an object literal no marker plane is set.
403
* @method _setYMarkerPlane
404
* @param {Array|Object} coords An array of y coordinates or an object literal
405
* containing key value pairs mapped to an array of coordinates.
406
* @param {Number} dataLength The length of data for the series.
409
_setYMarkerPlane: function(coords, dataLength)
413
yMarkerPlaneOffset = this.get("yMarkerPlaneOffset"),
415
if(Y_Lang.isArray(coords))
417
for(i = 0; i < dataLength; i = i + 1)
420
yMarkerPlane.push({start:nextY - yMarkerPlaneOffset, end: nextY + yMarkerPlaneOffset});
422
this.set("yMarkerPlane", yMarkerPlane);
427
* Gets the x-coordinates for a series. Used by the setAreaData method.
428
* Returns an array when an array is received as the first argument.
429
* Returns an object literal when an object literal is received as the first argument.
431
* @method _getXCoords
432
* @param {Array|Object} xData An array of data values mapped to the x axis or an
433
* object literal containing key values pairs of data values mapped to the x axis.
434
* @param {Number} xMin The minimum value of the x axis.
435
* @param {Number} dataWidth The width used to calculate the x-coordinates.
436
* @param {Number} xScaleFactor The ratio used to calculate x-coordinates.
437
* @param {Number} xOffset The distance of the first and last x-coordinate from the
438
* beginning and end of the x-axis.
439
* @param {Number} dataLength The number of data points in the arrays.
440
* @param {Number} leftPadding The left padding of the series.
441
* @return Array|Object
444
_getXCoords: function(xData, xMin, dataWidth, xScaleFactor, xOffset, dataLength, leftPadding)
446
var isNumber = Y_Lang.isNumber,
452
if(Y_Lang.isArray(xData))
455
for (i = 0; i < dataLength; ++i)
457
xValue = parseFloat(xData[i]);
460
nextX = (((xValue - xMin) * xScaleFactor) + leftPadding + xOffset);
474
if(xData.hasOwnProperty(key))
476
xcoords[key] = this._getXCoords.apply(
478
[xData[key], xMin, dataWidth, xScaleFactor, xOffset, dataLength, leftPadding]
487
* Gets the y-coordinates for a series. Used by the setAreaData method.
488
* Returns an array when an array is received as the first argument.
489
* Returns an object literal when an object literal is received as the first argument.
491
* @method _getYCoords
492
* @param {Array|Object} yData An array of data values mapped to the y axis or an
493
* object literal containing key values pairs of data values mapped to the y axis.
494
* @param {Number} yMin The minimum value of the y axis.
495
* @param {Number} dataHeight The height used to calculate the y-coordinates.
496
* @param {Number} yScaleFactor The ratio used to calculate y-coordinates.
497
* @param {Number} yOffset The distance of the first and last y-coordinate from the beginning and end of the y-axis.
498
* @param {Number} dataLength The number of data points in the arrays.
499
* @param {Number} topPadding The top padding of the series.
500
* @return Array|Object
503
_getYCoords: function(yData, yMin, dataHeight, yScaleFactor, yOffset, dataLength, topPadding)
505
var isNumber = Y_Lang.isNumber,
511
if(Y_Lang.isArray(yData))
514
for (i = 0; i < dataLength; ++i)
516
yValue = parseFloat(yData[i]);
519
nextY = ((dataHeight + topPadding + yOffset) - (yValue - yMin) * yScaleFactor);
533
if(yData.hasOwnProperty(key))
535
ycoords[key] = this._getYCoords.apply(
537
[yData[key], yMin, dataHeight, yScaleFactor, yOffset, dataLength, topPadding]
546
* Finds the first valid index of an array coordinates.
548
* @method _getFirstValidIndex
549
* @param {Array} coords An array of x or y coordinates.
553
_getFirstValidIndex: function(coords)
557
limit = coords.length;
558
while(!Y_Lang.isNumber(coord) && i < limit)
567
* Finds the last valid index of an array coordinates.
569
* @method _getLastValidIndex
570
* @param {Array} coords An array of x or y coordinates.
574
_getLastValidIndex: function(coords)
579
while(!Y_Lang.isNumber(coord) && i > limit)
595
var w = this.get("width"),
596
h = this.get("height"),
599
if(this.get("rendered"))
601
if((isFinite(w) && isFinite(h) && w > 0 && h > 0) &&
602
((this.get("xData") && this.get("yData")) ||
603
this._updateAxisBase()))
607
this._callLater = true;
610
this._drawing = true;
611
this._callLater = false;
613
xcoords = this.get("xcoords");
614
ycoords = this.get("ycoords");
615
if(xcoords && ycoords && xcoords.length > 0)
619
this._drawing = false;
626
this._toggleVisible(this.get("visible"));
627
this.fire("drawingComplete");
634
* Default value for plane offsets when the parent chart's `interactiveType` is `planar`.
636
* @property _defaultPlaneOffset
640
_defaultPlaneOffset: 4,
643
* Destructor implementation for the CartesianSeries class.
644
* Calls destroy on all Graphic instances.
649
destructor: function()
651
if(this.get("rendered"))
653
if(this._xDataReadyHandle)
655
this._xDataReadyHandle.detach();
657
if(this._xDataUpdateHandle)
659
this._xDataUpdateHandle.detach();
661
if(this._yDataReadyHandle)
663
this._yDataReadyHandle.detach();
665
if(this._yDataUpdateHandle)
667
this._yDataUpdateHandle.detach();
669
this._xAxisChangeHandle.detach();
670
this._yAxisChangeHandle.detach();
674
* Event handle for the x-axis' dataReady event.
676
* @property _xDataReadyHandle
677
* @type {EventHandle}
682
* Event handle for the x-axis dataUpdate event.
684
* @property _xDataUpdateHandle
685
* @type {EventHandle}
690
* Event handle for the y-axis dataReady event.
692
* @property _yDataReadyHandle
693
* @type {EventHandle}
698
* Event handle for the y-axis dataUpdate event.
699
* @property _yDataUpdateHandle
700
* @type {EventHandle}
705
* Event handle for the xAxisChange event.
706
* @property _xAxisChangeHandle
707
* @type {EventHandle}
712
* Event handle for the yAxisChange event.
713
* @property _yAxisChangeHandle
714
* @type {EventHandle}
719
* Event handle for the stylesChange event.
720
* @property _stylesChangeHandle
721
* @type {EventHandle}
726
* Event handle for the widthChange event.
727
* @property _widthChangeHandle
728
* @type {EventHandle}
733
* Event handle for the heightChange event.
734
* @property _heightChangeHandle
735
* @type {EventHandle}
740
* Event handle for the visibleChange event.
741
* @property _visibleChangeHandle
742
* @type {EventHandle}
748
* An array of all series of the same type used within a chart application.
750
* @attribute seriesTypeCollection
753
seriesTypeCollection: {},
756
* Name used for for displaying data related to the x-coordinate.
758
* @attribute xDisplayName
764
return this._xDisplayName || this.get("xKey");
767
setter: function(val)
769
this._xDisplayName = val.toString();
775
* Name used for for displaying data related to the y-coordinate.
777
* @attribute yDisplayName
783
return this._yDisplayName || this.get("yKey");
786
setter: function(val)
788
this._yDisplayName = val.toString();
794
* Name used for for displaying category data
796
* @attribute categoryDisplayName
800
categoryDisplayName: {
805
return this.get("direction") === "vertical" ? this.get("yDisplayName") : this.get("xDisplayName");
808
setter: function(val)
810
if(this.get("direction") === "vertical")
812
this._yDisplayName = val;
816
this._xDisplayName = val;
823
* Name used for for displaying value data
825
* @attribute valueDisplayName
834
return this.get("direction") === "vertical" ? this.get("xDisplayName") : this.get("yDisplayName");
837
setter: function(val)
839
if(this.get("direction") === "vertical")
841
this._xDisplayName = val;
845
this._yDisplayName = val;
852
* Read-only attribute indicating the type of series.
863
* Order of this instance of this `type`.
871
* Order of the instance
873
* @attribute graphOrder
879
* x coordinates for the series.
887
* y coordinates for the series
895
* Reference to the `Axis` instance used for assigning
896
* x-values to the graph.
904
* Reference to the `Axis` instance used for assigning
905
* y-values to the graph.
913
* Indicates which array to from the hash of value arrays in
914
* the x-axis `Axis` instance.
920
setter: function(val)
922
if(Y_Lang.isArray(val))
928
return val.toString();
934
* Indicates which array to from the hash of value arrays in
935
* the y-axis `Axis` instance.
941
setter: function(val)
943
if(Y_Lang.isArray(val))
949
return val.toString();
955
* Array of x values for the series.
963
* Array of y values for the series.
971
* Collection of area maps along the xAxis. Used to determine mouseover for multiple
974
* @attribute xMarkerPlane
980
* Collection of area maps along the yAxis. Used to determine mouseover for multiple
983
* @attribute yMarkerPlane
989
* Distance from a data coordinate to the left/right for setting a hotspot.
991
* @attribute xMarkerPlaneOffset
994
xMarkerPlaneOffset: {
996
var marker = this.get("styles").marker;
997
if(marker && marker.width && isFinite(marker.width))
999
return marker.width * 0.5;
1001
return this._defaultPlaneOffset;
1006
* Distance from a data coordinate to the top/bottom for setting a hotspot.
1008
* @attribute yMarkerPlaneOffset
1011
yMarkerPlaneOffset: {
1012
getter: function() {
1013
var marker = this.get("styles").marker;
1014
if(marker && marker.height && isFinite(marker.height))
1016
return marker.height * 0.5;
1018
return this._defaultPlaneOffset;
1023
* Direction of the series
1025
* @attribute direction
1035
}, '3.10.3', {"requires": ["series-base"]});