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
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:
10 <pre><code>
11 Ext.create('Ext.chart.Chart', {
12 renderTo: Ext.getBody(),
22 axes: [ ...some axes options... ],
23 series: [ ...some series options... ]
25 </code></pre>
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).
36 Ext.define('Ext.chart.Chart', {
38 /* Begin Definitions */
40 alias: 'widget.chart',
42 extend: 'Ext.draw.Component',
45 themeManager: 'Ext.chart.theme.Theme',
46 mask: 'Ext.chart.Mask',
47 navigation: 'Ext.chart.Navigation'
51 'Ext.util.MixedCollection',
52 'Ext.data.StoreManager',
54 'Ext.util.DelayedTask'
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'.
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.
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.
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.
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.
90 enginePriority: ['Svg', 'Vml'],
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.
96 * For example, if `background` were to be a color we could set the object as
98 <pre><code>
103 </code></pre>
105 You can specify an image by using:
107 <pre><code>
109 image: 'http://path.to.image/'
111 </code></pre>
113 Also you can specify a gradient by using the gradient object syntax:
115 <pre><code>
130 </code></pre>
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:
139 * <li><strong>id</strong> - string - The unique name of the gradient.</li>
140 * <li><strong>angle</strong> - number, optional - The angle of the gradient in degrees.</li>
141 * <li><strong>stops</strong> - object - An object with numbers as keys (from 0 to 100) and style objects
142 * as values</li>
148 <pre><code>
175 </code></pre>
177 Then the sprites can use `gradientId` and `gradientId2` by setting the fill attributes to those ids, for example:
179 <pre><code>
180 sprite.setAttributes({
181 fill: 'url(#gradientId)'
183 </code></pre>
188 constructor: function(config) {
191 me.initTheme(config.theme || me.theme);
193 Ext.apply(config, { gradients: me.gradients });
196 Ext.apply(config, { background: me.background });
198 if (config.animate) {
203 if (Ext.isObject(config.animate)) {
204 config.animate = Ext.applyIf(config.animate, defaultAnim);
207 config.animate = defaultAnim;
210 me.mixins.mask.constructor.call(me, config);
211 me.mixins.navigation.constructor.call(me, config);
212 me.callParent([config]);
215 initComponent: function() {
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 * <tt>false</tt> the {@link #refresh} action will be cancelled.
234 * @param {Chart} this
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
252 me.maxGutter = [0, 0];
253 me.store = Ext.data.StoreManager.lookup(me.store);
255 me.axes = Ext.create('Ext.util.MixedCollection', false, function(a) { return a.position; });
257 me.axes.addAll(axes);
260 me.series = Ext.create('Ext.util.MixedCollection', false, function(a) { return a.seriesId || (a.seriesId = Ext.id(null, 'ext-chart-series-')); });
262 me.series.addAll(series);
264 if (me.legend !== false) {
265 me.legend = Ext.create('Ext.chart.Legend', Ext.applyIf({chart:me}, me.legend));
269 mousemove: me.onMouseMove,
270 mouseleave: me.onMouseLeave,
271 mousedown: me.onMouseDown,
272 mouseup: me.onMouseUp,
277 // @private overrides the component method to set the correct dimensions to the chart.
278 afterComponentLayout: function(width, height) {
280 if (Ext.isNumber(width) && Ext.isNumber(height)) {
282 me.curHeight = height;
285 this.callParent(arguments);
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.
292 redraw: function(resize) {
294 chartBBox = me.chartBBox = {
297 height: me.curHeight,
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
307 me.axes.each(function(axis) {
310 me.axes.each(function(axis) {
314 // Create legend if not already created
315 if (legend !== false) {
319 // Place axes properly, including influence from each other
322 // Reposition legend based on new axis alignment
323 if (me.legend !== false) {
324 legend.updatePosition();
327 // Find the max gutter
330 // Draw axes and series
331 me.resizing = !!resize;
333 me.axes.each(me.drawAxis, me);
334 me.series.each(me.drawCharts, me);
338 // @private set the store after rendering the chart.
339 afterRender: function() {
344 if (me.categoryNames) {
345 me.setCategoryNames(me.categoryNames);
348 if (me.tipRenderer) {
349 ref = me.getFunctionRef(me.tipRenderer);
350 me.setTipRenderer(ref.fn, ref.scope);
352 me.bindStore(me.store, true);
356 // @private get x and y position of the mouse cursor.
357 getEventXY: function(e) {
359 box = this.surface.getRegion(),
361 x = pageXY[0] - box.left,
362 y = pageXY[1] - box.top;
366 // @private wrap the mouse down position to delegate the event to the series.
367 onClick: function(e) {
369 position = me.getEventXY(e),
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]);
379 series.fireEvent('itemclick', item);
386 // @private wrap the mouse down position to delegate the event to the series.
387 onMouseDown: function(e) {
389 position = me.getEventXY(e),
393 me.mixins.mask.onMouseDown.call(me, e);
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]);
402 series.fireEvent('itemmousedown', item);
409 // @private wrap the mouse up event to delegate it to the series.
410 onMouseUp: function(e) {
412 position = me.getEventXY(e),
416 me.mixins.mask.onMouseUp.call(me, e);
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]);
425 series.fireEvent('itemmouseup', item);
432 // @private wrap the mouse move event so it can be delegated to the series.
433 onMouseMove: function(e) {
435 position = me.getEventXY(e),
436 item, last, storeItem, storeField;
439 me.mixins.mask.onMouseMove.call(me, e);
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;
452 if (item !== last || item && (item.storeItem != storeItem || item.storeField != storeField)) {
454 series.fireEvent('itemmouseout', last);
455 delete series._lastItemForPoint;
456 delete series._lastStoreField;
457 delete series._lastStoreItem;
460 series.fireEvent('itemmouseover', item);
461 series._lastItemForPoint = item;
462 series._lastStoreItem = item.storeItem;
463 series._lastStoreField = item.storeField;
468 last = series._lastItemForPoint;
470 series.fireEvent('itemmouseout', last);
471 delete series._lastItemForPoint;
472 delete series._lastStoreField;
473 delete series._lastStoreItem;
479 // @private handle mouse leave event.
480 onMouseLeave: function(e) {
483 me.mixins.mask.onMouseLeave.call(me, e);
485 me.series.each(function(series) {
486 delete series._lastItemForPoint;
490 // @private buffered refresh for when we update the store
491 delayRefresh: function() {
493 if (!me.refreshTask) {
494 me.refreshTask = Ext.create('Ext.util.DelayedTask', me.refresh, me);
496 me.refreshTask.delay(me.refreshBuffer);
500 refresh: function() {
502 if (me.rendered && me.curWidth != undefined && me.curHeight != undefined) {
503 if (me.fireEvent('beforerefresh', me) !== false) {
505 me.fireEvent('refresh', me);
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
514 bindStore: function(store, initial) {
516 if (!initial && me.store) {
517 if (store !== me.store && me.store.autoDestroy) {
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);
529 store = Ext.data.StoreManager.lookup(store);
532 datachanged: me.refresh,
533 add: me.delayRefresh,
534 remove: me.delayRefresh,
535 update: me.delayRefresh,
540 if (store && !initial) {
545 // @private Create Axis
546 initializeAxis: function(axis) {
548 chartBBox = me.chartBBox,
550 h = chartBBox.height,
553 themeAttrs = me.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);
568 switch (axis.position) {
603 Ext.apply(config, axis);
604 axis = me.axes.replace(Ext.createByAlias('axis.' + axis.type.toLowerCase(), config));
607 Ext.apply(axis, config);
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.
616 alignAxes: function() {
620 edges = ['top', 'right', 'bottom', 'left'],
622 insetPadding = me.insetPadding,
626 bottom: insetPadding,
630 function getAxis(edge) {
631 var i = axes.findIndex('position', edge);
632 return (i < 0) ? null : axes.getAt(i);
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),
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];
649 // Add axis size if there's one on this edge only if it has been
651 if (axis && axis.bbox) {
653 insets[edge] += (isVertical ? bbox.width : bbox.height);
656 // Build the chart bbox based on the collected inset values
660 width: me.curWidth - insets.left - insets.right,
661 height: me.curHeight - insets.top - insets.bottom
663 me.chartBBox = chartBBox;
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');
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);
678 // @private initialize the series.
679 initializeSeries: function(series, idx) {
681 themeAttrs = me.themeAttrs,
682 seriesObj, markerObj, seriesThemes, st,
683 markerThemes, colorArrayStyle = [],
687 seriesId: series.seriesId
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;
700 colorArrayStyle = [];
701 for (l = seriesThemes.length; i < l; i++) {
702 st = seriesThemes[i];
703 if (st.fill || st.stroke) {
704 colorArrayStyle.push(st.fill || st.stroke);
707 if (colorArrayStyle.length) {
708 config.colorArrayStyle = colorArrayStyle;
711 config.seriesIdx = idx;
713 if (series instanceof Ext.chart.series.Series) {
714 Ext.apply(series, config);
716 Ext.applyIf(config, series);
717 series = me.series.replace(Ext.createByAlias('series.' + series.type.toLowerCase(), config));
719 if (series.initialize) {
725 getMaxGutter: function() {
728 me.series.each(function(s) {
729 var gutter = s.getGutters && s.getGutters() || [0, 0];
730 maxGutter[0] = Math.max(maxGutter[0], gutter[0]);
731 maxGutter[1] = Math.max(maxGutter[1], gutter[1]);
733 me.maxGutter = maxGutter;
736 // @private draw axis.
737 drawAxis: function(axis) {
741 // @private draw series.
742 drawCharts: function(series) {
743 series.triggerafterrender = false;
746 series.fireEvent('afterrender');
750 // @private remove gently.
751 destroy: function() {
752 this.surface.destroy();
753 this.bindStore(null);
754 this.callParent(arguments);
757 </pre></pre></body></html>