Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Chart.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="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/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-Chart'>/**
19 </span> * Charts provide a flexible way to achieve a wide range of data visualization capablitities.
20  * Each Chart gets its data directly from a {@link Ext.data.Store Store}, and automatically
21  * updates its display whenever data in the Store changes. In addition, the look and feel
22  * of a Chart can be customized using {@link Ext.chart.theme.Theme Theme}s.
23  * 
24  * ## Creating a Simple Chart
25  * 
26  * Every Chart has three key parts - a {@link Ext.data.Store Store} that contains the data,
27  * an array of {@link Ext.chart.axis.Axis Axes} which define the boundaries of the Chart,
28  * and one or more {@link Ext.chart.series.Series Series} to handle the visual rendering of the data points.
29  * 
30  * ### 1. Creating a Store
31  * 
32  * The first step is to create a {@link Ext.data.Model Model} that represents the type of
33  * data that will be displayed in the Chart. For example the data for a chart that displays
34  * a weather forecast could be represented as a series of &quot;WeatherPoint&quot; data points with
35  * two fields - &quot;temperature&quot;, and &quot;date&quot;:
36  * 
37  *     Ext.define('WeatherPoint', {
38  *         extend: 'Ext.data.Model',
39  *         fields: ['temperature', 'date']
40  *     });
41  * 
42  * Next a {@link Ext.data.Store Store} must be created.  The store contains a collection of &quot;WeatherPoint&quot; Model instances.
43  * The data could be loaded dynamically, but for sake of ease this example uses inline data:
44  * 
45  *     var store = Ext.create('Ext.data.Store', {
46  *         model: 'WeatherPoint',
47  *         data: [
48  *             { temperature: 58, date: new Date(2011, 1, 1, 8) },
49  *             { temperature: 63, date: new Date(2011, 1, 1, 9) },
50  *             { temperature: 73, date: new Date(2011, 1, 1, 10) },
51  *             { temperature: 78, date: new Date(2011, 1, 1, 11) },
52  *             { temperature: 81, date: new Date(2011, 1, 1, 12) }
53  *         ]
54  *     });
55  *    
56  * For additional information on Models and Stores please refer to the [Data Guide](#/guide/data).
57  * 
58  * ### 2. Creating the Chart object
59  * 
60  * Now that a Store has been created it can be used in a Chart:
61  * 
62  *     Ext.create('Ext.chart.Chart', {
63  *        renderTo: Ext.getBody(),
64  *        width: 400,
65  *        height: 300,
66  *        store: store
67  *     });
68  *    
69  * That's all it takes to create a Chart instance that is backed by a Store.
70  * However, if the above code is run in a browser, a blank screen will be displayed.
71  * This is because the two pieces that are responsible for the visual display,
72  * the Chart's {@link #cfg-axes axes} and {@link #cfg-series series}, have not yet been defined.
73  * 
74  * ### 3. Configuring the Axes
75  * 
76  * {@link Ext.chart.axis.Axis Axes} are the lines that define the boundaries of the data points that a Chart can display.
77  * This example uses one of the most common Axes configurations - a horizontal &quot;x&quot; axis, and a vertical &quot;y&quot; axis:
78  * 
79  *     Ext.create('Ext.chart.Chart', {
80  *         ...
81  *         axes: [
82  *             {
83  *                 title: 'Temperature',
84  *                 type: 'Numeric',
85  *                 position: 'left',
86  *                 fields: ['temperature'],
87  *                 minimum: 0,
88  *                 maximum: 100
89  *             },
90  *             {
91  *                 title: 'Time',
92  *                 type: 'Time',
93  *                 position: 'bottom',
94  *                 fields: ['date'],
95  *                 dateFormat: 'ga'
96  *             }
97  *         ]
98  *     });
99  *    
100  * The &quot;Temperature&quot; axis is a vertical {@link Ext.chart.axis.Numeric Numeric Axis} and is positioned on the left edge of the Chart.
101  * It represents the bounds of the data contained in the &quot;WeatherPoint&quot; Model's &quot;temperature&quot; field that was
102  * defined above. The minimum value for this axis is &quot;0&quot;, and the maximum is &quot;100&quot;.
103  * 
104  * The horizontal axis is a {@link Ext.chart.axis.Time Time Axis} and is positioned on the bottom edge of the Chart.
105  * It represents the bounds of the data contained in the &quot;WeatherPoint&quot; Model's &quot;date&quot; field.
106  * The {@link Ext.chart.axis.Time#cfg-dateFormat dateFormat}
107  * configuration tells the Time Axis how to format it's labels.
108  * 
109  * Here's what the Chart looks like now that it has its Axes configured:
110  * 
111  * {@img Ext.chart.Chart/Ext.chart.Chart1.png Chart Axes}
112  * 
113  * ### 4. Configuring the Series
114  * 
115  * The final step in creating a simple Chart is to configure one or more {@link Ext.chart.series.Series Series}.
116  * Series are responsible for the visual representation of the data points contained in the Store.
117  * This example only has one Series:
118  * 
119  *     Ext.create('Ext.chart.Chart', {
120  *         ...
121  *         axes: [
122  *             ...
123  *         ],
124  *         series: [
125  *             {
126  *                 type: 'line',
127  *                 xField: 'date',
128  *                 yField: 'temperature'
129  *             }
130  *         ]
131  *     });
132  *     
133  * This Series is a {@link Ext.chart.series.Line Line Series}, and it uses the &quot;date&quot; and &quot;temperature&quot; fields
134  * from the &quot;WeatherPoint&quot; Models in the Store to plot its data points:
135  * 
136  * {@img Ext.chart.Chart/Ext.chart.Chart2.png Line Series}
137  * 
138  * See the [Simple Chart Example](doc-resources/Ext.chart.Chart/examples/simple_chart/index.html) for a live demo.
139  * 
140  * ## Themes
141  * 
142  * The color scheme for a Chart can be easily changed using the {@link #cfg-theme theme} configuration option:
143  * 
144  *     Ext.create('Ext.chart.Chart', {
145  *         ...
146  *         theme: 'Green',
147  *         ...
148  *     });
149  * 
150  * {@img Ext.chart.Chart/Ext.chart.Chart3.png Green Theme}
151  * 
152  * For more information on Charts please refer to the [Drawing and Charting Guide](#/guide/drawing_and_charting).
153  * 
154  */
155 Ext.define('Ext.chart.Chart', {
156
157     /* Begin Definitions */
158
159     alias: 'widget.chart',
160
161     extend: 'Ext.draw.Component',
162     
163     mixins: {
164         themeManager: 'Ext.chart.theme.Theme',
165         mask: 'Ext.chart.Mask',
166         navigation: 'Ext.chart.Navigation'
167     },
168
169     requires: [
170         'Ext.util.MixedCollection',
171         'Ext.data.StoreManager',
172         'Ext.chart.Legend',
173         'Ext.util.DelayedTask'
174     ],
175
176     /* End Definitions */
177
178     // @private
179     viewBox: false,
180
181 <span id='Ext-chart-Chart-cfg-theme'>    /**
182 </span>     * @cfg {String} theme
183      * The name of the theme to be used. A theme defines the colors and other visual displays of tick marks
184      * on axis, text, title text, line colors, marker colors and styles, etc. Possible theme values are 'Base', 'Green',
185      * 'Sky', 'Red', 'Purple', 'Blue', 'Yellow' and also six category themes 'Category1' to 'Category6'. Default value
186      * is 'Base'.
187      */
188
189 <span id='Ext-chart-Chart-cfg-animate'>    /**
190 </span>     * @cfg {Boolean/Object} animate
191      * True for the default animation (easing: 'ease' and duration: 500) or a standard animation config
192      * object to be used for default chart animations. Defaults to false.
193      */
194     animate: false,
195
196 <span id='Ext-chart-Chart-cfg-legend'>    /**
197 </span>     * @cfg {Boolean/Object} legend
198      * True for the default legend display or a legend config object. Defaults to false.
199      */
200     legend: false,
201
202 <span id='Ext-chart-Chart-cfg-insetPadding'>    /**
203 </span>     * @cfg {Number} insetPadding
204      * The amount of inset padding in pixels for the chart. Defaults to 10.
205      */
206     insetPadding: 10,
207
208 <span id='Ext-chart-Chart-cfg-enginePriority'>    /**
209 </span>     * @cfg {String[]} enginePriority
210      * Defines the priority order for which Surface implementation to use. The first one supported by the current
211      * environment will be used. Defaults to `['Svg', 'Vml']`.
212      */
213     enginePriority: ['Svg', 'Vml'],
214
215 <span id='Ext-chart-Chart-cfg-background'>    /**
216 </span>     * @cfg {Object/Boolean} background
217      * The chart background. This can be a gradient object, image, or color. Defaults to false for no
218      * background. For example, if `background` were to be a color we could set the object as
219      *
220      *     background: {
221      *         //color string
222      *         fill: '#ccc'
223      *     }
224      *
225      * You can specify an image by using:
226      *
227      *     background: {
228      *         image: 'http://path.to.image/'
229      *     }
230      *
231      * Also you can specify a gradient by using the gradient object syntax:
232      *
233      *     background: {
234      *         gradient: {
235      *             id: 'gradientId',
236      *             angle: 45,
237      *             stops: {
238      *                 0: {
239      *                     color: '#555'
240      *                 }
241      *                 100: {
242      *                     color: '#ddd'
243      *                 }
244      *             }
245      *         }
246      *     }
247      */
248     background: false,
249
250 <span id='Ext-chart-Chart-cfg-gradients'>    /**
251 </span>     * @cfg {Object[]} gradients
252      * Define a set of gradients that can be used as `fill` property in sprites. The gradients array is an
253      * array of objects with the following properties:
254      *
255      * - **id** - string - The unique name of the gradient.
256      * - **angle** - number, optional - The angle of the gradient in degrees.
257      * - **stops** - object - An object with numbers as keys (from 0 to 100) and style objects as values
258      *
259      * For example:
260      *
261      *     gradients: [{
262      *         id: 'gradientId',
263      *         angle: 45,
264      *         stops: {
265      *             0: {
266      *                 color: '#555'
267      *             },
268      *             100: {
269      *                 color: '#ddd'
270      *             }
271      *         }
272      *     }, {
273      *         id: 'gradientId2',
274      *         angle: 0,
275      *         stops: {
276      *             0: {
277      *                 color: '#590'
278      *             },
279      *             20: {
280      *                 color: '#599'
281      *             },
282      *             100: {
283      *                 color: '#ddd'
284      *             }
285      *         }
286      *     }]
287      *
288      * Then the sprites can use `gradientId` and `gradientId2` by setting the fill attributes to those ids, for example:
289      *
290      *     sprite.setAttributes({
291      *         fill: 'url(#gradientId)'
292      *     }, true);
293      */
294
295 <span id='Ext-chart-Chart-cfg-store'>    /**
296 </span>     * @cfg {Ext.data.Store} store
297      * The store that supplies data to this chart.
298      */
299
300 <span id='Ext-chart-Chart-cfg-series'>    /**
301 </span>     * @cfg {Ext.chart.series.Series[]} series
302      * Array of {@link Ext.chart.series.Series Series} instances or config objects.  For example:
303      * 
304      *     series: [{
305      *         type: 'column',
306      *         axis: 'left',
307      *         listeners: {
308      *             'afterrender': function() {
309      *                 console('afterrender');
310      *             }
311      *         },
312      *         xField: 'category',
313      *         yField: 'data1'
314      *     }]
315      */
316
317 <span id='Ext-chart-Chart-cfg-axes'>    /**
318 </span>     * @cfg {Ext.chart.axis.Axis[]} axes
319      * Array of {@link Ext.chart.axis.Axis Axis} instances or config objects.  For example:
320      * 
321      *     axes: [{
322      *         type: 'Numeric',
323      *         position: 'left',
324      *         fields: ['data1'],
325      *         title: 'Number of Hits',
326      *         minimum: 0,
327      *         //one minor tick between two major ticks
328      *         minorTickSteps: 1
329      *     }, {
330      *         type: 'Category',
331      *         position: 'bottom',
332      *         fields: ['name'],
333      *         title: 'Month of the Year'
334      *     }]
335      */
336
337     constructor: function(config) {
338         var me = this,
339             defaultAnim;
340             
341         config = Ext.apply({}, config);
342         me.initTheme(config.theme || me.theme);
343         if (me.gradients) {
344             Ext.apply(config, { gradients: me.gradients });
345         }
346         if (me.background) {
347             Ext.apply(config, { background: me.background });
348         }
349         if (config.animate) {
350             defaultAnim = {
351                 easing: 'ease',
352                 duration: 500
353             };
354             if (Ext.isObject(config.animate)) {
355                 config.animate = Ext.applyIf(config.animate, defaultAnim);
356             }
357             else {
358                 config.animate = defaultAnim;
359             }
360         }
361         me.mixins.mask.constructor.call(me, config);
362         me.mixins.navigation.constructor.call(me, config);
363         me.callParent([config]);
364     },
365     
366     getChartStore: function(){
367         return this.substore || this.store;    
368     },
369
370     initComponent: function() {
371         var me = this,
372             axes,
373             series;
374         me.callParent();
375         me.addEvents(
376             'itemmousedown',
377             'itemmouseup',
378             'itemmouseover',
379             'itemmouseout',
380             'itemclick',
381             'itemdoubleclick',
382             'itemdragstart',
383             'itemdrag',
384             'itemdragend',
385 <span id='Ext-chart-Chart-event-beforerefresh'>            /**
386 </span>             * @event beforerefresh
387              * Fires before a refresh to the chart data is called. If the beforerefresh handler returns false the
388              * {@link #refresh} action will be cancelled.
389              * @param {Ext.chart.Chart} this
390              */
391             'beforerefresh',
392 <span id='Ext-chart-Chart-event-refresh'>            /**
393 </span>             * @event refresh
394              * Fires after the chart data has been refreshed.
395              * @param {Ext.chart.Chart} this
396              */
397             'refresh'
398         );
399         Ext.applyIf(me, {
400             zoom: {
401                 width: 1,
402                 height: 1,
403                 x: 0,
404                 y: 0
405             }
406         });
407         me.maxGutter = [0, 0];
408         me.store = Ext.data.StoreManager.lookup(me.store);
409         axes = me.axes;
410         me.axes = Ext.create('Ext.util.MixedCollection', false, function(a) { return a.position; });
411         if (axes) {
412             me.axes.addAll(axes);
413         }
414         series = me.series;
415         me.series = Ext.create('Ext.util.MixedCollection', false, function(a) { return a.seriesId || (a.seriesId = Ext.id(null, 'ext-chart-series-')); });
416         if (series) {
417             me.series.addAll(series);
418         }
419         if (me.legend !== false) {
420             me.legend = Ext.create('Ext.chart.Legend', Ext.applyIf({chart:me}, me.legend));
421         }
422
423         me.on({
424             mousemove: me.onMouseMove,
425             mouseleave: me.onMouseLeave,
426             mousedown: me.onMouseDown,
427             mouseup: me.onMouseUp,
428             scope: me
429         });
430     },
431
432     // @private overrides the component method to set the correct dimensions to the chart.
433     afterComponentLayout: function(width, height) {
434         var me = this;
435         if (Ext.isNumber(width) &amp;&amp; Ext.isNumber(height)) {
436             me.curWidth = width;
437             me.curHeight = height;
438             me.redraw(true);
439         }
440         this.callParent(arguments);
441     },
442
443 <span id='Ext-chart-Chart-method-redraw'>    /**
444 </span>     * Redraws the chart. If animations are set this will animate the chart too. 
445      * @param {Boolean} resize (optional) flag which changes the default origin points of the chart for animations.
446      */
447     redraw: function(resize) {
448         var me = this,
449             chartBBox = me.chartBBox = {
450                 x: 0,
451                 y: 0,
452                 height: me.curHeight,
453                 width: me.curWidth
454             },
455             legend = me.legend;
456         me.surface.setSize(chartBBox.width, chartBBox.height);
457         // Instantiate Series and Axes
458         me.series.each(me.initializeSeries, me);
459         me.axes.each(me.initializeAxis, me);
460         //process all views (aggregated data etc) on stores
461         //before rendering.
462         me.axes.each(function(axis) {
463             axis.processView();
464         });
465         me.axes.each(function(axis) {
466             axis.drawAxis(true);
467         });
468
469         // Create legend if not already created
470         if (legend !== false) {
471             legend.create();
472         }
473
474         // Place axes properly, including influence from each other
475         me.alignAxes();
476
477         // Reposition legend based on new axis alignment
478         if (me.legend !== false) {
479             legend.updatePosition();
480         }
481
482         // Find the max gutter
483         me.getMaxGutter();
484
485         // Draw axes and series
486         me.resizing = !!resize;
487
488         me.axes.each(me.drawAxis, me);
489         me.series.each(me.drawCharts, me);
490         me.resizing = false;
491     },
492
493     // @private set the store after rendering the chart.
494     afterRender: function() {
495         var ref,
496             me = this;
497         this.callParent();
498
499         if (me.categoryNames) {
500             me.setCategoryNames(me.categoryNames);
501         }
502
503         if (me.tipRenderer) {
504             ref = me.getFunctionRef(me.tipRenderer);
505             me.setTipRenderer(ref.fn, ref.scope);
506         }
507         me.bindStore(me.store, true);
508         me.refresh();
509     },
510
511     // @private get x and y position of the mouse cursor.
512     getEventXY: function(e) {
513         var me = this,
514             box = this.surface.getRegion(),
515             pageXY = e.getXY(),
516             x = pageXY[0] - box.left,
517             y = pageXY[1] - box.top;
518         return [x, y];
519     },
520
521     // @private wrap the mouse down position to delegate the event to the series.
522     onClick: function(e) {
523         var me = this,
524             position = me.getEventXY(e),
525             item;
526
527         // Ask each series if it has an item corresponding to (not necessarily exactly
528         // on top of) the current mouse coords. Fire itemclick event.
529         me.series.each(function(series) {
530             if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
531                 if (series.getItemForPoint) {
532                     item = series.getItemForPoint(position[0], position[1]);
533                     if (item) {
534                         series.fireEvent('itemclick', item);
535                     }
536                 }
537             }
538         }, me);
539     },
540
541     // @private wrap the mouse down position to delegate the event to the series.
542     onMouseDown: function(e) {
543         var me = this,
544             position = me.getEventXY(e),
545             item;
546
547         if (me.mask) {
548             me.mixins.mask.onMouseDown.call(me, e);
549         }
550         // Ask each series if it has an item corresponding to (not necessarily exactly
551         // on top of) the current mouse coords. Fire mousedown event.
552         me.series.each(function(series) {
553             if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
554                 if (series.getItemForPoint) {
555                     item = series.getItemForPoint(position[0], position[1]);
556                     if (item) {
557                         series.fireEvent('itemmousedown', item);
558                     }
559                 }
560             }
561         }, me);
562     },
563
564     // @private wrap the mouse up event to delegate it to the series.
565     onMouseUp: function(e) {
566         var me = this,
567             position = me.getEventXY(e),
568             item;
569
570         if (me.mask) {
571             me.mixins.mask.onMouseUp.call(me, e);
572         }
573         // Ask each series if it has an item corresponding to (not necessarily exactly
574         // on top of) the current mouse coords. Fire mousedown event.
575         me.series.each(function(series) {
576             if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
577                 if (series.getItemForPoint) {
578                     item = series.getItemForPoint(position[0], position[1]);
579                     if (item) {
580                         series.fireEvent('itemmouseup', item);
581                     }
582                 }
583             }
584         }, me);
585     },
586
587     // @private wrap the mouse move event so it can be delegated to the series.
588     onMouseMove: function(e) {
589         var me = this,
590             position = me.getEventXY(e),
591             item, last, storeItem, storeField;
592
593         if (me.mask) {
594             me.mixins.mask.onMouseMove.call(me, e);
595         }
596         // Ask each series if it has an item corresponding to (not necessarily exactly
597         // on top of) the current mouse coords. Fire itemmouseover/out events.
598         me.series.each(function(series) {
599             if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
600                 if (series.getItemForPoint) {
601                     item = series.getItemForPoint(position[0], position[1]);
602                     last = series._lastItemForPoint;
603                     storeItem = series._lastStoreItem;
604                     storeField = series._lastStoreField;
605
606
607                     if (item !== last || item &amp;&amp; (item.storeItem != storeItem || item.storeField != storeField)) {
608                         if (last) {
609                             series.fireEvent('itemmouseout', last);
610                             delete series._lastItemForPoint;
611                             delete series._lastStoreField;
612                             delete series._lastStoreItem;
613                         }
614                         if (item) {
615                             series.fireEvent('itemmouseover', item);
616                             series._lastItemForPoint = item;
617                             series._lastStoreItem = item.storeItem;
618                             series._lastStoreField = item.storeField;
619                         }
620                     }
621                 }
622             } else {
623                 last = series._lastItemForPoint;
624                 if (last) {
625                     series.fireEvent('itemmouseout', last);
626                     delete series._lastItemForPoint;
627                     delete series._lastStoreField;
628                     delete series._lastStoreItem;
629                 }
630             }
631         }, me);
632     },
633
634     // @private handle mouse leave event.
635     onMouseLeave: function(e) {
636         var me = this;
637         if (me.mask) {
638             me.mixins.mask.onMouseLeave.call(me, e);
639         }
640         me.series.each(function(series) {
641             delete series._lastItemForPoint;
642         });
643     },
644
645     // @private buffered refresh for when we update the store
646     delayRefresh: function() {
647         var me = this;
648         if (!me.refreshTask) {
649             me.refreshTask = Ext.create('Ext.util.DelayedTask', me.refresh, me);
650         }
651         me.refreshTask.delay(me.refreshBuffer);
652     },
653
654     // @private
655     refresh: function() {
656         var me = this;
657         if (me.rendered &amp;&amp; me.curWidth !== undefined &amp;&amp; me.curHeight !== undefined) {
658             if (me.fireEvent('beforerefresh', me) !== false) {
659                 me.redraw();
660                 me.fireEvent('refresh', me);
661             }
662         }
663     },
664
665 <span id='Ext-chart-Chart-method-bindStore'>    /**
666 </span>     * Changes the data store bound to this chart and refreshes it.
667      * @param {Ext.data.Store} store The store to bind to this chart
668      */
669     bindStore: function(store, initial) {
670         var me = this;
671         if (!initial &amp;&amp; me.store) {
672             if (store !== me.store &amp;&amp; me.store.autoDestroy) {
673                 me.store.destroyStore();
674             }
675             else {
676                 me.store.un('datachanged', me.refresh, me);
677                 me.store.un('add', me.delayRefresh, me);
678                 me.store.un('remove', me.delayRefresh, me);
679                 me.store.un('update', me.delayRefresh, me);
680                 me.store.un('clear', me.refresh, me);
681             }
682         }
683         if (store) {
684             store = Ext.data.StoreManager.lookup(store);
685             store.on({
686                 scope: me,
687                 datachanged: me.refresh,
688                 add: me.delayRefresh,
689                 remove: me.delayRefresh,
690                 update: me.delayRefresh,
691                 clear: me.refresh
692             });
693         }
694         me.store = store;
695         if (store &amp;&amp; !initial) {
696             me.refresh();
697         }
698     },
699
700     // @private Create Axis
701     initializeAxis: function(axis) {
702         var me = this,
703             chartBBox = me.chartBBox,
704             w = chartBBox.width,
705             h = chartBBox.height,
706             x = chartBBox.x,
707             y = chartBBox.y,
708             themeAttrs = me.themeAttrs,
709             config = {
710                 chart: me
711             };
712         if (themeAttrs) {
713             config.axisStyle = Ext.apply({}, themeAttrs.axis);
714             config.axisLabelLeftStyle = Ext.apply({}, themeAttrs.axisLabelLeft);
715             config.axisLabelRightStyle = Ext.apply({}, themeAttrs.axisLabelRight);
716             config.axisLabelTopStyle = Ext.apply({}, themeAttrs.axisLabelTop);
717             config.axisLabelBottomStyle = Ext.apply({}, themeAttrs.axisLabelBottom);
718             config.axisTitleLeftStyle = Ext.apply({}, themeAttrs.axisTitleLeft);
719             config.axisTitleRightStyle = Ext.apply({}, themeAttrs.axisTitleRight);
720             config.axisTitleTopStyle = Ext.apply({}, themeAttrs.axisTitleTop);
721             config.axisTitleBottomStyle = Ext.apply({}, themeAttrs.axisTitleBottom);
722         }
723         switch (axis.position) {
724             case 'top':
725                 Ext.apply(config, {
726                     length: w,
727                     width: h,
728                     x: x,
729                     y: y
730                 });
731             break;
732             case 'bottom':
733                 Ext.apply(config, {
734                     length: w,
735                     width: h,
736                     x: x,
737                     y: h
738                 });
739             break;
740             case 'left':
741                 Ext.apply(config, {
742                     length: h,
743                     width: w,
744                     x: x,
745                     y: h
746                 });
747             break;
748             case 'right':
749                 Ext.apply(config, {
750                     length: h,
751                     width: w,
752                     x: w,
753                     y: h
754                 });
755             break;
756         }
757         if (!axis.chart) {
758             Ext.apply(config, axis);
759             axis = me.axes.replace(Ext.createByAlias('axis.' + axis.type.toLowerCase(), config));
760         }
761         else {
762             Ext.apply(axis, config);
763         }
764     },
765
766
767 <span id='Ext-chart-Chart-method-alignAxes'>    /**
768 </span>     * @private Adjust the dimensions and positions of each axis and the chart body area after accounting
769      * for the space taken up on each side by the axes and legend.
770      */
771     alignAxes: function() {
772         var me = this,
773             axes = me.axes,
774             legend = me.legend,
775             edges = ['top', 'right', 'bottom', 'left'],
776             chartBBox,
777             insetPadding = me.insetPadding,
778             insets = {
779                 top: insetPadding,
780                 right: insetPadding,
781                 bottom: insetPadding,
782                 left: insetPadding
783             };
784
785         function getAxis(edge) {
786             var i = axes.findIndex('position', edge);
787             return (i &lt; 0) ? null : axes.getAt(i);
788         }
789
790         // Find the space needed by axes and legend as a positive inset from each edge
791         Ext.each(edges, function(edge) {
792             var isVertical = (edge === 'left' || edge === 'right'),
793                 axis = getAxis(edge),
794                 bbox;
795
796             // Add legend size if it's on this edge
797             if (legend !== false) {
798                 if (legend.position === edge) {
799                     bbox = legend.getBBox();
800                     insets[edge] += (isVertical ? bbox.width : bbox.height) + insets[edge];
801                 }
802             }
803
804             // Add axis size if there's one on this edge only if it has been
805             //drawn before.
806             if (axis &amp;&amp; axis.bbox) {
807                 bbox = axis.bbox;
808                 insets[edge] += (isVertical ? bbox.width : bbox.height);
809             }
810         });
811         // Build the chart bbox based on the collected inset values
812         chartBBox = {
813             x: insets.left,
814             y: insets.top,
815             width: me.curWidth - insets.left - insets.right,
816             height: me.curHeight - insets.top - insets.bottom
817         };
818         me.chartBBox = chartBBox;
819
820         // Go back through each axis and set its length and position based on the
821         // corresponding edge of the chartBBox
822         axes.each(function(axis) {
823             var pos = axis.position,
824                 isVertical = (pos === 'left' || pos === 'right');
825
826             axis.x = (pos === 'right' ? chartBBox.x + chartBBox.width : chartBBox.x);
827             axis.y = (pos === 'top' ? chartBBox.y : chartBBox.y + chartBBox.height);
828             axis.width = (isVertical ? chartBBox.width : chartBBox.height);
829             axis.length = (isVertical ? chartBBox.height : chartBBox.width);
830         });
831     },
832
833     // @private initialize the series.
834     initializeSeries: function(series, idx) {
835         var me = this,
836             themeAttrs = me.themeAttrs,
837             seriesObj, markerObj, seriesThemes, st,
838             markerThemes, colorArrayStyle = [],
839             i = 0, l,
840             config = {
841                 chart: me,
842                 seriesId: series.seriesId
843             };
844         if (themeAttrs) {
845             seriesThemes = themeAttrs.seriesThemes;
846             markerThemes = themeAttrs.markerThemes;
847             seriesObj = Ext.apply({}, themeAttrs.series);
848             markerObj = Ext.apply({}, themeAttrs.marker);
849             config.seriesStyle = Ext.apply(seriesObj, seriesThemes[idx % seriesThemes.length]);
850             config.seriesLabelStyle = Ext.apply({}, themeAttrs.seriesLabel);
851             config.markerStyle = Ext.apply(markerObj, markerThemes[idx % markerThemes.length]);
852             if (themeAttrs.colors) {
853                 config.colorArrayStyle = themeAttrs.colors;
854             } else {
855                 colorArrayStyle = [];
856                 for (l = seriesThemes.length; i &lt; l; i++) {
857                     st = seriesThemes[i];
858                     if (st.fill || st.stroke) {
859                         colorArrayStyle.push(st.fill || st.stroke);
860                     }
861                 }
862                 if (colorArrayStyle.length) {
863                     config.colorArrayStyle = colorArrayStyle;
864                 }
865             }
866             config.seriesIdx = idx;
867         }
868         if (series instanceof Ext.chart.series.Series) {
869             Ext.apply(series, config);
870         } else {
871             Ext.applyIf(config, series);
872             series = me.series.replace(Ext.createByAlias('series.' + series.type.toLowerCase(), config));
873         }
874         if (series.initialize) {
875             series.initialize();
876         }
877     },
878
879     // @private
880     getMaxGutter: function() {
881         var me = this,
882             maxGutter = [0, 0];
883         me.series.each(function(s) {
884             var gutter = s.getGutters &amp;&amp; s.getGutters() || [0, 0];
885             maxGutter[0] = Math.max(maxGutter[0], gutter[0]);
886             maxGutter[1] = Math.max(maxGutter[1], gutter[1]);
887         });
888         me.maxGutter = maxGutter;
889     },
890
891     // @private draw axis.
892     drawAxis: function(axis) {
893         axis.drawAxis();
894     },
895
896     // @private draw series.
897     drawCharts: function(series) {
898         series.triggerafterrender = false;
899         series.drawSeries();
900         if (!this.animate) {
901             series.fireEvent('afterrender');
902         }
903     },
904
905     // @private remove gently.
906     destroy: function() {
907         Ext.destroy(this.surface);
908         this.bindStore(null);
909         this.callParent(arguments);
910     }
911 });
912 </pre>
913 </body>
914 </html>