3 * Copyright(c) 2006-2010 Sencha Inc.
5 * http://www.sencha.com/license
8 * @class Ext.chart.Chart
9 * @extends Ext.FlashComponent
10 * The Ext.chart package provides the capability to visualize data with flash based charting.
11 * Each chart binds directly to an Ext.data.Store enabling automatic updates of the chart.
12 * To change the look and feel of a chart, see the {@link #chartStyle} and {@link #extraStyle} config options.
17 Ext.chart.Chart = Ext.extend(Ext.FlashComponent, {
21 * @cfg {String} backgroundColor
26 * @cfg {Object} chartStyle
27 * Sets styles for this chart. This contains default styling, so modifying this property will <b>override</b>
28 * the built in styles of the chart. Use {@link #extraStyle} to add customizations to the default styling.
32 animationEnabled: true,
59 * The url to load the chart from. This defaults to Ext.chart.Chart.CHART_URL, which should
60 * be modified to point to the local charts resource.
64 * @cfg {Object} extraStyle
65 * Contains extra styles that will be added or overwritten to the default chartStyle. Defaults to <tt>null</tt>.
66 * For a detailed list of the options available, visit the YUI Charts site
67 * at <a href="http://developer.yahoo.com/yui/charts/#basicstyles">http://developer.yahoo.com/yui/charts/#basicstyles</a><br/>
68 * Some of the options availabe:<br />
69 * <ul style="padding:5px;padding-left:16px;list-style-type:inherit;">
70 * <li><b>padding</b> - The space around the edge of the chart's contents. Padding does not increase the size of the chart.</li>
71 * <li><b>animationEnabled</b> - A Boolean value that specifies whether marker animations are enabled or not. Enabled by default.</li>
72 * <li><b>font</b> - An Object defining the font style to be used in the chart. Defaults to <tt>{ name: 'Tahoma', color: 0x444444, size: 11 }</tt><br/>
73 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
74 * <li><b>name</b> - font name</li>
75 * <li><b>color</b> - font color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>
76 * <li><b>size</b> - font size in points (numeric portion only, ie: 11)</li>
77 * <li><b>bold</b> - boolean</li>
78 * <li><b>italic</b> - boolean</li>
79 * <li><b>underline</b> - boolean</li>
82 * <li><b>border</b> - An object defining the border style around the chart. The chart itself will decrease in dimensions to accomodate the border.<br/>
83 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
84 * <li><b>color</b> - border color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>
85 * <li><b>size</b> - border size in pixels (numeric portion only, ie: 1)</li>
88 * <li><b>background</b> - An object defining the background style of the chart.<br/>
89 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
90 * <li><b>color</b> - border color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>
91 * <li><b>image</b> - an image URL. May be relative to the current document or absolute.</li>
94 * <li><b>legend</b> - An object defining the legend style<br/>
95 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
96 * <li><b>display</b> - location of the legend. Possible values are "none", "left", "right", "top", and "bottom".</li>
97 * <li><b>spacing</b> - an image URL. May be relative to the current document or absolute.</li>
98 * <li><b>padding, border, background, font</b> - same options as described above.</li>
100 * <li><b>dataTip</b> - An object defining the style of the data tip (tooltip).<br/>
101 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
102 * <li><b>padding, border, background, font</b> - same options as described above.</li>
104 * <li><b>xAxis and yAxis</b> - An object defining the style of the style of either axis.<br/>
105 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
106 * <li><b>color</b> - same option as described above.</li>
107 * <li><b>size</b> - same option as described above.</li>
108 * <li><b>showLabels</b> - boolean</li>
109 * <li><b>labelRotation</b> - a value in degrees from -90 through 90. Default is zero.</li>
111 * <li><b>majorGridLines and minorGridLines</b> - An object defining the style of the style of the grid lines.<br/>
112 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
113 * <li><b>color, size</b> - same options as described above.</li>
115 * <li><b>zeroGridLine</b> - An object defining the style of the style of the zero grid line.<br/>
116 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
117 * <li><b>color, size</b> - same options as described above.</li>
119 * <li><b>majorTicks and minorTicks</b> - An object defining the style of the style of ticks in the chart.<br/>
120 * <ul style="padding:5px;padding-left:26px;list-style-type:circle;">
121 * <li><b>color, size</b> - same options as described above.</li>
122 * <li><b>length</b> - the length of each tick in pixels extending from the axis.</li>
123 * <li><b>display</b> - how the ticks are drawn. Possible values are "none", "inside", "outside", and "cross".</li>
130 * @cfg {Object} seriesStyles
131 * Contains styles to apply to the series after a refresh. Defaults to <tt>null</tt>.
136 * @cfg {Boolean} disableCaching
137 * True to add a "cache buster" to the end of the chart url. Defaults to true for Opera and IE.
139 disableCaching: Ext.isIE || Ext.isOpera,
140 disableCacheParam: '_dc',
142 initComponent : function(){
143 Ext.chart.Chart.superclass.initComponent.call(this);
145 this.url = Ext.chart.Chart.CHART_URL;
147 if(this.disableCaching){
148 this.url = Ext.urlAppend(this.url, String.format('{0}={1}', this.disableCacheParam, new Date().getTime()));
159 * @event beforerefresh
160 * Fires before a refresh to the chart data is called. If the beforerefresh handler returns
161 * <tt>false</tt> the {@link #refresh} action will be cancelled.
162 * @param {Chart} this
167 * Fires after the chart data has been refreshed.
168 * @param {Chart} this
172 this.store = Ext.StoreMgr.lookup(this.store);
176 * Sets a single style value on the Chart instance.
178 * @param name {String} Name of the Chart style value to change.
179 * @param value {Object} New value to pass to the Chart style.
181 setStyle: function(name, value){
182 this.swf.setStyle(name, Ext.encode(value));
186 * Resets all styles on the Chart instance.
188 * @param styles {Object} Initializer for all Chart styles.
190 setStyles: function(styles){
191 this.swf.setStyles(Ext.encode(styles));
195 * Sets the styles on all series in the Chart.
197 * @param styles {Array} Initializer for all Chart series styles.
199 setSeriesStyles: function(styles){
200 this.seriesStyles = styles;
202 Ext.each(styles, function(style){
203 s.push(Ext.encode(style));
205 this.swf.setSeriesStyles(s);
208 setCategoryNames : function(names){
209 this.swf.setCategoryNames(names);
212 setLegendRenderer : function(fn, scope){
214 scope = scope || chart;
215 chart.removeFnProxy(chart.legendFnName);
216 chart.legendFnName = chart.createFnProxy(function(name){
217 return fn.call(scope, name);
219 chart.swf.setLegendLabelFunction(chart.legendFnName);
222 setTipRenderer : function(fn, scope){
224 scope = scope || chart;
225 chart.removeFnProxy(chart.tipFnName);
226 chart.tipFnName = chart.createFnProxy(function(item, index, series){
227 var record = chart.store.getAt(index);
228 return fn.call(scope, chart, record, index, series);
230 chart.swf.setDataTipFunction(chart.tipFnName);
233 setSeries : function(series){
234 this.series = series;
239 * Changes the data store bound to this chart and refreshes it.
240 * @param {Store} store The store to bind to this chart
242 bindStore : function(store, initial){
243 if(!initial && this.store){
244 if(store !== this.store && this.store.autoDestroy){
245 this.store.destroy();
247 this.store.un("datachanged", this.refresh, this);
248 this.store.un("add", this.delayRefresh, this);
249 this.store.un("remove", this.delayRefresh, this);
250 this.store.un("update", this.delayRefresh, this);
251 this.store.un("clear", this.refresh, this);
255 store = Ext.StoreMgr.lookup(store);
258 datachanged: this.refresh,
259 add: this.delayRefresh,
260 remove: this.delayRefresh,
261 update: this.delayRefresh,
266 if(store && !initial){
271 onSwfReady : function(isReset){
272 Ext.chart.Chart.superclass.onSwfReady.call(this, isReset);
274 this.swf.setType(this.type);
277 this.setStyles(Ext.apply({}, this.extraStyle, this.chartStyle));
280 if(this.categoryNames){
281 this.setCategoryNames(this.categoryNames);
284 if(this.tipRenderer){
285 ref = this.getFunctionRef(this.tipRenderer);
286 this.setTipRenderer(ref.fn, ref.scope);
288 if(this.legendRenderer){
289 ref = this.getFunctionRef(this.legendRenderer);
290 this.setLegendRenderer(ref.fn, ref.scope);
293 this.bindStore(this.store, true);
295 this.refresh.defer(10, this);
298 delayRefresh : function(){
299 if(!this.refreshTask){
300 this.refreshTask = new Ext.util.DelayedTask(this.refresh, this);
302 this.refreshTask.delay(this.refreshBuffer);
305 refresh : function(){
306 if(this.fireEvent('beforerefresh', this) !== false){
307 var styleChanged = false;
308 // convert the store data into something YUI charts can understand
309 var data = [], rs = this.store.data.items;
310 for(var j = 0, len = rs.length; j < len; j++){
311 data[j] = rs[j].data;
313 //make a copy of the series definitions so that we aren't
314 //editing them directly.
315 var dataProvider = [];
317 var currentSeries = null;
320 seriesCount = this.series.length;
321 for(i = 0; i < seriesCount; i++){
322 currentSeries = this.series[i];
323 var clonedSeries = {};
324 for(var prop in currentSeries){
325 if(prop == "style" && currentSeries.style !== null){
326 clonedSeries.style = Ext.encode(currentSeries.style);
328 //we don't want to modify the styles again next time
329 //so null out the style property.
330 // this causes issues
331 // currentSeries.style = null;
333 clonedSeries[prop] = currentSeries[prop];
336 dataProvider.push(clonedSeries);
341 for(i = 0; i < seriesCount; i++){
342 currentSeries = dataProvider[i];
343 if(!currentSeries.type){
344 currentSeries.type = this.type;
346 currentSeries.dataProvider = data;
349 dataProvider.push({type: this.type, dataProvider: data});
351 this.swf.setDataProvider(dataProvider);
352 if(this.seriesStyles){
353 this.setSeriesStyles(this.seriesStyles);
355 this.fireEvent('refresh', this);
360 createFnProxy : function(fn){
361 var fnName = 'extFnProxy' + (++Ext.chart.Chart.PROXY_FN_ID);
362 Ext.chart.Chart.proxyFunction[fnName] = fn;
363 return 'Ext.chart.Chart.proxyFunction.' + fnName;
367 removeFnProxy : function(fn){
368 if(!Ext.isEmpty(fn)){
369 fn = fn.replace('Ext.chart.Chart.proxyFunction.', '');
370 delete Ext.chart.Chart.proxyFunction[fn];
375 getFunctionRef : function(val){
376 if(Ext.isFunction(val)){
384 scope: val.scope || this
390 onDestroy: function(){
391 if (this.refreshTask && this.refreshTask.cancel){
392 this.refreshTask.cancel();
394 Ext.chart.Chart.superclass.onDestroy.call(this);
395 this.bindStore(null);
396 this.removeFnProxy(this.tipFnName);
397 this.removeFnProxy(this.legendFnName);
400 Ext.reg('chart', Ext.chart.Chart);
401 Ext.chart.Chart.PROXY_FN_ID = 0;
402 Ext.chart.Chart.proxyFunction = {};
405 * Sets the url to load the chart from. This should be set to a local resource.
409 Ext.chart.Chart.CHART_URL = 'http:/' + '/yui.yahooapis.com/2.8.2/build/charts/assets/charts.swf';
412 * @class Ext.chart.PieChart
413 * @extends Ext.chart.Chart
417 Ext.chart.PieChart = Ext.extend(Ext.chart.Chart, {
420 onSwfReady : function(isReset){
421 Ext.chart.PieChart.superclass.onSwfReady.call(this, isReset);
423 this.setDataField(this.dataField);
424 this.setCategoryField(this.categoryField);
427 setDataField : function(field){
428 this.dataField = field;
429 this.swf.setDataField(field);
432 setCategoryField : function(field){
433 this.categoryField = field;
434 this.swf.setCategoryField(field);
437 Ext.reg('piechart', Ext.chart.PieChart);
440 * @class Ext.chart.CartesianChart
441 * @extends Ext.chart.Chart
443 * @xtype cartesianchart
445 Ext.chart.CartesianChart = Ext.extend(Ext.chart.Chart, {
446 onSwfReady : function(isReset){
447 Ext.chart.CartesianChart.superclass.onSwfReady.call(this, isReset);
450 this.setXField(this.xField);
453 this.setYField(this.yField);
456 this.setXAxis(this.xAxis);
459 this.setXAxes(this.xAxes);
462 this.setYAxis(this.yAxis);
465 this.setYAxes(this.yAxes);
467 if(Ext.isDefined(this.constrainViewport)){
468 this.swf.setConstrainViewport(this.constrainViewport);
472 setXField : function(value){
474 this.swf.setHorizontalField(value);
477 setYField : function(value){
479 this.swf.setVerticalField(value);
482 setXAxis : function(value){
483 this.xAxis = this.createAxis('xAxis', value);
484 this.swf.setHorizontalAxis(this.xAxis);
487 setXAxes : function(value){
489 for(var i = 0; i < value.length; i++) {
490 axis = this.createAxis('xAxis' + i, value[i]);
491 this.swf.setHorizontalAxis(axis);
495 setYAxis : function(value){
496 this.yAxis = this.createAxis('yAxis', value);
497 this.swf.setVerticalAxis(this.yAxis);
500 setYAxes : function(value){
502 for(var i = 0; i < value.length; i++) {
503 axis = this.createAxis('yAxis' + i, value[i]);
504 this.swf.setVerticalAxis(axis);
508 createAxis : function(axis, value){
509 var o = Ext.apply({}, value),
514 old = this[axis].labelFunction;
515 this.removeFnProxy(old);
516 this.labelFn.remove(old);
519 ref = this.getFunctionRef(o.labelRenderer);
520 o.labelFunction = this.createFnProxy(function(v){
521 return ref.fn.call(ref.scope, v);
523 delete o.labelRenderer;
524 this.labelFn.push(o.labelFunction);
526 if(axis.indexOf('xAxis') > -1 && o.position == 'left'){
527 o.position = 'bottom';
532 onDestroy : function(){
533 Ext.chart.CartesianChart.superclass.onDestroy.call(this);
534 Ext.each(this.labelFn, function(fn){
535 this.removeFnProxy(fn);
539 Ext.reg('cartesianchart', Ext.chart.CartesianChart);
542 * @class Ext.chart.LineChart
543 * @extends Ext.chart.CartesianChart
547 Ext.chart.LineChart = Ext.extend(Ext.chart.CartesianChart, {
550 Ext.reg('linechart', Ext.chart.LineChart);
553 * @class Ext.chart.ColumnChart
554 * @extends Ext.chart.CartesianChart
558 Ext.chart.ColumnChart = Ext.extend(Ext.chart.CartesianChart, {
561 Ext.reg('columnchart', Ext.chart.ColumnChart);
564 * @class Ext.chart.StackedColumnChart
565 * @extends Ext.chart.CartesianChart
567 * @xtype stackedcolumnchart
569 Ext.chart.StackedColumnChart = Ext.extend(Ext.chart.CartesianChart, {
572 Ext.reg('stackedcolumnchart', Ext.chart.StackedColumnChart);
575 * @class Ext.chart.BarChart
576 * @extends Ext.chart.CartesianChart
580 Ext.chart.BarChart = Ext.extend(Ext.chart.CartesianChart, {
583 Ext.reg('barchart', Ext.chart.BarChart);
586 * @class Ext.chart.StackedBarChart
587 * @extends Ext.chart.CartesianChart
589 * @xtype stackedbarchart
591 Ext.chart.StackedBarChart = Ext.extend(Ext.chart.CartesianChart, {
594 Ext.reg('stackedbarchart', Ext.chart.StackedBarChart);
599 * @class Ext.chart.Axis
600 * Defines a CartesianChart's vertical or horizontal axis.
603 Ext.chart.Axis = function(config){
604 Ext.apply(this, config);
607 Ext.chart.Axis.prototype =
618 * The direction in which the axis is drawn. May be "horizontal" or "vertical".
620 * @property orientation
623 orientation: "horizontal",
626 * If true, the items on the axis will be drawn in opposite direction.
634 * A string reference to the globally-accessible function that may be called to
635 * determine each of the label values for this axis.
637 * @property labelFunction
643 * If true, labels that overlap previously drawn labels on the axis will be hidden.
645 * @property hideOverlappingLabels
648 hideOverlappingLabels: true,
651 * The space, in pixels, between labels on an axis.
653 * @property labelSpacing
660 * @class Ext.chart.NumericAxis
661 * @extends Ext.chart.Axis
662 * A type of axis whose units are measured in numeric values.
665 Ext.chart.NumericAxis = Ext.extend(Ext.chart.Axis, {
669 * The minimum value drawn by the axis. If not set explicitly, the axis
670 * minimum will be calculated automatically.
678 * The maximum value drawn by the axis. If not set explicitly, the axis
679 * maximum will be calculated automatically.
687 * The spacing between major intervals on this axis.
689 * @property majorUnit
695 * The spacing between minor intervals on this axis.
697 * @property minorUnit
703 * If true, the labels, ticks, gridlines, and other objects will snap to the
704 * nearest major or minor unit. If false, their position will be based on
707 * @property snapToUnits
713 * If true, and the bounds are calculated automatically, either the minimum
714 * or maximum will be set to zero.
716 * @property alwaysShowZero
719 alwaysShowZero: true,
722 * The scaling algorithm to use on this axis. May be "linear" or
731 * Indicates whether to round the major unit.
733 * @property roundMajorUnit
736 roundMajorUnit: true,
739 * Indicates whether to factor in the size of the labels when calculating a
742 * @property calculateByLabelSize
745 calculateByLabelSize: true,
748 * Indicates the position of the axis relative to the chart
756 * Indicates whether to extend maximum beyond data's maximum to the nearest
759 * @property adjustMaximumByMajorUnit
762 adjustMaximumByMajorUnit: true,
765 * Indicates whether to extend the minimum beyond data's minimum to the
768 * @property adjustMinimumByMajorUnit
771 adjustMinimumByMajorUnit: true
776 * @class Ext.chart.TimeAxis
777 * @extends Ext.chart.Axis
778 * A type of axis whose units are measured in time-based values.
781 Ext.chart.TimeAxis = Ext.extend(Ext.chart.Axis, {
785 * The minimum value drawn by the axis. If not set explicitly, the axis
786 * minimum will be calculated automatically.
794 * The maximum value drawn by the axis. If not set explicitly, the axis
795 * maximum will be calculated automatically.
803 * The spacing between major intervals on this axis.
805 * @property majorUnit
811 * The time unit used by the majorUnit.
813 * @property majorTimeUnit
819 * The spacing between minor intervals on this axis.
821 * @property majorUnit
827 * The time unit used by the minorUnit.
829 * @property majorTimeUnit
835 * If true, the labels, ticks, gridlines, and other objects will snap to the
836 * nearest major or minor unit. If false, their position will be based on
839 * @property snapToUnits
845 * Series that are stackable will only stack when this value is set to true.
847 * @property stackingEnabled
850 stackingEnabled: false,
853 * Indicates whether to factor in the size of the labels when calculating a
856 * @property calculateByLabelSize
859 calculateByLabelSize: true
864 * @class Ext.chart.CategoryAxis
865 * @extends Ext.chart.Axis
866 * A type of axis that displays items in categories.
869 Ext.chart.CategoryAxis = Ext.extend(Ext.chart.Axis, {
873 * A list of category names to display along this axis.
875 * @property categoryNames
881 * Indicates whether or not to calculate the number of categories (ticks and
882 * labels) when there is not enough room to display all labels on the axis.
883 * If set to true, the axis will determine the number of categories to plot.
884 * If not, all categories will be plotted.
886 * @property calculateCategoryCount
889 calculateCategoryCount: false
894 * @class Ext.chart.Series
895 * Series class for the charts widget.
898 Ext.chart.Series = function(config) { Ext.apply(this, config); };
900 Ext.chart.Series.prototype =
903 * The type of series.
911 * The human-readable name of the series.
913 * @property displayName
920 * @class Ext.chart.CartesianSeries
921 * @extends Ext.chart.Series
922 * CartesianSeries class for the charts widget.
925 Ext.chart.CartesianSeries = Ext.extend(Ext.chart.Series, {
927 * The field used to access the x-axis value from the items from the data
936 * The field used to access the y-axis value from the items from the data
945 * False to not show this series in the legend. Defaults to <tt>true</tt>.
947 * @property showInLegend
953 * Indicates which axis the series will bind to
962 * @class Ext.chart.ColumnSeries
963 * @extends Ext.chart.CartesianSeries
964 * ColumnSeries class for the charts widget.
967 Ext.chart.ColumnSeries = Ext.extend(Ext.chart.CartesianSeries, {
972 * @class Ext.chart.LineSeries
973 * @extends Ext.chart.CartesianSeries
974 * LineSeries class for the charts widget.
977 Ext.chart.LineSeries = Ext.extend(Ext.chart.CartesianSeries, {
982 * @class Ext.chart.BarSeries
983 * @extends Ext.chart.CartesianSeries
984 * BarSeries class for the charts widget.
987 Ext.chart.BarSeries = Ext.extend(Ext.chart.CartesianSeries, {
993 * @class Ext.chart.PieSeries
994 * @extends Ext.chart.Series
995 * PieSeries class for the charts widget.
998 Ext.chart.PieSeries = Ext.extend(Ext.chart.Series, {