Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / src / widgets / chart / Chart.js
1 /*!
2  * Ext JS Library 3.3.1
3  * Copyright(c) 2006-2010 Sencha Inc.
4  * licensing@sencha.com
5  * http://www.sencha.com/license
6  */
7 /**
8  * @class Ext.chart.Chart
9  * @extends Ext.FlashComponent
10  * The Ext.chart package provides the capability to visualize data with flash based charting.
11  * Each chart binds directly to an Ext.data.Store enabling automatic updates of the chart.
12  * To change the look and feel of a chart, see the {@link #chartStyle} and {@link #extraStyle} config options.
13  * @constructor
14  * @xtype chart
15  */
16
17  Ext.chart.Chart = Ext.extend(Ext.FlashComponent, {
18     refreshBuffer: 100,
19
20     /**
21      * @cfg {String} backgroundColor
22      * @hide
23      */
24
25     /**
26      * @cfg {Object} chartStyle
27      * Sets styles for this chart. This contains default styling, so modifying this property will <b>override</b>
28      * the built in styles of the chart. Use {@link #extraStyle} to add customizations to the default styling.
29      */
30     chartStyle: {
31         padding: 10,
32         animationEnabled: true,
33         font: {
34             name: 'Tahoma',
35             color: 0x444444,
36             size: 11
37         },
38         dataTip: {
39             padding: 5,
40             border: {
41                 color: 0x99bbe8,
42                 size:1
43             },
44             background: {
45                 color: 0xDAE7F6,
46                 alpha: .9
47             },
48             font: {
49                 name: 'Tahoma',
50                 color: 0x15428B,
51                 size: 10,
52                 bold: true
53             }
54         }
55     },
56
57     /**
58      * @cfg {String} url
59      * The url to load the chart from. This defaults to Ext.chart.Chart.CHART_URL, which should
60      * be modified to point to the local charts resource.
61      */
62
63     /**
64      * @cfg {Object} extraStyle
65      * Contains extra styles that will be added or overwritten to the default chartStyle. Defaults to <tt>null</tt>.
66      * For a detailed list of the options available, visit the YUI Charts site
67      * at <a href="http://developer.yahoo.com/yui/charts/#basicstyles">http://developer.yahoo.com/yui/charts/#basicstyles</a><br/>
68      * Some of the options availabe:<br />
69      * <ul style="padding:5px;padding-left:16px;list-style-type:inherit;">
70      * <li><b>padding</b> - The space around the edge of the chart's contents. Padding does not increase the size of the chart.</li>
71      * <li><b>animationEnabled</b> - A Boolean value that specifies whether marker animations are enabled or not. Enabled by default.</li>
72      * <li><b>font</b> - An Object defining the font style to be used in the chart. Defaults to <tt>{ name: 'Tahoma', color: 0x444444, size: 11 }</tt><br/>
73      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
74      *      <li><b>name</b> - font name</li>
75      *      <li><b>color</b> - font color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>
76      *      <li><b>size</b> - font size in points (numeric portion only, ie: 11)</li>
77      *      <li><b>bold</b> - boolean</li>
78      *      <li><b>italic</b> - boolean</li>
79      *      <li><b>underline</b> - boolean</li>
80      *  </ul>
81      * </li>
82      * <li><b>border</b> - An object defining the border style around the chart. The chart itself will decrease in dimensions to accomodate the border.<br/>
83      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
84      *      <li><b>color</b> - border color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>
85      *      <li><b>size</b> - border size in pixels (numeric portion only, ie: 1)</li>
86      *  </ul>
87      * </li>
88      * <li><b>background</b> - An object defining the background style of the chart.<br/>
89      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
90      *      <li><b>color</b> - border color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>
91      *      <li><b>image</b> - an image URL. May be relative to the current document or absolute.</li>
92      *  </ul>
93      * </li>
94      * <li><b>legend</b> - An object defining the legend style<br/>
95      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
96      *      <li><b>display</b> - location of the legend. Possible values are "none", "left", "right", "top", and "bottom".</li>
97      *      <li><b>spacing</b> - an image URL. May be relative to the current document or absolute.</li>
98      *      <li><b>padding, border, background, font</b> - same options as described above.</li>
99      *  </ul></li>
100      * <li><b>dataTip</b> - An object defining the style of the data tip (tooltip).<br/>
101      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
102      *      <li><b>padding, border, background, font</b> - same options as described above.</li>
103      *  </ul></li>
104      * <li><b>xAxis and yAxis</b> - An object defining the style of the style of either axis.<br/>
105      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
106      *      <li><b>color</b> - same option as described above.</li>
107      *      <li><b>size</b> - same option as described above.</li>
108      *      <li><b>showLabels</b> - boolean</li>
109      *      <li><b>labelRotation</b> - a value in degrees from -90 through 90. Default is zero.</li>
110      *  </ul></li>
111      * <li><b>majorGridLines and minorGridLines</b> - An object defining the style of the style of the grid lines.<br/>
112      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
113      *      <li><b>color, size</b> - same options as described above.</li>
114      *  </ul></li></li>
115      * <li><b>zeroGridLine</b> - An object defining the style of the style of the zero grid line.<br/>
116      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
117      *      <li><b>color, size</b> - same options as described above.</li>
118      *  </ul></li></li>
119      * <li><b>majorTicks and minorTicks</b> - An object defining the style of the style of ticks in the chart.<br/>
120      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
121      *      <li><b>color, size</b> - same options as described above.</li>
122      *      <li><b>length</b> - the length of each tick in pixels extending from the axis.</li>
123      *      <li><b>display</b> - how the ticks are drawn. Possible values are "none", "inside", "outside", and "cross".</li>
124      *  </ul></li></li>
125      * </ul>
126      */
127     extraStyle: null,
128
129     /**
130      * @cfg {Object} seriesStyles
131      * Contains styles to apply to the series after a refresh. Defaults to <tt>null</tt>.
132      */
133     seriesStyles: null,
134
135     /**
136      * @cfg {Boolean} disableCaching
137      * True to add a "cache buster" to the end of the chart url. Defaults to true for Opera and IE.
138      */
139     disableCaching: Ext.isIE || Ext.isOpera,
140     disableCacheParam: '_dc',
141
142     initComponent : function(){
143         Ext.chart.Chart.superclass.initComponent.call(this);
144         if(!this.url){
145             this.url = Ext.chart.Chart.CHART_URL;
146         }
147         if(this.disableCaching){
148             this.url = Ext.urlAppend(this.url, String.format('{0}={1}', this.disableCacheParam, new Date().getTime()));
149         }
150         this.addEvents(
151             'itemmouseover',
152             'itemmouseout',
153             'itemclick',
154             'itemdoubleclick',
155             'itemdragstart',
156             'itemdrag',
157             'itemdragend',
158             /**
159              * @event beforerefresh
160              * Fires before a refresh to the chart data is called.  If the beforerefresh handler returns
161              * <tt>false</tt> the {@link #refresh} action will be cancelled.
162              * @param {Chart} this
163              */
164             'beforerefresh',
165             /**
166              * @event refresh
167              * Fires after the chart data has been refreshed.
168              * @param {Chart} this
169              */
170             'refresh'
171         );
172         this.store = Ext.StoreMgr.lookup(this.store);
173     },
174
175     /**
176      * Sets a single style value on the Chart instance.
177      *
178      * @param name {String} Name of the Chart style value to change.
179      * @param value {Object} New value to pass to the Chart style.
180      */
181      setStyle: function(name, value){
182          this.swf.setStyle(name, Ext.encode(value));
183      },
184
185     /**
186      * Resets all styles on the Chart instance.
187      *
188      * @param styles {Object} Initializer for all Chart styles.
189      */
190     setStyles: function(styles){
191         this.swf.setStyles(Ext.encode(styles));
192     },
193
194     /**
195      * Sets the styles on all series in the Chart.
196      *
197      * @param styles {Array} Initializer for all Chart series styles.
198      */
199     setSeriesStyles: function(styles){
200         this.seriesStyles = styles;
201         var s = [];
202         Ext.each(styles, function(style){
203             s.push(Ext.encode(style));
204         });
205         this.swf.setSeriesStyles(s);
206     },
207
208     setCategoryNames : function(names){
209         this.swf.setCategoryNames(names);
210     },
211
212     setLegendRenderer : function(fn, scope){
213         var chart = this;
214         scope = scope || chart;
215         chart.removeFnProxy(chart.legendFnName);
216         chart.legendFnName = chart.createFnProxy(function(name){
217             return fn.call(scope, name);
218         });
219         chart.swf.setLegendLabelFunction(chart.legendFnName);
220     },
221
222     setTipRenderer : function(fn, scope){
223         var chart = this;
224         scope = scope || chart;
225         chart.removeFnProxy(chart.tipFnName);
226         chart.tipFnName = chart.createFnProxy(function(item, index, series){
227             var record = chart.store.getAt(index);
228             return fn.call(scope, chart, record, index, series);
229         });
230         chart.swf.setDataTipFunction(chart.tipFnName);
231     },
232
233     setSeries : function(series){
234         this.series = series;
235         this.refresh();
236     },
237
238     /**
239      * Changes the data store bound to this chart and refreshes it.
240      * @param {Store} store The store to bind to this chart
241      */
242     bindStore : function(store, initial){
243         if(!initial && this.store){
244             if(store !== this.store && this.store.autoDestroy){
245                 this.store.destroy();
246             }else{
247                 this.store.un("datachanged", this.refresh, this);
248                 this.store.un("add", this.delayRefresh, this);
249                 this.store.un("remove", this.delayRefresh, this);
250                 this.store.un("update", this.delayRefresh, this);
251                 this.store.un("clear", this.refresh, this);
252             }
253         }
254         if(store){
255             store = Ext.StoreMgr.lookup(store);
256             store.on({
257                 scope: this,
258                 datachanged: this.refresh,
259                 add: this.delayRefresh,
260                 remove: this.delayRefresh,
261                 update: this.delayRefresh,
262                 clear: this.refresh
263             });
264         }
265         this.store = store;
266         if(store && !initial){
267             this.refresh();
268         }
269     },
270
271     onSwfReady : function(isReset){
272         Ext.chart.Chart.superclass.onSwfReady.call(this, isReset);
273         var ref;
274         this.swf.setType(this.type);
275
276         if(this.chartStyle){
277             this.setStyles(Ext.apply({}, this.extraStyle, this.chartStyle));
278         }
279
280         if(this.categoryNames){
281             this.setCategoryNames(this.categoryNames);
282         }
283
284         if(this.tipRenderer){
285             ref = this.getFunctionRef(this.tipRenderer);
286             this.setTipRenderer(ref.fn, ref.scope);
287         }
288         if(this.legendRenderer){
289             ref = this.getFunctionRef(this.legendRenderer);
290             this.setLegendRenderer(ref.fn, ref.scope);
291         }
292         if(!isReset){
293             this.bindStore(this.store, true);
294         }
295         this.refresh.defer(10, this);
296     },
297
298     delayRefresh : function(){
299         if(!this.refreshTask){
300             this.refreshTask = new Ext.util.DelayedTask(this.refresh, this);
301         }
302         this.refreshTask.delay(this.refreshBuffer);
303     },
304
305     refresh : function(){
306         if(this.fireEvent('beforerefresh', this) !== false){
307             var styleChanged = false;
308             // convert the store data into something YUI charts can understand
309             var data = [], rs = this.store.data.items;
310             for(var j = 0, len = rs.length; j < len; j++){
311                 data[j] = rs[j].data;
312             }
313             //make a copy of the series definitions so that we aren't
314             //editing them directly.
315             var dataProvider = [];
316             var seriesCount = 0;
317             var currentSeries = null;
318             var i = 0;
319             if(this.series){
320                 seriesCount = this.series.length;
321                 for(i = 0; i < seriesCount; i++){
322                     currentSeries = this.series[i];
323                     var clonedSeries = {};
324                     for(var prop in currentSeries){
325                         if(prop == "style" && currentSeries.style !== null){
326                             clonedSeries.style = Ext.encode(currentSeries.style);
327                             styleChanged = true;
328                             //we don't want to modify the styles again next time
329                             //so null out the style property.
330                             // this causes issues
331                             // currentSeries.style = null;
332                         } else{
333                             clonedSeries[prop] = currentSeries[prop];
334                         }
335                     }
336                     dataProvider.push(clonedSeries);
337                 }
338             }
339
340             if(seriesCount > 0){
341                 for(i = 0; i < seriesCount; i++){
342                     currentSeries = dataProvider[i];
343                     if(!currentSeries.type){
344                         currentSeries.type = this.type;
345                     }
346                     currentSeries.dataProvider = data;
347                 }
348             } else{
349                 dataProvider.push({type: this.type, dataProvider: data});
350             }
351             this.swf.setDataProvider(dataProvider);
352             if(this.seriesStyles){
353                 this.setSeriesStyles(this.seriesStyles);
354             }
355             this.fireEvent('refresh', this);
356         }
357     },
358
359     // private
360     createFnProxy : function(fn){
361         var fnName = 'extFnProxy' + (++Ext.chart.Chart.PROXY_FN_ID);
362         Ext.chart.Chart.proxyFunction[fnName] = fn;
363         return 'Ext.chart.Chart.proxyFunction.' + fnName;
364     },
365
366     // private
367     removeFnProxy : function(fn){
368         if(!Ext.isEmpty(fn)){
369             fn = fn.replace('Ext.chart.Chart.proxyFunction.', '');
370             delete Ext.chart.Chart.proxyFunction[fn];
371         }
372     },
373
374     // private
375     getFunctionRef : function(val){
376         if(Ext.isFunction(val)){
377             return {
378                 fn: val,
379                 scope: this
380             };
381         }else{
382             return {
383                 fn: val.fn,
384                 scope: val.scope || this
385             };
386         }
387     },
388
389     // private
390     onDestroy: function(){
391         if (this.refreshTask && this.refreshTask.cancel){
392             this.refreshTask.cancel();
393         }
394         Ext.chart.Chart.superclass.onDestroy.call(this);
395         this.bindStore(null);
396         this.removeFnProxy(this.tipFnName);
397         this.removeFnProxy(this.legendFnName);
398     }
399 });
400 Ext.reg('chart', Ext.chart.Chart);
401 Ext.chart.Chart.PROXY_FN_ID = 0;
402 Ext.chart.Chart.proxyFunction = {};
403
404 /**
405  * Sets the url to load the chart from. This should be set to a local resource.
406  * @static
407  * @type String
408  */
409 Ext.chart.Chart.CHART_URL = 'http:/' + '/yui.yahooapis.com/2.8.2/build/charts/assets/charts.swf';
410
411 /**
412  * @class Ext.chart.PieChart
413  * @extends Ext.chart.Chart
414  * @constructor
415  * @xtype piechart
416  */
417 Ext.chart.PieChart = Ext.extend(Ext.chart.Chart, {
418     type: 'pie',
419
420     onSwfReady : function(isReset){
421         Ext.chart.PieChart.superclass.onSwfReady.call(this, isReset);
422
423         this.setDataField(this.dataField);
424         this.setCategoryField(this.categoryField);
425     },
426
427     setDataField : function(field){
428         this.dataField = field;
429         this.swf.setDataField(field);
430     },
431
432     setCategoryField : function(field){
433         this.categoryField = field;
434         this.swf.setCategoryField(field);
435     }
436 });
437 Ext.reg('piechart', Ext.chart.PieChart);
438
439 /**
440  * @class Ext.chart.CartesianChart
441  * @extends Ext.chart.Chart
442  * @constructor
443  * @xtype cartesianchart
444  */
445 Ext.chart.CartesianChart = Ext.extend(Ext.chart.Chart, {
446     onSwfReady : function(isReset){
447         Ext.chart.CartesianChart.superclass.onSwfReady.call(this, isReset);
448         this.labelFn = [];
449         if(this.xField){
450             this.setXField(this.xField);
451         }
452         if(this.yField){
453             this.setYField(this.yField);
454         }
455         if(this.xAxis){
456             this.setXAxis(this.xAxis);
457         }
458         if(this.xAxes){
459             this.setXAxes(this.xAxes);
460         }
461         if(this.yAxis){
462             this.setYAxis(this.yAxis);
463         }
464         if(this.yAxes){
465             this.setYAxes(this.yAxes);
466         }
467         if(Ext.isDefined(this.constrainViewport)){
468             this.swf.setConstrainViewport(this.constrainViewport);
469         }
470     },
471
472     setXField : function(value){
473         this.xField = value;
474         this.swf.setHorizontalField(value);
475     },
476
477     setYField : function(value){
478         this.yField = value;
479         this.swf.setVerticalField(value);
480     },
481
482     setXAxis : function(value){
483         this.xAxis = this.createAxis('xAxis', value);
484         this.swf.setHorizontalAxis(this.xAxis);
485     },
486
487     setXAxes : function(value){
488         var axis;
489         for(var i = 0; i < value.length; i++) {
490             axis = this.createAxis('xAxis' + i, value[i]);
491             this.swf.setHorizontalAxis(axis);
492         }
493     },
494
495     setYAxis : function(value){
496         this.yAxis = this.createAxis('yAxis', value);
497         this.swf.setVerticalAxis(this.yAxis);
498     },
499
500     setYAxes : function(value){
501         var axis;
502         for(var i = 0; i < value.length; i++) {
503             axis = this.createAxis('yAxis' + i, value[i]);
504             this.swf.setVerticalAxis(axis);
505         }
506     },
507
508     createAxis : function(axis, value){
509         var o = Ext.apply({}, value),
510             ref,
511             old;
512
513         if(this[axis]){
514             old = this[axis].labelFunction;
515             this.removeFnProxy(old);
516             this.labelFn.remove(old);
517         }
518         if(o.labelRenderer){
519             ref = this.getFunctionRef(o.labelRenderer);
520             o.labelFunction = this.createFnProxy(function(v){
521                 return ref.fn.call(ref.scope, v);
522             });
523             delete o.labelRenderer;
524             this.labelFn.push(o.labelFunction);
525         }
526         if(axis.indexOf('xAxis') > -1 && o.position == 'left'){
527             o.position = 'bottom';
528         }
529         return o;
530     },
531
532     onDestroy : function(){
533         Ext.chart.CartesianChart.superclass.onDestroy.call(this);
534         Ext.each(this.labelFn, function(fn){
535             this.removeFnProxy(fn);
536         }, this);
537     }
538 });
539 Ext.reg('cartesianchart', Ext.chart.CartesianChart);
540
541 /**
542  * @class Ext.chart.LineChart
543  * @extends Ext.chart.CartesianChart
544  * @constructor
545  * @xtype linechart
546  */
547 Ext.chart.LineChart = Ext.extend(Ext.chart.CartesianChart, {
548     type: 'line'
549 });
550 Ext.reg('linechart', Ext.chart.LineChart);
551
552 /**
553  * @class Ext.chart.ColumnChart
554  * @extends Ext.chart.CartesianChart
555  * @constructor
556  * @xtype columnchart
557  */
558 Ext.chart.ColumnChart = Ext.extend(Ext.chart.CartesianChart, {
559     type: 'column'
560 });
561 Ext.reg('columnchart', Ext.chart.ColumnChart);
562
563 /**
564  * @class Ext.chart.StackedColumnChart
565  * @extends Ext.chart.CartesianChart
566  * @constructor
567  * @xtype stackedcolumnchart
568  */
569 Ext.chart.StackedColumnChart = Ext.extend(Ext.chart.CartesianChart, {
570     type: 'stackcolumn'
571 });
572 Ext.reg('stackedcolumnchart', Ext.chart.StackedColumnChart);
573
574 /**
575  * @class Ext.chart.BarChart
576  * @extends Ext.chart.CartesianChart
577  * @constructor
578  * @xtype barchart
579  */
580 Ext.chart.BarChart = Ext.extend(Ext.chart.CartesianChart, {
581     type: 'bar'
582 });
583 Ext.reg('barchart', Ext.chart.BarChart);
584
585 /**
586  * @class Ext.chart.StackedBarChart
587  * @extends Ext.chart.CartesianChart
588  * @constructor
589  * @xtype stackedbarchart
590  */
591 Ext.chart.StackedBarChart = Ext.extend(Ext.chart.CartesianChart, {
592     type: 'stackbar'
593 });
594 Ext.reg('stackedbarchart', Ext.chart.StackedBarChart);
595
596
597
598 /**
599  * @class Ext.chart.Axis
600  * Defines a CartesianChart's vertical or horizontal axis.
601  * @constructor
602  */
603 Ext.chart.Axis = function(config){
604     Ext.apply(this, config);
605 };
606
607 Ext.chart.Axis.prototype =
608 {
609     /**
610      * The type of axis.
611      *
612      * @property type
613      * @type String
614      */
615     type: null,
616
617     /**
618      * The direction in which the axis is drawn. May be "horizontal" or "vertical".
619      *
620      * @property orientation
621      * @type String
622      */
623     orientation: "horizontal",
624
625     /**
626      * If true, the items on the axis will be drawn in opposite direction.
627      *
628      * @property reverse
629      * @type Boolean
630      */
631     reverse: false,
632
633     /**
634      * A string reference to the globally-accessible function that may be called to
635      * determine each of the label values for this axis.
636      *
637      * @property labelFunction
638      * @type String
639      */
640     labelFunction: null,
641
642     /**
643      * If true, labels that overlap previously drawn labels on the axis will be hidden.
644      *
645      * @property hideOverlappingLabels
646      * @type Boolean
647      */
648     hideOverlappingLabels: true,
649
650     /**
651      * The space, in pixels, between labels on an axis.
652      *
653      * @property labelSpacing
654      * @type Number
655      */
656     labelSpacing: 2
657 };
658
659 /**
660  * @class Ext.chart.NumericAxis
661  * @extends Ext.chart.Axis
662  * A type of axis whose units are measured in numeric values.
663  * @constructor
664  */
665 Ext.chart.NumericAxis = Ext.extend(Ext.chart.Axis, {
666     type: "numeric",
667
668     /**
669      * The minimum value drawn by the axis. If not set explicitly, the axis
670      * minimum will be calculated automatically.
671      *
672      * @property minimum
673      * @type Number
674      */
675     minimum: NaN,
676
677     /**
678      * The maximum value drawn by the axis. If not set explicitly, the axis
679      * maximum will be calculated automatically.
680      *
681      * @property maximum
682      * @type Number
683      */
684     maximum: NaN,
685
686     /**
687      * The spacing between major intervals on this axis.
688      *
689      * @property majorUnit
690      * @type Number
691      */
692     majorUnit: NaN,
693
694     /**
695      * The spacing between minor intervals on this axis.
696      *
697      * @property minorUnit
698      * @type Number
699      */
700     minorUnit: NaN,
701
702     /**
703      * If true, the labels, ticks, gridlines, and other objects will snap to the
704      * nearest major or minor unit. If false, their position will be based on
705      * the minimum value.
706      *
707      * @property snapToUnits
708      * @type Boolean
709      */
710     snapToUnits: true,
711
712     /**
713      * If true, and the bounds are calculated automatically, either the minimum
714      * or maximum will be set to zero.
715      *
716      * @property alwaysShowZero
717      * @type Boolean
718      */
719     alwaysShowZero: true,
720
721     /**
722      * The scaling algorithm to use on this axis. May be "linear" or
723      * "logarithmic".
724      *
725      * @property scale
726      * @type String
727      */
728     scale: "linear",
729
730     /**
731      * Indicates whether to round the major unit.
732      *
733      * @property roundMajorUnit
734      * @type Boolean
735      */
736     roundMajorUnit: true,
737
738     /**
739      * Indicates whether to factor in the size of the labels when calculating a
740      * major unit.
741      *
742      * @property calculateByLabelSize
743      * @type Boolean
744      */
745     calculateByLabelSize: true,
746
747     /**
748      * Indicates the position of the axis relative to the chart
749      *
750      * @property position
751      * @type String
752      */
753     position: 'left',
754
755     /**
756      * Indicates whether to extend maximum beyond data's maximum to the nearest
757      * majorUnit.
758      *
759      * @property adjustMaximumByMajorUnit
760      * @type Boolean
761      */
762     adjustMaximumByMajorUnit: true,
763
764     /**
765      * Indicates whether to extend the minimum beyond data's minimum to the
766      * nearest majorUnit.
767      *
768      * @property adjustMinimumByMajorUnit
769      * @type Boolean
770      */
771     adjustMinimumByMajorUnit: true
772
773 });
774
775 /**
776  * @class Ext.chart.TimeAxis
777  * @extends Ext.chart.Axis
778  * A type of axis whose units are measured in time-based values.
779  * @constructor
780  */
781 Ext.chart.TimeAxis = Ext.extend(Ext.chart.Axis, {
782     type: "time",
783
784     /**
785      * The minimum value drawn by the axis. If not set explicitly, the axis
786      * minimum will be calculated automatically.
787      *
788      * @property minimum
789      * @type Date
790      */
791     minimum: null,
792
793     /**
794      * The maximum value drawn by the axis. If not set explicitly, the axis
795      * maximum will be calculated automatically.
796      *
797      * @property maximum
798      * @type Number
799      */
800     maximum: null,
801
802     /**
803      * The spacing between major intervals on this axis.
804      *
805      * @property majorUnit
806      * @type Number
807      */
808     majorUnit: NaN,
809
810     /**
811      * The time unit used by the majorUnit.
812      *
813      * @property majorTimeUnit
814      * @type String
815      */
816     majorTimeUnit: null,
817
818     /**
819      * The spacing between minor intervals on this axis.
820      *
821      * @property majorUnit
822      * @type Number
823      */
824     minorUnit: NaN,
825
826     /**
827      * The time unit used by the minorUnit.
828      *
829      * @property majorTimeUnit
830      * @type String
831      */
832     minorTimeUnit: null,
833
834     /**
835      * If true, the labels, ticks, gridlines, and other objects will snap to the
836      * nearest major or minor unit. If false, their position will be based on
837      * the minimum value.
838      *
839      * @property snapToUnits
840      * @type Boolean
841      */
842     snapToUnits: true,
843
844     /**
845      * Series that are stackable will only stack when this value is set to true.
846      *
847      * @property stackingEnabled
848      * @type Boolean
849      */
850     stackingEnabled: false,
851
852     /**
853      * Indicates whether to factor in the size of the labels when calculating a
854      * major unit.
855      *
856      * @property calculateByLabelSize
857      * @type Boolean
858      */
859     calculateByLabelSize: true
860
861 });
862
863 /**
864  * @class Ext.chart.CategoryAxis
865  * @extends Ext.chart.Axis
866  * A type of axis that displays items in categories.
867  * @constructor
868  */
869 Ext.chart.CategoryAxis = Ext.extend(Ext.chart.Axis, {
870     type: "category",
871
872     /**
873      * A list of category names to display along this axis.
874      *
875      * @property categoryNames
876      * @type Array
877      */
878     categoryNames: null,
879
880     /**
881      * Indicates whether or not to calculate the number of categories (ticks and
882      * labels) when there is not enough room to display all labels on the axis.
883      * If set to true, the axis will determine the number of categories to plot.
884      * If not, all categories will be plotted.
885      *
886      * @property calculateCategoryCount
887      * @type Boolean
888      */
889     calculateCategoryCount: false
890
891 });
892
893 /**
894  * @class Ext.chart.Series
895  * Series class for the charts widget.
896  * @constructor
897  */
898 Ext.chart.Series = function(config) { Ext.apply(this, config); };
899
900 Ext.chart.Series.prototype =
901 {
902     /**
903      * The type of series.
904      *
905      * @property type
906      * @type String
907      */
908     type: null,
909
910     /**
911      * The human-readable name of the series.
912      *
913      * @property displayName
914      * @type String
915      */
916     displayName: null
917 };
918
919 /**
920  * @class Ext.chart.CartesianSeries
921  * @extends Ext.chart.Series
922  * CartesianSeries class for the charts widget.
923  * @constructor
924  */
925 Ext.chart.CartesianSeries = Ext.extend(Ext.chart.Series, {
926     /**
927      * The field used to access the x-axis value from the items from the data
928      * source.
929      *
930      * @property xField
931      * @type String
932      */
933     xField: null,
934
935     /**
936      * The field used to access the y-axis value from the items from the data
937      * source.
938      *
939      * @property yField
940      * @type String
941      */
942     yField: null,
943
944     /**
945      * False to not show this series in the legend. Defaults to <tt>true</tt>.
946      *
947      * @property showInLegend
948      * @type Boolean
949      */
950     showInLegend: true,
951
952     /**
953      * Indicates which axis the series will bind to
954      *
955      * @property axis
956      * @type String
957      */
958     axis: 'primary'
959 });
960
961 /**
962  * @class Ext.chart.ColumnSeries
963  * @extends Ext.chart.CartesianSeries
964  * ColumnSeries class for the charts widget.
965  * @constructor
966  */
967 Ext.chart.ColumnSeries = Ext.extend(Ext.chart.CartesianSeries, {
968     type: "column"
969 });
970
971 /**
972  * @class Ext.chart.LineSeries
973  * @extends Ext.chart.CartesianSeries
974  * LineSeries class for the charts widget.
975  * @constructor
976  */
977 Ext.chart.LineSeries = Ext.extend(Ext.chart.CartesianSeries, {
978     type: "line"
979 });
980
981 /**
982  * @class Ext.chart.BarSeries
983  * @extends Ext.chart.CartesianSeries
984  * BarSeries class for the charts widget.
985  * @constructor
986  */
987 Ext.chart.BarSeries = Ext.extend(Ext.chart.CartesianSeries, {
988     type: "bar"
989 });
990
991
992 /**
993  * @class Ext.chart.PieSeries
994  * @extends Ext.chart.Series
995  * PieSeries class for the charts widget.
996  * @constructor
997  */
998 Ext.chart.PieSeries = Ext.extend(Ext.chart.Series, {
999     type: "pie",
1000     dataField: null,
1001     categoryField: null
1002 });