Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / Time3.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-chart-axis-Time-method-constructor'><span id='Ext-chart-axis-Time'>/**
19 </span></span> * @class Ext.chart.axis.Time
20  * @extends Ext.chart.axis.Axis
21  *
22  * A type of axis whose units are measured in time values. Use this axis
23  * for listing dates that you will want to group or dynamically change.
24  * If you just want to display dates as categories then use the
25  * Category class for axis instead.
26  *
27  * For example:
28  *
29  *     axes: [{
30  *         type: 'Time',
31  *         position: 'bottom',
32  *         fields: 'date',
33  *         title: 'Day',
34  *         dateFormat: 'M d',
35  *         groupBy: 'year,month,day',
36  *         aggregateOp: 'sum',
37  *     
38  *         constrain: true,
39  *         fromDate: new Date('1/1/11'),
40  *         toDate: new Date('1/7/11')
41  *     }]
42  *
43  * In this example we're creating a time axis that has as title *Day*.
44  * The field the axis is bound to is `date`.
45  * The date format to use to display the text for the axis labels is `M d`
46  * which is a three letter month abbreviation followed by the day number.
47  * The time axis will show values for dates between `fromDate` and `toDate`.
48  * Since `constrain` is set to true all other values for other dates not between
49  * the fromDate and toDate will not be displayed.
50  * 
51  * @constructor
52  */
53 Ext.define('Ext.chart.axis.Time', {
54
55     /* Begin Definitions */
56
57     extend: 'Ext.chart.axis.Category',
58
59     alternateClassName: 'Ext.chart.TimeAxis',
60
61     alias: 'axis.time',
62
63     requires: ['Ext.data.Store', 'Ext.data.JsonStore'],
64
65     /* End Definitions */
66
67 <span id='Ext-chart-axis-Time-property-calculateByLabelSize'>     /**
68 </span>      * The minimum value drawn by the axis. If not set explicitly, the axis
69       * minimum will be calculated automatically.
70       * @property calculateByLabelSize
71       * @type Boolean
72       */
73     calculateByLabelSize: true,
74     
75 <span id='Ext-chart-axis-Time-property-dateFormat'>     /**
76 </span>     * Indicates the format the date will be rendered on. 
77      * For example: 'M d' will render the dates as 'Jan 30', etc.
78       *
79      * @property dateFormat
80      * @type {String|Boolean}
81       */
82     dateFormat: false,
83     
84 <span id='Ext-chart-axis-Time-property-timeUnit'>     /**
85 </span>     * Indicates the time unit to use for each step. Can be 'day', 'month', 'year' or a comma-separated combination of all of them.
86      * Default's 'year,month,day'.
87      *
88      * @property timeUnit
89      * @type {String}
90      */
91     groupBy: 'year,month,day',
92     
93 <span id='Ext-chart-axis-Time-property-aggregateOp'>    /**
94 </span>     * Aggregation operation when grouping. Possible options are 'sum', 'avg', 'max', 'min'. Default's 'sum'.
95      * 
96      * @property aggregateOp
97      * @type {String}
98       */
99     aggregateOp: 'sum',
100     
101 <span id='Ext-chart-axis-Time-property-fromDate'>    /**
102 </span>     * The starting date for the time axis.
103      * @property fromDate
104      * @type Date
105      */
106     fromDate: false,
107     
108 <span id='Ext-chart-axis-Time-property-toDate'>    /**
109 </span>     * The ending date for the time axis.
110      * @property toDate
111      * @type Date
112      */
113     toDate: false,
114     
115 <span id='Ext-chart-axis-Time-property-step'>    /**
116 </span>     * An array with two components: The first is the unit of the step (day, month, year, etc). The second one is the number of units for the step (1, 2, etc.).
117      * Default's [Ext.Date.DAY, 1].
118      * 
119      * @property step 
120      * @type Array
121      */
122     step: [Ext.Date.DAY, 1],
123     
124 <span id='Ext-chart-axis-Time-property-constrain'>    /**
125 </span>     * If true, the values of the chart will be rendered only if they belong between the fromDate and toDate. 
126      * If false, the time axis will adapt to the new values by adding/removing steps.
127      * Default's [Ext.Date.DAY, 1].
128      * 
129      * @property constrain 
130      * @type Boolean
131      */
132     constrain: false,
133     
134     // @private a wrapper for date methods.
135     dateMethods: {
136         'year': function(date) {
137             return date.getFullYear();
138         },
139         'month': function(date) {
140             return date.getMonth() + 1;
141         },
142         'day': function(date) {
143             return date.getDate();
144         },
145         'hour': function(date) {
146             return date.getHours();
147         },
148         'minute': function(date) {
149             return date.getMinutes();
150         },
151         'second': function(date) {
152             return date.getSeconds();
153         },
154         'millisecond': function(date) {
155             return date.getMilliseconds();
156         }
157     },
158     
159     // @private holds aggregate functions.
160     aggregateFn: (function() {
161         var etype = (function() {
162             var rgxp = /^\[object\s(.*)\]$/,
163                 toString = Object.prototype.toString;
164             return function(e) {
165                 return toString.call(e).match(rgxp)[1];
166             };
167         })();
168         return {
169             'sum': function(list) {
170                 var i = 0, l = list.length, acum = 0;
171                 if (!list.length || etype(list[0]) != 'Number') {
172                     return list[0];
173                 }
174                 for (; i &lt; l; i++) {
175                     acum += list[i];
176                 }
177                 return acum;
178             },
179             'max': function(list) {
180                 if (!list.length || etype(list[0]) != 'Number') {
181                     return list[0];
182                 }
183                 return Math.max.apply(Math, list);
184             },
185             'min': function(list) {
186                 if (!list.length || etype(list[0]) != 'Number') {
187                     return list[0];
188                 }
189                 return Math.min.apply(Math, list);
190             },
191             'avg': function(list) {
192                 var i = 0, l = list.length, acum = 0;
193                 if (!list.length || etype(list[0]) != 'Number') {
194                     return list[0];
195                 }
196                 for (; i &lt; l; i++) {
197                     acum += list[i];
198                 }
199                 return acum / l;
200             }
201         };
202     })(),
203     
204     // @private normalized the store to fill date gaps in the time interval.
205     constrainDates: function() {
206         var fromDate = Ext.Date.clone(this.fromDate),
207             toDate = Ext.Date.clone(this.toDate),
208             step = this.step,
209             field = this.fields,
210             store = this.chart.store,
211             record, recObj, fieldNames = [],
212             newStore = Ext.create('Ext.data.Store', {
213                 model: store.model
214             });
215         
216         var getRecordByDate = (function() {
217             var index = 0, l = store.getCount();
218             return function(date) {
219                 var rec, recDate;
220                 for (; index &lt; l; index++) {
221                     rec = store.getAt(index);
222                     recDate = rec.get(field);
223                     if (+recDate &gt; +date) {
224                         return false;
225                     } else if (+recDate == +date) {
226                         return rec;
227                     }
228                 }
229                 return false;
230             };
231         })();
232         
233         if (!this.constrain) {
234             this.chart.filteredStore = this.chart.store;
235             return;
236         }
237
238         while(+fromDate &lt;= +toDate) {
239             record = getRecordByDate(fromDate);
240             recObj = {};
241             if (record) {
242                 newStore.add(record.data);
243             } else {
244                 newStore.model.prototype.fields.each(function(f) {
245                     recObj[f.name] = false;
246                 });
247                 recObj.date = fromDate;
248                 newStore.add(recObj);
249             }
250             fromDate = Ext.Date.add(fromDate, step[0], step[1]);
251         }
252          
253         this.chart.filteredStore = newStore;
254     },
255     
256     // @private aggregates values if multiple store elements belong to the same time step.
257     aggregate: function() {
258         var aggStore = {}, 
259             aggKeys = [], key, value,
260             op = this.aggregateOp,
261             field = this.fields, i,
262             fields = this.groupBy.split(','),
263             curField,
264             recFields = [],
265             recFieldsLen = 0,
266             obj,
267             dates = [],
268             json = [],
269             l = fields.length,
270             dateMethods = this.dateMethods,
271             aggregateFn = this.aggregateFn,
272             store = this.chart.filteredStore || this.chart.store;
273         
274         store.each(function(rec) {
275             //get all record field names in a simple array
276             if (!recFields.length) {
277                 rec.fields.each(function(f) {
278                     recFields.push(f.name);
279                 });
280                 recFieldsLen = recFields.length;
281             }
282             //get record date value
283             value = rec.get(field);
284             //generate key for grouping records
285             for (i = 0; i &lt; l; i++) {
286                 if (i == 0) {
287                     key = String(dateMethods[fields[i]](value));
288                 } else {
289                     key += '||' + dateMethods[fields[i]](value);
290                 }
291             }
292             //get aggregation record from hash
293             if (key in aggStore) {
294                 obj = aggStore[key];
295             } else {
296                 obj = aggStore[key] = {};
297                 aggKeys.push(key);
298                 dates.push(value);
299             }
300             //append record values to an aggregation record
301             for (i = 0; i &lt; recFieldsLen; i++) {
302                 curField = recFields[i];
303                 if (!obj[curField]) {
304                     obj[curField] = [];
305                 }
306                 if (rec.get(curField) !== undefined) {
307                     obj[curField].push(rec.get(curField));
308                 }
309             }
310         });
311         //perform aggregation operations on fields
312         for (key in aggStore) {
313             obj = aggStore[key];
314             for (i = 0; i &lt; recFieldsLen; i++) {
315                 curField = recFields[i];
316                 obj[curField] = aggregateFn[op](obj[curField]);
317             }
318             json.push(obj);
319         }
320         this.chart.substore = Ext.create('Ext.data.JsonStore', {
321             fields: recFields,
322             data: json
323         });
324         
325         this.dates = dates;
326     },
327     
328     // @private creates a label array to be used as the axis labels.
329      setLabels: function() {
330         var store = this.chart.substore,
331             fields = this.fields,
332             format = this.dateFormat,
333             labels, i, dates = this.dates,
334             formatFn = Ext.Date.format;
335         this.labels = labels = [];
336         store.each(function(record, i) {
337             if (!format) {
338                 labels.push(record.get(fields));
339             } else {
340                 labels.push(formatFn(dates[i], format));
341             }
342          }, this);
343      },
344
345     processView: function() {
346          //TODO(nico): fix this eventually...
347          if (this.constrain) {
348              this.constrainDates();
349              this.aggregate();
350              this.chart.substore = this.chart.filteredStore;
351          } else {
352              this.aggregate();
353          }
354     },
355
356      // @private modifies the store and creates the labels for the axes.
357      applyData: function() {
358         this.setLabels();
359         var count = this.chart.substore.getCount();
360          return {
361              from: 0,
362              to: count,
363              steps: count - 1,
364              step: 1
365          };
366      }
367  });
368
369 </pre>
370 </body>
371 </html>