| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-chart-Chart'>/**</span> * Charts provide a flexible way to achieve a wide range of data visualization capablitities. * Each Chart gets its data directly from a {@link Ext.data.Store Store}, and automatically * updates its display whenever data in the Store changes. In addition, the look and feel * of a Chart can be customized using {@link Ext.chart.theme.Theme Theme}s. *  * ## Creating a Simple Chart *  * Every Chart has three key parts - a {@link Ext.data.Store Store} that contains the data, * an array of {@link Ext.chart.axis.Axis Axes} which define the boundaries of the Chart, * and one or more {@link Ext.chart.series.Series Series} to handle the visual rendering of the data points. *  * ### 1. Creating a Store *  * The first step is to create a {@link Ext.data.Model Model} that represents the type of * data that will be displayed in the Chart. For example the data for a chart that displays * a weather forecast could be represented as a series of "WeatherPoint" data points with * two fields - "temperature", and "date": *  *     Ext.define('WeatherPoint', { *         extend: 'Ext.data.Model', *         fields: ['temperature', 'date'] *     }); *  * Next a {@link Ext.data.Store Store} must be created.  The store contains a collection of "WeatherPoint" Model instances. * The data could be loaded dynamically, but for sake of ease this example uses inline data: *  *     var store = Ext.create('Ext.data.Store', { *         model: 'WeatherPoint', *         data: [ *             { temperature: 58, date: new Date(2011, 1, 1, 8) }, *             { temperature: 63, date: new Date(2011, 1, 1, 9) }, *             { temperature: 73, date: new Date(2011, 1, 1, 10) }, *             { temperature: 78, date: new Date(2011, 1, 1, 11) }, *             { temperature: 81, date: new Date(2011, 1, 1, 12) } *         ] *     }); *     * For additional information on Models and Stores please refer to the [Data Guide](#/guide/data). *  * ### 2. Creating the Chart object *  * Now that a Store has been created it can be used in a Chart: *  *     Ext.create('Ext.chart.Chart', { *        renderTo: Ext.getBody(), *        width: 400, *        height: 300, *        store: store *     }); *     * That's all it takes to create a Chart instance that is backed by a Store. * However, if the above code is run in a browser, a blank screen will be displayed. * This is because the two pieces that are responsible for the visual display, * the Chart's {@link #cfg-axes axes} and {@link #cfg-series series}, have not yet been defined. *  * ### 3. Configuring the Axes *  * {@link Ext.chart.axis.Axis Axes} are the lines that define the boundaries of the data points that a Chart can display. * This example uses one of the most common Axes configurations - a horizontal "x" axis, and a vertical "y" axis: *  *     Ext.create('Ext.chart.Chart', { *         ... *         axes: [ *             { *                 title: 'Temperature', *                 type: 'Numeric', *                 position: 'left', *                 fields: ['temperature'], *                 minimum: 0, *                 maximum: 100 *             }, *             { *                 title: 'Time', *                 type: 'Time', *                 position: 'bottom', *                 fields: ['date'], *                 dateFormat: 'ga' *             } *         ] *     }); *     * The "Temperature" axis is a vertical {@link Ext.chart.axis.Numeric Numeric Axis} and is positioned on the left edge of the Chart. * It represents the bounds of the data contained in the "WeatherPoint" Model's "temperature" field that was * defined above. The minimum value for this axis is "0", and the maximum is "100". *  * The horizontal axis is a {@link Ext.chart.axis.Time Time Axis} and is positioned on the bottom edge of the Chart. * It represents the bounds of the data contained in the "WeatherPoint" Model's "date" field. * The {@link Ext.chart.axis.Time#cfg-dateFormat dateFormat} * configuration tells the Time Axis how to format it's labels. *  * Here's what the Chart looks like now that it has its Axes configured: *  * {@img Ext.chart.Chart/Ext.chart.Chart1.png Chart Axes} *  * ### 4. Configuring the Series *  * The final step in creating a simple Chart is to configure one or more {@link Ext.chart.series.Series Series}. * Series are responsible for the visual representation of the data points contained in the Store. * This example only has one Series: *  *     Ext.create('Ext.chart.Chart', { *         ... *         axes: [ *             ... *         ], *         series: [ *             { *                 type: 'line', *                 xField: 'date', *                 yField: 'temperature' *             } *         ] *     }); *      * This Series is a {@link Ext.chart.series.Line Line Series}, and it uses the "date" and "temperature" fields * from the "WeatherPoint" Models in the Store to plot its data points: *  * {@img Ext.chart.Chart/Ext.chart.Chart2.png Line Series} *  * See the [Line Charts Example](#!/example/charts/Charts.html) for a live demo. *  * ## Themes *  * The color scheme for a Chart can be easily changed using the {@link #cfg-theme theme} configuration option: *  *     Ext.create('Ext.chart.Chart', { *         ... *         theme: 'Green', *         ... *     }); *  * {@img Ext.chart.Chart/Ext.chart.Chart3.png Green Theme} *  * For more information on Charts please refer to the [Drawing and Charting Guide](#/guide/drawing_and_charting). *  */Ext.define('Ext.chart.Chart', {    /* Begin Definitions */    alias: 'widget.chart',    extend: 'Ext.draw.Component',        mixins: {        themeManager: 'Ext.chart.theme.Theme',        mask: 'Ext.chart.Mask',        navigation: 'Ext.chart.Navigation',        bindable: 'Ext.util.Bindable',        observable: 'Ext.util.Observable'    },    uses: [        'Ext.chart.series.Series'    ],        requires: [        'Ext.util.MixedCollection',        'Ext.data.StoreManager',        'Ext.chart.Legend',        'Ext.chart.theme.Base',        'Ext.chart.theme.Theme',        'Ext.util.DelayedTask'    ],    /* End Definitions */    // @private    viewBox: false,<span id='Ext-chart-Chart-cfg-theme'>    /**</span>     * @cfg {String} theme     * The name of the theme to be used. A theme defines the colors and other visual displays of tick marks     * on axis, text, title text, line colors, marker colors and styles, etc. Possible theme values are 'Base', 'Green',     * 'Sky', 'Red', 'Purple', 'Blue', 'Yellow' and also six category themes 'Category1' to 'Category6'. Default value     * is 'Base'.     */<span id='Ext-chart-Chart-cfg-animate'>    /**</span>     * @cfg {Boolean/Object} animate     * True for the default animation (easing: 'ease' and duration: 500) or a standard animation config     * object to be used for default chart animations. Defaults to false.     */    animate: false,<span id='Ext-chart-Chart-cfg-legend'>    /**</span>     * @cfg {Boolean/Object} legend     * True for the default legend display or a legend config object. Defaults to false.     */    legend: false,<span id='Ext-chart-Chart-cfg-insetPadding'>    /**</span>     * @cfg {Number} insetPadding     * The amount of inset padding in pixels for the chart. Defaults to 10.     */    insetPadding: 10,<span id='Ext-chart-Chart-cfg-enginePriority'>    /**</span>     * @cfg {String[]} enginePriority     * Defines the priority order for which Surface implementation to use. The first one supported by the current     * environment will be used. Defaults to `['Svg', 'Vml']`.     */    enginePriority: ['Svg', 'Vml'],<span id='Ext-chart-Chart-cfg-background'>    /**</span>     * @cfg {Object/Boolean} background     * The chart background. This can be a gradient object, image, or color. Defaults to false for no     * background. For example, if `background` were to be a color we could set the object as     *     *     background: {     *         //color string     *         fill: '#ccc'     *     }     *     * You can specify an image by using:     *     *     background: {     *         image: 'http://path.to.image/'     *     }     *     * Also you can specify a gradient by using the gradient object syntax:     *     *     background: {     *         gradient: {     *             id: 'gradientId',     *             angle: 45,     *             stops: {     *                 0: {     *                     color: '#555'     *                 }     *                 100: {     *                     color: '#ddd'     *                 }     *             }     *         }     *     }     */    background: false,<span id='Ext-chart-Chart-cfg-gradients'>    /**</span>     * @cfg {Object[]} gradients     * Define a set of gradients that can be used as `fill` property in sprites. The gradients array is an     * array of objects with the following properties:     *     * - **id** - string - The unique name of the gradient.     * - **angle** - number, optional - The angle of the gradient in degrees.     * - **stops** - object - An object with numbers as keys (from 0 to 100) and style objects as values     *     * For example:     *     *     gradients: [{     *         id: 'gradientId',     *         angle: 45,     *         stops: {     *             0: {     *                 color: '#555'     *             },     *             100: {     *                 color: '#ddd'     *             }     *         }     *     }, {     *         id: 'gradientId2',     *         angle: 0,     *         stops: {     *             0: {     *                 color: '#590'     *             },     *             20: {     *                 color: '#599'     *             },     *             100: {     *                 color: '#ddd'     *             }     *         }     *     }]     *     * Then the sprites can use `gradientId` and `gradientId2` by setting the fill attributes to those ids, for example:     *     *     sprite.setAttributes({     *         fill: 'url(#gradientId)'     *     }, true);     */<span id='Ext-chart-Chart-cfg-store'>    /**</span>     * @cfg {Ext.data.Store} store     * The store that supplies data to this chart.     */<span id='Ext-chart-Chart-cfg-series'>    /**</span>     * @cfg {Ext.chart.series.Series[]} series     * Array of {@link Ext.chart.series.Series Series} instances or config objects.  For example:     *      *     series: [{     *         type: 'column',     *         axis: 'left',     *         listeners: {     *             'afterrender': function() {     *                 console('afterrender');     *             }     *         },     *         xField: 'category',     *         yField: 'data1'     *     }]     */<span id='Ext-chart-Chart-cfg-axes'>    /**</span>     * @cfg {Ext.chart.axis.Axis[]} axes     * Array of {@link Ext.chart.axis.Axis Axis} instances or config objects.  For example:     *      *     axes: [{     *         type: 'Numeric',     *         position: 'left',     *         fields: ['data1'],     *         title: 'Number of Hits',     *         minimum: 0,     *         //one minor tick between two major ticks     *         minorTickSteps: 1     *     }, {     *         type: 'Category',     *         position: 'bottom',     *         fields: ['name'],     *         title: 'Month of the Year'     *     }]     */    constructor: function(config) {        var me = this,            defaultAnim;        config = Ext.apply({}, config);        me.initTheme(config.theme || me.theme);        if (me.gradients) {            Ext.apply(config, { gradients: me.gradients });        }        if (me.background) {            Ext.apply(config, { background: me.background });        }        if (config.animate) {            defaultAnim = {                easing: 'ease',                duration: 500            };            if (Ext.isObject(config.animate)) {                config.animate = Ext.applyIf(config.animate, defaultAnim);            }            else {                config.animate = defaultAnim;            }        }        me.mixins.observable.constructor.call(me, config);        if (config.enableMask) {            me.mixins.mask.constructor.call(me);        }        me.mixins.navigation.constructor.call(me);        me.callParent([config]);    },        getChartStore: function(){        return this.substore || this.store;    },    initComponent: function() {        var me = this,            axes,            series;        me.callParent();        me.addEvents(            'itemmousedown',            'itemmouseup',            'itemmouseover',            'itemmouseout',            'itemclick',            'itemdblclick',            'itemdragstart',            'itemdrag',            'itemdragend',<span id='Ext-chart-Chart-event-beforerefresh'>            /**</span>             * @event beforerefresh             * Fires before a refresh to the chart data is called. If the beforerefresh handler returns false the             * {@link #event-refresh} action will be cancelled.             * @param {Ext.chart.Chart} this             */            'beforerefresh',<span id='Ext-chart-Chart-event-refresh'>            /**</span>             * @event refresh             * Fires after the chart data has been refreshed.             * @param {Ext.chart.Chart} this             */            'refresh'        );        Ext.applyIf(me, {            zoom: {                width: 1,                height: 1,                x: 0,                y: 0            }        });        me.maxGutter = [0, 0];        me.store = Ext.data.StoreManager.lookup(me.store);        axes = me.axes;        me.axes = new Ext.util.MixedCollection(false, function(a) { return a.position; });        if (axes) {            me.axes.addAll(axes);        }        series = me.series;        me.series = new Ext.util.MixedCollection(false, function(a) { return a.seriesId || (a.seriesId = Ext.id(null, 'ext-chart-series-')); });        if (series) {            me.series.addAll(series);        }        if (me.legend !== false) {            me.legend = new Ext.chart.Legend(Ext.applyIf({chart:me}, me.legend));        }        me.on({            mousemove: me.onMouseMove,            mouseleave: me.onMouseLeave,            mousedown: me.onMouseDown,            mouseup: me.onMouseUp,            click: me.onClick,            dblclick: me.onDblClick,            scope: me        });    },    // @private overrides the component method to set the correct dimensions to the chart.    afterComponentLayout: function(width, height) {        var me = this;        if (Ext.isNumber(width) && Ext.isNumber(height)) {            if (width !== me.curWidth || height !== me.curHeight) {                me.curWidth = width;                me.curHeight = height;                me.redraw(true);            } else if (me.needsRedraw) {                delete me.needsRedraw;                me.redraw();            }        }        this.callParent(arguments);    },<span id='Ext-chart-Chart-method-redraw'>    /**</span>     * Redraws the chart. If animations are set this will animate the chart too.      * @param {Boolean} resize (optional) flag which changes the default origin points of the chart for animations.     */    redraw: function(resize) {        var me = this,            seriesItems = me.series.items,            seriesLen = seriesItems.length,            axesItems = me.axes.items,            axesLen = axesItems.length,            i,            chartBBox = me.chartBBox = {                x: 0,                y: 0,                height: me.curHeight,                width: me.curWidth            },            legend = me.legend;        me.surface.setSize(chartBBox.width, chartBBox.height);        // Instantiate Series and Axes        for (i = 0; i < seriesLen; i++) {            me.initializeSeries(seriesItems[i],i);        }        for (i = 0; i < axesLen; i++) {            me.initializeAxis(axesItems[i]);        }        //process all views (aggregated data etc) on stores        //before rendering.        for (i = 0; i < axesLen; i++) {            axesItems[i].processView();        }        for (i = 0; i < axesLen; i++) {            axesItems[i].drawAxis(true);        }        // Create legend if not already created        if (legend !== false && legend.visible) {            if (legend.update || !legend.created) {              legend.create();            }        }        // Place axes properly, including influence from each other        me.alignAxes();        // Reposition legend based on new axis alignment        if (legend !== false && legend.visible) {            legend.updatePosition();        }        // Find the max gutter        me.getMaxGutter();        // Draw axes and series        me.resizing = !!resize;        for (i = 0; i < axesLen; i++) {            axesItems[i].drawAxis();        }        for (i = 0; i < seriesLen; i++) {            me.drawCharts(seriesItems[i]);        }        me.resizing = false;    },    // @private set the store after rendering the chart.    afterRender: function() {        var ref,            me = this;        this.callParent();        if (me.categoryNames) {            me.setCategoryNames(me.categoryNames);        }        if (me.tipRenderer) {            ref = me.getFunctionRef(me.tipRenderer);            me.setTipRenderer(ref.fn, ref.scope);        }        me.bindStore(me.store, true);        me.refresh();        if (me.surface.engine === 'Vml') {            me.on('added', me.onAddedVml, me);            me.mon(Ext.container.Container.hierarchyEventSource, 'added', me.onContainerAddedVml, me);        }    },    // When using a vml surface we need to redraw when this chart or one of its ancestors    // is moved to a new container after render, because moving the vml chart causes the    // vml elements to go haywire, some displaing incorrectly or not displaying at all.    // This appears to be caused by the component being moved to the detached body element    // before being added to the new container.    onAddedVml: function() {        this.needsRedraw = true; // redraw after component layout    },    onContainerAddedVml: function(container) {        if (this.isDescendantOf(container)) {            this.needsRedraw = true; // redraw after component layout        }    },    // @private get x and y position of the mouse cursor.    getEventXY: function(e) {        var me = this,            box = this.surface.getRegion(),            pageXY = e.getXY(),            x = pageXY[0] - box.left,            y = pageXY[1] - box.top;        return [x, y];    },        onClick: function(e) {        this.handleClick('itemclick', e);    },        onDblClick: function(e) {        this.handleClick('itemdblclick', e);    },    // @private wrap the mouse down position to delegate the event to the series.    handleClick: function(name, e) {        var me = this,            position = me.getEventXY(e),            seriesItems = me.series.items,            i, ln, series,            item;        // Ask each series if it has an item corresponding to (not necessarily exactly        // on top of) the current mouse coords. Fire itemclick event.        for (i = 0, ln = seriesItems.length; i < ln; i++) {            series = seriesItems[i];            if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {                if (series.getItemForPoint) {                    item = series.getItemForPoint(position[0], position[1]);                    if (item) {                        series.fireEvent(name, item);                    }                }            }        }    },    // @private wrap the mouse down position to delegate the event to the series.    onMouseDown: function(e) {        var me = this,            position = me.getEventXY(e),            seriesItems = me.series.items,            i, ln, series,            item;        if (me.enableMask) {            me.mixins.mask.onMouseDown.call(me, e);        }        // Ask each series if it has an item corresponding to (not necessarily exactly        // on top of) the current mouse coords. Fire itemmousedown event.        for (i = 0, ln = seriesItems.length; i < ln; i++) {            series = seriesItems[i];            if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {                if (series.getItemForPoint) {                    item = series.getItemForPoint(position[0], position[1]);                    if (item) {                        series.fireEvent('itemmousedown', item);                    }                }            }        }    },    // @private wrap the mouse up event to delegate it to the series.    onMouseUp: function(e) {        var me = this,            position = me.getEventXY(e),            seriesItems = me.series.items,            i, ln, series,            item;        if (me.enableMask) {            me.mixins.mask.onMouseUp.call(me, e);        }        // Ask each series if it has an item corresponding to (not necessarily exactly        // on top of) the current mouse coords. Fire itemmouseup event.        for (i = 0, ln = seriesItems.length; i < ln; i++) {            series = seriesItems[i];            if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {                if (series.getItemForPoint) {                    item = series.getItemForPoint(position[0], position[1]);                    if (item) {                        series.fireEvent('itemmouseup', item);                    }                }            }        }    },    // @private wrap the mouse move event so it can be delegated to the series.    onMouseMove: function(e) {        var me = this,            position = me.getEventXY(e),            seriesItems = me.series.items,            i, ln, series,            item, last, storeItem, storeField;                if (me.enableMask) {            me.mixins.mask.onMouseMove.call(me, e);        }        // Ask each series if it has an item corresponding to (not necessarily exactly        // on top of) the current mouse coords. Fire itemmouseover/out events.        for (i = 0, ln = seriesItems.length; i < ln; i++) {            series = seriesItems[i];            if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {                if (series.getItemForPoint) {                    item = series.getItemForPoint(position[0], position[1]);                    last = series._lastItemForPoint;                    storeItem = series._lastStoreItem;                    storeField = series._lastStoreField;                    if (item !== last || item && (item.storeItem != storeItem || item.storeField != storeField)) {                        if (last) {                            series.fireEvent('itemmouseout', last);                            delete series._lastItemForPoint;                            delete series._lastStoreField;                            delete series._lastStoreItem;                        }                        if (item) {                            series.fireEvent('itemmouseover', item);                            series._lastItemForPoint = item;                            series._lastStoreItem = item.storeItem;                            series._lastStoreField = item.storeField;                        }                    }                }            } else {                last = series._lastItemForPoint;                if (last) {                    series.fireEvent('itemmouseout', last);                    delete series._lastItemForPoint;                    delete series._lastStoreField;                    delete series._lastStoreItem;                }            }        }    },    // @private handle mouse leave event.    onMouseLeave: function(e) {        var me = this,            seriesItems = me.series.items,            i, ln, series;        if (me.enableMask) {            me.mixins.mask.onMouseLeave.call(me, e);        }        for (i = 0, ln = seriesItems.length; i < ln; i++) {            series = seriesItems[i];            delete series._lastItemForPoint;        }    },    // @private buffered refresh for when we update the store    delayRefresh: function() {        var me = this;        if (!me.refreshTask) {            me.refreshTask = new Ext.util.DelayedTask(me.refresh, me);        }        me.refreshTask.delay(me.refreshBuffer);    },    // @private    refresh: function() {        var me = this;                    if (me.rendered && me.curWidth !== undefined && me.curHeight !== undefined) {            if (!me.isVisible(true) && !me.refreshPending) {                me.setShowListeners('mon');                me.refreshPending = true;                return;            }            if (me.fireEvent('beforerefresh', me) !== false) {                me.redraw();                me.fireEvent('refresh', me);            }        }    },        onShow: function(){        var me = this;        me.callParent(arguments);        if (me.refreshPending) {            me.delayRefresh();            me.setShowListeners('mun');        }        delete me.refreshPending;    },        setShowListeners: function(method){        var me = this;        me[method](Ext.container.Container.hierarchyEventSource, {            scope: me,            single: true,            show: me.forceRefresh,            expand: me.forceRefresh        });    },        forceRefresh: function(container) {        var me = this;        if (me.isDescendantOf(container) && me.refreshPending) {            // Add unbind here, because either expand/show could be fired,            // so be sure to unbind the listener that didn't            me.setShowListeners('mun');            me.delayRefresh();        }            delete me.refreshPending;    },    bindStore: function(store, initial) {        var me = this;        me.mixins.bindable.bindStore.apply(me, arguments);        if (me.store && !initial) {            me.refresh();        }    },        getStoreListeners: function() {        var refresh = this.refresh,            delayRefresh = this.delayRefresh;                    return {            refresh: refresh,            add: delayRefresh,            remove: delayRefresh,            update: delayRefresh,            clear: refresh        };    },    // @private Create Axis    initializeAxis: function(axis) {        var me = this,            chartBBox = me.chartBBox,            w = chartBBox.width,            h = chartBBox.height,            x = chartBBox.x,            y = chartBBox.y,            themeAttrs = me.themeAttrs,            config = {                chart: me            };        if (themeAttrs) {            config.axisStyle = Ext.apply({}, themeAttrs.axis);            config.axisLabelLeftStyle = Ext.apply({}, themeAttrs.axisLabelLeft);            config.axisLabelRightStyle = Ext.apply({}, themeAttrs.axisLabelRight);            config.axisLabelTopStyle = Ext.apply({}, themeAttrs.axisLabelTop);            config.axisLabelBottomStyle = Ext.apply({}, themeAttrs.axisLabelBottom);            config.axisTitleLeftStyle = Ext.apply({}, themeAttrs.axisTitleLeft);            config.axisTitleRightStyle = Ext.apply({}, themeAttrs.axisTitleRight);            config.axisTitleTopStyle = Ext.apply({}, themeAttrs.axisTitleTop);            config.axisTitleBottomStyle = Ext.apply({}, themeAttrs.axisTitleBottom);        }        switch (axis.position) {            case 'top':                Ext.apply(config, {                    length: w,                    width: h,                    x: x,                    y: y                });            break;            case 'bottom':                Ext.apply(config, {                    length: w,                    width: h,                    x: x,                    y: h                });            break;            case 'left':                Ext.apply(config, {                    length: h,                    width: w,                    x: x,                    y: h                });            break;            case 'right':                Ext.apply(config, {                    length: h,                    width: w,                    x: w,                    y: h                });            break;        }        if (!axis.chart) {            Ext.apply(config, axis);            axis = me.axes.replace(Ext.createByAlias('axis.' + axis.type.toLowerCase(), config));        }        else {            Ext.apply(axis, config);        }    },<span id='Ext-chart-Chart-method-alignAxes'>    /**</span>     * @private Adjust the dimensions and positions of each axis and the chart body area after accounting     * for the space taken up on each side by the axes and legend.     */    alignAxes: function() {        var me = this,            axes = me.axes,            axesItems = axes.items,            axis,            legend = me.legend,            edges = ['top', 'right', 'bottom', 'left'],            edge,            i, ln,            chartBBox,            insetPadding = me.insetPadding,            insets = {                top: insetPadding,                right: insetPadding,                bottom: insetPadding,                left: insetPadding            },            isVertical, bbox, pos;        function getAxis(edge) {            var i = axes.findIndex('position', edge);            return (i < 0) ? null : axes.getAt(i);        }        // Find the space needed by axes and legend as a positive inset from each edge        for (i = 0, ln = edges.length; i < ln; i++) {            edge = edges[i];            isVertical = (edge === 'left' || edge === 'right');            axis = getAxis(edge);            // Add legend size if it's on this edge            if (legend !== false) {                if (legend.position === edge) {                    bbox = legend.getBBox();                    insets[edge] += (isVertical ? bbox.width : bbox.height) + insets[edge];                }            }            // Add axis size if there's one on this edge only if it has been            //drawn before.            if (axis && axis.bbox) {                bbox = axis.bbox;                insets[edge] += (isVertical ? bbox.width : bbox.height);            }        }        // Build the chart bbox based on the collected inset values        chartBBox = {            x: insets.left,            y: insets.top,            width: me.curWidth - insets.left - insets.right,            height: me.curHeight - insets.top - insets.bottom        };        me.chartBBox = chartBBox;        // Go back through each axis and set its length and position based on the        // corresponding edge of the chartBBox        for (i = 0, ln = axesItems.length; i < ln; i++) {            axis = axesItems[i];            pos = axis.position;            isVertical = (pos === 'left' || pos === 'right');            axis.x = (pos === 'right' ? chartBBox.x + chartBBox.width : chartBBox.x);            axis.y = (pos === 'top' ? chartBBox.y : chartBBox.y + chartBBox.height);            axis.width = (isVertical ? chartBBox.width : chartBBox.height);            axis.length = (isVertical ? chartBBox.height : chartBBox.width);        }    },    // @private initialize the series.    initializeSeries: function(series, idx) {        var me = this,            themeAttrs = me.themeAttrs,            seriesObj, markerObj, seriesThemes, st,            markerThemes, colorArrayStyle = [],            i = 0, l,            config = {                chart: me,                seriesId: series.seriesId            };        if (themeAttrs) {            seriesThemes = themeAttrs.seriesThemes;            markerThemes = themeAttrs.markerThemes;            seriesObj = Ext.apply({}, themeAttrs.series);            markerObj = Ext.apply({}, themeAttrs.marker);            config.seriesStyle = Ext.apply(seriesObj, seriesThemes[idx % seriesThemes.length]);            config.seriesLabelStyle = Ext.apply({}, themeAttrs.seriesLabel);            config.markerStyle = Ext.apply(markerObj, markerThemes[idx % markerThemes.length]);            if (themeAttrs.colors) {                config.colorArrayStyle = themeAttrs.colors;            } else {                colorArrayStyle = [];                for (l = seriesThemes.length; i < l; i++) {                    st = seriesThemes[i];                    if (st.fill || st.stroke) {                        colorArrayStyle.push(st.fill || st.stroke);                    }                }                if (colorArrayStyle.length) {                    config.colorArrayStyle = colorArrayStyle;                }            }            config.seriesIdx = idx;        }        if (series instanceof Ext.chart.series.Series) {            Ext.apply(series, config);        } else {            Ext.applyIf(config, series);            series = me.series.replace(Ext.createByAlias('series.' + series.type.toLowerCase(), config));        }        if (series.initialize) {            series.initialize();        }    },    // @private    getMaxGutter: function() {        var me = this,            seriesItems = me.series.items,            i, ln, series,            maxGutter = [0, 0],            gutter;        for (i = 0, ln = seriesItems.length; i < ln; i++) {            series = seriesItems[i];            gutter = series.getGutters && series.getGutters() || [0, 0];            maxGutter[0] = Math.max(maxGutter[0], gutter[0]);            maxGutter[1] = Math.max(maxGutter[1], gutter[1]);        }        me.maxGutter = maxGutter;    },    // @private draw axis.    drawAxis: function(axis) {        axis.drawAxis();    },    // @private draw series.    drawCharts: function(series) {        series.triggerafterrender = false;        series.drawSeries();        if (!this.animate) {            series.fireEvent('afterrender');        }    },<span id='Ext-chart-Chart-method-save'>    /**</span>     * Saves the chart by either triggering a download or returning a string containing the chart data     * as SVG.  The action depends on the export type specified in the passed configuration. The chart     * will be exported using either the {@link Ext.draw.engine.SvgExporter} or the {@link Ext.draw.engine.ImageExporter}     * classes.     *     * Possible export types:     *     * - 'image/png'     * - 'image/jpeg',     * - 'image/svg+xml'     *     * If 'image/svg+xml' is specified, the SvgExporter will be used.      * If 'image/png' or 'image/jpeg' are specified, the ImageExporter will be used. This exporter     * must post the SVG data to a remote server to have the data processed, see the {@link Ext.draw.engine.ImageExporter}     * for more details.     *     * Example usage:     *     *     chart.save({     *          type: 'image/png'     *     });     *     * @param {Object} [config] The configuration to be passed to the exporter.     * See the export method for the appropriate exporter for the relevant     * configuration options     * @return {Object} See the return types for the appropriate exporter     */    save: function(config){        return Ext.draw.Surface.save(this.surface, config);    },    // @private remove gently.    destroy: function() {        Ext.destroy(this.surface);        this.bindStore(null);        this.callParent(arguments);    }});</pre></body></html>
 |