Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / Chart.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-chart.Chart'>/**
2 </span> * @class Ext.chart.Chart
3  * @extends Ext.draw.Component
4  *
5  * The Ext.chart package provides the capability to visualize data.
6  * Each chart binds directly to an Ext.data.Store enabling automatic updates of the chart.
7  * A chart configuration object has some overall styling options as well as an array of axes
8  * and series. A chart instance example could look like:
9  *
10   &lt;pre&gt;&lt;code&gt;
11     Ext.create('Ext.chart.Chart', {
12         renderTo: Ext.getBody(),
13         width: 800,
14         height: 600,
15         animate: true,
16         store: store1,
17         shadow: true,
18         theme: 'Category1',
19         legend: {
20             position: 'right'
21         },
22         axes: [ ...some axes options... ],
23         series: [ ...some series options... ]
24     });
25   &lt;/code&gt;&lt;/pre&gt;
26  *
27  * In this example we set the `width` and `height` of the chart, we decide whether our series are
28  * animated or not and we select a store to be bound to the chart. We also turn on shadows for all series,
29  * select a color theme `Category1` for coloring the series, set the legend to the right part of the chart and
30  * then tell the chart to render itself in the body element of the document. For more information about the axes and
31  * series configurations please check the documentation of each series (Line, Bar, Pie, etc).
32  *
33  * @xtype chart
34  */
35
36 Ext.define('Ext.chart.Chart', {
37
38     /* Begin Definitions */
39
40     alias: 'widget.chart',
41
42     extend: 'Ext.draw.Component',
43     
44     mixins: {
45         themeManager: 'Ext.chart.theme.Theme',
46         mask: 'Ext.chart.Mask',
47         navigation: 'Ext.chart.Navigation'
48     },
49
50     requires: [
51         'Ext.util.MixedCollection',
52         'Ext.data.StoreManager',
53         'Ext.chart.Legend',
54         'Ext.util.DelayedTask'
55     ],
56
57     /* End Definitions */
58
59     // @private
60     viewBox: false,
61
62 <span id='Ext-chart.Chart-cfg-theme'>    /**
63 </span>     * @cfg {String} theme (optional) The name of the theme to be used. A theme defines the colors and
64      * other visual displays of tick marks on axis, text, title text, line colors, marker colors and styles, etc.
65      * Possible theme values are 'Base', 'Green', 'Sky', 'Red', 'Purple', 'Blue', 'Yellow' and also six category themes
66      * 'Category1' to 'Category6'. Default value is 'Base'.
67      */
68
69 <span id='Ext-chart.Chart-cfg-animate'>    /**
70 </span>     * @cfg {Boolean/Object} animate (optional) true for the default animation (easing: 'ease' and duration: 500)
71      * or a standard animation config object to be used for default chart animations. Defaults to false.
72      */
73     animate: false,
74
75 <span id='Ext-chart.Chart-cfg-legend'>    /**
76 </span>     * @cfg {Boolean/Object} legend (optional) true for the default legend display or a legend config object. Defaults to false.
77      */
78     legend: false,
79
80 <span id='Ext-chart.Chart-cfg-insetPadding'>    /**
81 </span>     * @cfg {integer} insetPadding (optional) Set the amount of inset padding in pixels for the chart. Defaults to 10.
82      */
83     insetPadding: 10,
84
85 <span id='Ext-chart.Chart-cfg-enginePriority'>    /**
86 </span>     * @cfg {Array} enginePriority
87      * Defines the priority order for which Surface implementation to use. The first
88      * one supported by the current environment will be used.
89      */
90     enginePriority: ['Svg', 'Vml'],
91
92 <span id='Ext-chart.Chart-cfg-background'>    /**
93 </span>     * @cfg {Object|Boolean} background (optional) Set the chart background. This can be a gradient object, image, or color.
94      * Defaults to false for no background.
95      *
96      * For example, if `background` were to be a color we could set the object as
97      *
98      &lt;pre&gt;&lt;code&gt;
99         background: {
100             //color string
101             fill: '#ccc'
102         }
103      &lt;/code&gt;&lt;/pre&gt;
104
105      You can specify an image by using:
106
107      &lt;pre&gt;&lt;code&gt;
108         background: {
109             image: 'http://path.to.image/'
110         }
111      &lt;/code&gt;&lt;/pre&gt;
112
113      Also you can specify a gradient by using the gradient object syntax:
114
115      &lt;pre&gt;&lt;code&gt;
116         background: {
117             gradient: {
118                 id: 'gradientId',
119                 angle: 45,
120                 stops: {
121                     0: {
122                         color: '#555'
123                     }
124                     100: {
125                         color: '#ddd'
126                     }
127                 }
128             }
129         }
130      &lt;/code&gt;&lt;/pre&gt;
131      */
132     background: false,
133
134 <span id='Ext-chart.Chart-cfg-gradients'>    /**
135 </span>     * @cfg {Array} gradients (optional) Define a set of gradients that can be used as `fill` property in sprites.
136      * The gradients array is an array of objects with the following properties:
137      *
138      * &lt;ul&gt;
139      * &lt;li&gt;&lt;strong&gt;id&lt;/strong&gt; - string - The unique name of the gradient.&lt;/li&gt;
140      * &lt;li&gt;&lt;strong&gt;angle&lt;/strong&gt; - number, optional - The angle of the gradient in degrees.&lt;/li&gt;
141      * &lt;li&gt;&lt;strong&gt;stops&lt;/strong&gt; - object - An object with numbers as keys (from 0 to 100) and style objects
142      * as values&lt;/li&gt;
143      * &lt;/ul&gt;
144      *
145
146      For example:
147
148      &lt;pre&gt;&lt;code&gt;
149         gradients: [{
150             id: 'gradientId',
151             angle: 45,
152             stops: {
153                 0: {
154                     color: '#555'
155                 },
156                 100: {
157                     color: '#ddd'
158                 }
159             }
160         },  {
161             id: 'gradientId2',
162             angle: 0,
163             stops: {
164                 0: {
165                     color: '#590'
166                 },
167                 20: {
168                     color: '#599'
169                 },
170                 100: {
171                     color: '#ddd'
172                 }
173             }
174         }]
175      &lt;/code&gt;&lt;/pre&gt;
176
177      Then the sprites can use `gradientId` and `gradientId2` by setting the fill attributes to those ids, for example:
178
179      &lt;pre&gt;&lt;code&gt;
180         sprite.setAttributes({
181             fill: 'url(#gradientId)'
182         }, true);
183      &lt;/code&gt;&lt;/pre&gt;
184
185      */
186
187
188     constructor: function(config) {
189         var me = this,
190             defaultAnim;
191         me.initTheme(config.theme || me.theme);
192         if (me.gradients) {
193             Ext.apply(config, { gradients: me.gradients });
194         }
195         if (me.background) {
196             Ext.apply(config, { background: me.background });
197         }
198         if (config.animate) {
199             defaultAnim = {
200                 easing: 'ease',
201                 duration: 500
202             };
203             if (Ext.isObject(config.animate)) {
204                 config.animate = Ext.applyIf(config.animate, defaultAnim);
205             }
206             else {
207                 config.animate = defaultAnim;
208             }
209         }
210         me.mixins.mask.constructor.call(me, config);
211         me.mixins.navigation.constructor.call(me, config);
212         me.callParent([config]);
213     },
214
215     initComponent: function() {
216         var me = this,
217             axes,
218             series;
219         me.callParent();
220         me.addEvents(
221             'itemmousedown',
222             'itemmouseup',
223             'itemmouseover',
224             'itemmouseout',
225             'itemclick',
226             'itemdoubleclick',
227             'itemdragstart',
228             'itemdrag',
229             'itemdragend',
230 <span id='Ext-chart.Chart-event-beforerefresh'>            /**
231 </span>                 * @event beforerefresh
232                  * Fires before a refresh to the chart data is called.  If the beforerefresh handler returns
233                  * &lt;tt&gt;false&lt;/tt&gt; the {@link #refresh} action will be cancelled.
234                  * @param {Chart} this
235                  */
236             'beforerefresh',
237 <span id='Ext-chart.Chart-event-refresh'>            /**
238 </span>                 * @event refresh
239                  * Fires after the chart data has been refreshed.
240                  * @param {Chart} this
241                  */
242             'refresh'
243         );
244         Ext.applyIf(me, {
245             zoom: {
246                 width: 1,
247                 height: 1,
248                 x: 0,
249                 y: 0
250             }
251         });
252         me.maxGutter = [0, 0];
253         me.store = Ext.data.StoreManager.lookup(me.store);
254         axes = me.axes;
255         me.axes = Ext.create('Ext.util.MixedCollection', false, function(a) { return a.position; });
256         if (axes) {
257             me.axes.addAll(axes);
258         }
259         series = me.series;
260         me.series = Ext.create('Ext.util.MixedCollection', false, function(a) { return a.seriesId || (a.seriesId = Ext.id(null, 'ext-chart-series-')); });
261         if (series) {
262             me.series.addAll(series);
263         }
264         if (me.legend !== false) {
265             me.legend = Ext.create('Ext.chart.Legend', Ext.applyIf({chart:me}, me.legend));
266         }
267
268         me.on({
269             mousemove: me.onMouseMove,
270             mouseleave: me.onMouseLeave,
271             mousedown: me.onMouseDown,
272             mouseup: me.onMouseUp,
273             scope: me
274         });
275     },
276
277     // @private overrides the component method to set the correct dimensions to the chart.
278     afterComponentLayout: function(width, height) {
279         var me = this;
280         if (Ext.isNumber(width) &amp;&amp; Ext.isNumber(height)) {
281             me.curWidth = width;
282             me.curHeight = height;
283             me.redraw(true);
284         }
285         this.callParent(arguments);
286     },
287
288 <span id='Ext-chart.Chart-cfg-resize'>    /**
289 </span>     * Redraw the chart. If animations are set this will animate the chart too.
290      * @cfg {boolean} resize Optional flag which changes the default origin points of the chart for animations.
291      */
292     redraw: function(resize) {
293         var me = this,
294             chartBBox = me.chartBBox = {
295                 x: 0,
296                 y: 0,
297                 height: me.curHeight,
298                 width: me.curWidth
299             },
300             legend = me.legend;
301         me.surface.setSize(chartBBox.width, chartBBox.height);
302         // Instantiate Series and Axes
303         me.series.each(me.initializeSeries, me);
304         me.axes.each(me.initializeAxis, me);
305         //process all views (aggregated data etc) on stores
306         //before rendering.
307         me.axes.each(function(axis) {
308             axis.processView();
309         });
310         me.axes.each(function(axis) {
311             axis.drawAxis(true);
312         });
313
314         // Create legend if not already created
315         if (legend !== false) {
316             legend.create();
317         }
318
319         // Place axes properly, including influence from each other
320         me.alignAxes();
321
322         // Reposition legend based on new axis alignment
323         if (me.legend !== false) {
324             legend.updatePosition();
325         }
326
327         // Find the max gutter
328         me.getMaxGutter();
329
330         // Draw axes and series
331         me.resizing = !!resize;
332
333         me.axes.each(me.drawAxis, me);
334         me.series.each(me.drawCharts, me);
335         me.resizing = false;
336     },
337
338     // @private set the store after rendering the chart.
339     afterRender: function() {
340         var ref,
341             me = this;
342         this.callParent();
343
344         if (me.categoryNames) {
345             me.setCategoryNames(me.categoryNames);
346         }
347
348         if (me.tipRenderer) {
349             ref = me.getFunctionRef(me.tipRenderer);
350             me.setTipRenderer(ref.fn, ref.scope);
351         }
352         me.bindStore(me.store, true);
353         me.refresh();
354     },
355
356     // @private get x and y position of the mouse cursor.
357     getEventXY: function(e) {
358         var me = this,
359             box = this.surface.getRegion(),
360             pageXY = e.getXY(),
361             x = pageXY[0] - box.left,
362             y = pageXY[1] - box.top;
363         return [x, y];
364     },
365
366     // @private wrap the mouse down position to delegate the event to the series.
367     onClick: function(e) {
368         var me = this,
369             position = me.getEventXY(e),
370             item;
371
372         // Ask each series if it has an item corresponding to (not necessarily exactly
373         // on top of) the current mouse coords. Fire itemclick event.
374         me.series.each(function(series) {
375             if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
376                 if (series.getItemForPoint) {
377                     item = series.getItemForPoint(position[0], position[1]);
378                     if (item) {
379                         series.fireEvent('itemclick', item);
380                     }
381                 }
382             }
383         }, me);
384     },
385
386     // @private wrap the mouse down position to delegate the event to the series.
387     onMouseDown: function(e) {
388         var me = this,
389             position = me.getEventXY(e),
390             item;
391
392         if (me.mask) {
393             me.mixins.mask.onMouseDown.call(me, e);
394         }
395         // Ask each series if it has an item corresponding to (not necessarily exactly
396         // on top of) the current mouse coords. Fire mousedown event.
397         me.series.each(function(series) {
398             if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
399                 if (series.getItemForPoint) {
400                     item = series.getItemForPoint(position[0], position[1]);
401                     if (item) {
402                         series.fireEvent('itemmousedown', item);
403                     }
404                 }
405             }
406         }, me);
407     },
408
409     // @private wrap the mouse up event to delegate it to the series.
410     onMouseUp: function(e) {
411         var me = this,
412             position = me.getEventXY(e),
413             item;
414
415         if (me.mask) {
416             me.mixins.mask.onMouseUp.call(me, e);
417         }
418         // Ask each series if it has an item corresponding to (not necessarily exactly
419         // on top of) the current mouse coords. Fire mousedown event.
420         me.series.each(function(series) {
421             if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
422                 if (series.getItemForPoint) {
423                     item = series.getItemForPoint(position[0], position[1]);
424                     if (item) {
425                         series.fireEvent('itemmouseup', item);
426                     }
427                 }
428             }
429         }, me);
430     },
431
432     // @private wrap the mouse move event so it can be delegated to the series.
433     onMouseMove: function(e) {
434         var me = this,
435             position = me.getEventXY(e),
436             item, last, storeItem, storeField;
437
438         if (me.mask) {
439             me.mixins.mask.onMouseMove.call(me, e);
440         }
441         // Ask each series if it has an item corresponding to (not necessarily exactly
442         // on top of) the current mouse coords. Fire itemmouseover/out events.
443         me.series.each(function(series) {
444             if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
445                 if (series.getItemForPoint) {
446                     item = series.getItemForPoint(position[0], position[1]);
447                     last = series._lastItemForPoint;
448                     storeItem = series._lastStoreItem;
449                     storeField = series._lastStoreField;
450
451
452                     if (item !== last || item &amp;&amp; (item.storeItem != storeItem || item.storeField != storeField)) {
453                         if (last) {
454                             series.fireEvent('itemmouseout', last);
455                             delete series._lastItemForPoint;
456                             delete series._lastStoreField;
457                             delete series._lastStoreItem;
458                         }
459                         if (item) {
460                             series.fireEvent('itemmouseover', item);
461                             series._lastItemForPoint = item;
462                             series._lastStoreItem = item.storeItem;
463                             series._lastStoreField = item.storeField;
464                         }
465                     }
466                 }
467             } else {
468                 last = series._lastItemForPoint;
469                 if (last) {
470                     series.fireEvent('itemmouseout', last);
471                     delete series._lastItemForPoint;
472                     delete series._lastStoreField;
473                     delete series._lastStoreItem;
474                 }
475             }
476         }, me);
477     },
478
479     // @private handle mouse leave event.
480     onMouseLeave: function(e) {
481         var me = this;
482         if (me.mask) {
483             me.mixins.mask.onMouseLeave.call(me, e);
484         }
485         me.series.each(function(series) {
486             delete series._lastItemForPoint;
487         });
488     },
489
490     // @private buffered refresh for when we update the store
491     delayRefresh: function() {
492         var me = this;
493         if (!me.refreshTask) {
494             me.refreshTask = Ext.create('Ext.util.DelayedTask', me.refresh, me);
495         }
496         me.refreshTask.delay(me.refreshBuffer);
497     },
498
499     // @private
500     refresh: function() {
501         var me = this;
502         if (me.rendered &amp;&amp; me.curWidth != undefined &amp;&amp; me.curHeight != undefined) {
503             if (me.fireEvent('beforerefresh', me) !== false) {
504                 me.redraw();
505                 me.fireEvent('refresh', me);
506             }
507         }
508     },
509
510 <span id='Ext-chart.Chart-method-bindStore'>    /**
511 </span>     * Changes the data store bound to this chart and refreshes it.
512      * @param {Store} store The store to bind to this chart
513      */
514     bindStore: function(store, initial) {
515         var me = this;
516         if (!initial &amp;&amp; me.store) {
517             if (store !== me.store &amp;&amp; me.store.autoDestroy) {
518                 me.store.destroy();
519             }
520             else {
521                 me.store.un('datachanged', me.refresh, me);
522                 me.store.un('add', me.delayRefresh, me);
523                 me.store.un('remove', me.delayRefresh, me);
524                 me.store.un('update', me.delayRefresh, me);
525                 me.store.un('clear', me.refresh, me);
526             }
527         }
528         if (store) {
529             store = Ext.data.StoreManager.lookup(store);
530             store.on({
531                 scope: me,
532                 datachanged: me.refresh,
533                 add: me.delayRefresh,
534                 remove: me.delayRefresh,
535                 update: me.delayRefresh,
536                 clear: me.refresh
537             });
538         }
539         me.store = store;
540         if (store &amp;&amp; !initial) {
541             me.refresh();
542         }
543     },
544
545     // @private Create Axis
546     initializeAxis: function(axis) {
547         var me = this,
548             chartBBox = me.chartBBox,
549             w = chartBBox.width,
550             h = chartBBox.height,
551             x = chartBBox.x,
552             y = chartBBox.y,
553             themeAttrs = me.themeAttrs,
554             config = {
555                 chart: me
556             };
557         if (themeAttrs) {
558             config.axisStyle = Ext.apply({}, themeAttrs.axis);
559             config.axisLabelLeftStyle = Ext.apply({}, themeAttrs.axisLabelLeft);
560             config.axisLabelRightStyle = Ext.apply({}, themeAttrs.axisLabelRight);
561             config.axisLabelTopStyle = Ext.apply({}, themeAttrs.axisLabelTop);
562             config.axisLabelBottomStyle = Ext.apply({}, themeAttrs.axisLabelBottom);
563             config.axisTitleLeftStyle = Ext.apply({}, themeAttrs.axisTitleLeft);
564             config.axisTitleRightStyle = Ext.apply({}, themeAttrs.axisTitleRight);
565             config.axisTitleTopStyle = Ext.apply({}, themeAttrs.axisTitleTop);
566             config.axisTitleBottomStyle = Ext.apply({}, themeAttrs.axisTitleBottom);
567         }
568         switch (axis.position) {
569             case 'top':
570                 Ext.apply(config, {
571                     length: w,
572                     width: h,
573                     x: x,
574                     y: y
575                 });
576             break;
577             case 'bottom':
578                 Ext.apply(config, {
579                     length: w,
580                     width: h,
581                     x: x,
582                     y: h
583                 });
584             break;
585             case 'left':
586                 Ext.apply(config, {
587                     length: h,
588                     width: w,
589                     x: x,
590                     y: h
591                 });
592             break;
593             case 'right':
594                 Ext.apply(config, {
595                     length: h,
596                     width: w,
597                     x: w,
598                     y: h
599                 });
600             break;
601         }
602         if (!axis.chart) {
603             Ext.apply(config, axis);
604             axis = me.axes.replace(Ext.createByAlias('axis.' + axis.type.toLowerCase(), config));
605         }
606         else {
607             Ext.apply(axis, config);
608         }
609     },
610
611
612 <span id='Ext-chart.Chart-method-alignAxes'>    /**
613 </span>     * @private Adjust the dimensions and positions of each axis and the chart body area after accounting
614      * for the space taken up on each side by the axes and legend.
615      */
616     alignAxes: function() {
617         var me = this,
618             axes = me.axes,
619             legend = me.legend,
620             edges = ['top', 'right', 'bottom', 'left'],
621             chartBBox,
622             insetPadding = me.insetPadding,
623             insets = {
624                 top: insetPadding,
625                 right: insetPadding,
626                 bottom: insetPadding,
627                 left: insetPadding
628             };
629
630         function getAxis(edge) {
631             var i = axes.findIndex('position', edge);
632             return (i &lt; 0) ? null : axes.getAt(i);
633         }
634
635         // Find the space needed by axes and legend as a positive inset from each edge
636         Ext.each(edges, function(edge) {
637             var isVertical = (edge === 'left' || edge === 'right'),
638                 axis = getAxis(edge),
639                 bbox;
640
641             // Add legend size if it's on this edge
642             if (legend !== false) {
643                 if (legend.position === edge) {
644                     bbox = legend.getBBox();
645                     insets[edge] += (isVertical ? bbox.width : bbox.height) + insets[edge];
646                 }
647             }
648
649             // Add axis size if there's one on this edge only if it has been
650             //drawn before.
651             if (axis &amp;&amp; axis.bbox) {
652                 bbox = axis.bbox;
653                 insets[edge] += (isVertical ? bbox.width : bbox.height);
654             }
655         });
656         // Build the chart bbox based on the collected inset values
657         chartBBox = {
658             x: insets.left,
659             y: insets.top,
660             width: me.curWidth - insets.left - insets.right,
661             height: me.curHeight - insets.top - insets.bottom
662         };
663         me.chartBBox = chartBBox;
664
665         // Go back through each axis and set its length and position based on the
666         // corresponding edge of the chartBBox
667         axes.each(function(axis) {
668             var pos = axis.position,
669                 isVertical = (pos === 'left' || pos === 'right');
670
671             axis.x = (pos === 'right' ? chartBBox.x + chartBBox.width : chartBBox.x);
672             axis.y = (pos === 'top' ? chartBBox.y : chartBBox.y + chartBBox.height);
673             axis.width = (isVertical ? chartBBox.width : chartBBox.height);
674             axis.length = (isVertical ? chartBBox.height : chartBBox.width);
675         });
676     },
677
678     // @private initialize the series.
679     initializeSeries: function(series, idx) {
680         var me = this,
681             themeAttrs = me.themeAttrs,
682             seriesObj, markerObj, seriesThemes, st,
683             markerThemes, colorArrayStyle = [],
684             i = 0, l,
685             config = {
686                 chart: me,
687                 seriesId: series.seriesId
688             };
689         if (themeAttrs) {
690             seriesThemes = themeAttrs.seriesThemes;
691             markerThemes = themeAttrs.markerThemes;
692             seriesObj = Ext.apply({}, themeAttrs.series);
693             markerObj = Ext.apply({}, themeAttrs.marker);
694             config.seriesStyle = Ext.apply(seriesObj, seriesThemes[idx % seriesThemes.length]);
695             config.seriesLabelStyle = Ext.apply({}, themeAttrs.seriesLabel);
696             config.markerStyle = Ext.apply(markerObj, markerThemes[idx % markerThemes.length]);
697             if (themeAttrs.colors) {
698                 config.colorArrayStyle = themeAttrs.colors;
699             } else {
700                 colorArrayStyle = [];
701                 for (l = seriesThemes.length; i &lt; l; i++) {
702                     st = seriesThemes[i];
703                     if (st.fill || st.stroke) {
704                         colorArrayStyle.push(st.fill || st.stroke);
705                     }
706                 }
707                 if (colorArrayStyle.length) {
708                     config.colorArrayStyle = colorArrayStyle;
709                 }
710             }
711             config.seriesIdx = idx;
712         }
713         if (series instanceof Ext.chart.series.Series) {
714             Ext.apply(series, config);
715         } else {
716             Ext.applyIf(config, series);
717             series = me.series.replace(Ext.createByAlias('series.' + series.type.toLowerCase(), config));
718         }
719         if (series.initialize) {
720             series.initialize();
721         }
722     },
723
724     // @private
725     getMaxGutter: function() {
726         var me = this,
727             maxGutter = [0, 0];
728         me.series.each(function(s) {
729             var gutter = s.getGutters &amp;&amp; s.getGutters() || [0, 0];
730             maxGutter[0] = Math.max(maxGutter[0], gutter[0]);
731             maxGutter[1] = Math.max(maxGutter[1], gutter[1]);
732         });
733         me.maxGutter = maxGutter;
734     },
735
736     // @private draw axis.
737     drawAxis: function(axis) {
738         axis.drawAxis();
739     },
740
741     // @private draw series.
742     drawCharts: function(series) {
743         series.triggerafterrender = false;
744         series.drawSeries();
745         if (!this.animate) {
746             series.fireEvent('afterrender');
747         }
748     },
749
750     // @private remove gently.
751     destroy: function() {
752         this.surface.destroy();
753         this.bindStore(null);
754         this.callParent(arguments);
755     }
756 });
757 </pre></pre></body></html>