Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / chart / series / Cartesian.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.chart.series.Cartesian
17  * @extends Ext.chart.series.Series
18  *
19  * Common base class for series implementations which plot values using x/y coordinates.
20  */
21 Ext.define('Ext.chart.series.Cartesian', {
22
23     /* Begin Definitions */
24
25     extend: 'Ext.chart.series.Series',
26
27     alternateClassName: ['Ext.chart.CartesianSeries', 'Ext.chart.CartesianChart'],
28
29     /* End Definitions */
30
31     /**
32      * The field used to access the x axis value from the items from the data
33      * source.
34      *
35      * @cfg xField
36      * @type String
37      */
38     xField: null,
39
40     /**
41      * The field used to access the y-axis value from the items from the data
42      * source.
43      *
44      * @cfg yField
45      * @type String
46      */
47     yField: null,
48
49     /**
50      * @cfg {String} axis
51      * The position of the axis to bind the values to. Possible values are 'left', 'bottom', 'top' and 'right'.
52      * You must explicitly set this value to bind the values of the line series to the ones in the axis, otherwise a
53      * relative scale will be used.
54      */
55     axis: 'left',
56
57     getLegendLabels: function() {
58         var me = this,
59             labels = [],
60             combinations = me.combinations;
61
62         Ext.each([].concat(me.yField), function(yField, i) {
63             var title = me.title;
64             // Use the 'title' config if present, otherwise use the raw yField name
65             labels.push((Ext.isArray(title) ? title[i] : title) || yField);
66         });
67
68         // Handle yFields combined via legend drag-drop
69         if (combinations) {
70             Ext.each(combinations, function(combo) {
71                 var label0 = labels[combo[0]],
72                     label1 = labels[combo[1]];
73                 labels[combo[1]] = label0 + ' & ' + label1;
74                 labels.splice(combo[0], 1);
75             });
76         }
77
78         return labels;
79     },
80
81     /**
82      * @protected Iterates over a given record's values for each of this series's yFields,
83      * executing a given function for each value. Any yFields that have been combined
84      * via legend drag-drop will be treated as a single value.
85      * @param {Ext.data.Model} record
86      * @param {Function} fn
87      * @param {Object} scope
88      */
89     eachYValue: function(record, fn, scope) {
90         Ext.each(this.getYValueAccessors(), function(accessor, i) {
91             fn.call(scope, accessor(record), i);
92         });
93     },
94
95     /**
96      * @protected Returns the number of yField values, taking into account fields combined
97      * via legend drag-drop.
98      * @return {Number}
99      */
100     getYValueCount: function() {
101         return this.getYValueAccessors().length;
102     },
103
104     combine: function(index1, index2) {
105         var me = this,
106             accessors = me.getYValueAccessors(),
107             accessor1 = accessors[index1],
108             accessor2 = accessors[index2];
109
110         // Combine the yValue accessors for the two indexes into a single accessor that returns their sum
111         accessors[index2] = function(record) {
112             return accessor1(record) + accessor2(record);
113         };
114         accessors.splice(index1, 1);
115
116         me.callParent([index1, index2]);
117     },
118
119     clearCombinations: function() {
120         // Clear combined accessors, they'll get regenerated on next call to getYValueAccessors
121         delete this.yValueAccessors;
122         this.callParent();
123     },
124
125     /**
126      * @protected Returns an array of functions, each of which returns the value of the yField
127      * corresponding to function's index in the array, for a given record (each function takes the
128      * record as its only argument.) If yFields have been combined by the user via legend drag-drop,
129      * this list of accessors will be kept in sync with those combinations.
130      * @return {Array} array of accessor functions
131      */
132     getYValueAccessors: function() {
133         var me = this,
134             accessors = me.yValueAccessors;
135         if (!accessors) {
136             accessors = me.yValueAccessors = [];
137             Ext.each([].concat(me.yField), function(yField) {
138                 accessors.push(function(record) {
139                     return record.get(yField);
140                 });
141             });
142         }
143         return accessors;
144     },
145
146     /**
147      * Calculate the min and max values for this series's xField.
148      * @return {Array} [min, max]
149      */
150     getMinMaxXValues: function() {
151         var me = this,
152             min, max,
153             xField = me.xField;
154
155         if (me.getRecordCount() > 0) {
156             min = Infinity;
157             max = -min;
158             me.eachRecord(function(record) {
159                 var xValue = record.get(xField);
160                 if (xValue > max) {
161                     max = xValue;
162                 }
163                 if (xValue < min) {
164                     min = xValue;
165                 }
166             });
167         } else {
168             min = max = 0;
169         }
170         return [min, max];
171     },
172
173     /**
174      * Calculate the min and max values for this series's yField(s). Takes into account yField
175      * combinations, exclusions, and stacking.
176      * @return {Array} [min, max]
177      */
178     getMinMaxYValues: function() {
179         var me = this,
180             stacked = me.stacked,
181             min, max,
182             positiveTotal, negativeTotal;
183
184         function eachYValueStacked(yValue, i) {
185             if (!me.isExcluded(i)) {
186                 if (yValue < 0) {
187                     negativeTotal += yValue;
188                 } else {
189                     positiveTotal += yValue;
190                 }
191             }
192         }
193
194         function eachYValue(yValue, i) {
195             if (!me.isExcluded(i)) {
196                 if (yValue > max) {
197                     max = yValue;
198                 }
199                 if (yValue < min) {
200                     min = yValue;
201                 }
202             }
203         }
204
205         if (me.getRecordCount() > 0) {
206             min = Infinity;
207             max = -min;
208             me.eachRecord(function(record) {
209                 if (stacked) {
210                     positiveTotal = 0;
211                     negativeTotal = 0;
212                     me.eachYValue(record, eachYValueStacked);
213                     if (positiveTotal > max) {
214                         max = positiveTotal;
215                     }
216                     if (negativeTotal < min) {
217                         min = negativeTotal;
218                     }
219                 } else {
220                     me.eachYValue(record, eachYValue);
221                 }
222             });
223         } else {
224             min = max = 0;
225         }
226         return [min, max];
227     },
228
229     getAxesForXAndYFields: function() {
230         var me = this,
231             axes = me.chart.axes,
232             axis = [].concat(me.axis),
233             xAxis, yAxis;
234
235         if (Ext.Array.indexOf(axis, 'top') > -1) {
236             xAxis = 'top';
237         } else if (Ext.Array.indexOf(axis, 'bottom') > -1) {
238             xAxis = 'bottom';
239         } else {
240             if (axes.get('top')) {
241                 xAxis = 'top';
242             } else if (axes.get('bottom')) {
243                 xAxis = 'bottom';
244             }
245         }
246
247         if (Ext.Array.indexOf(axis, 'left') > -1) {
248             yAxis = 'left';
249         } else if (Ext.Array.indexOf(axis, 'right') > -1) {
250             yAxis = 'right';
251         } else {
252             if (axes.get('left')) {
253                 yAxis = 'left';
254             } else if (axes.get('right')) {
255                 yAxis = 'right';
256             }
257         }
258
259         return {
260             xAxis: xAxis,
261             yAxis: yAxis
262         };
263     }
264
265
266 });
267