Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

Working with Charts

Save for later
  • 14 min read
  • 07 Sep 2015

article-image

In this article by Anand Dayalan, the author of the book Ext JS 6 By Example, he explores the different types of chart components in Ext JS and ends with a sample project called expense analyzer. The following topics will be covered:

  • Charts types
  • Bar and column charts
  • Area and line charts
  • Pie charts
  • 3D charts
  • The expense analyzer – a sample project

(For more resources related to this topic, see here.)


Charts


Ext JS is almost like a one-stop shop for all your JavaScript framework needs. Yes, Ext JS also includes charts with all other rich components you learned so far.

Chart types


There are three types of charts: cartesian, polar, and spacefilling.

The cartesian chart

Ext.chart.CartesianChart (xtype: cartesian or chart)


A cartesian chart has two directions: X and Y. By default, X is horizontal and Y is vertical. Charts that use the cartesian coordinates are column, bar, area, line, and scatter.

The polar chart

Ext.chart.PolarChart (xtype: polar)


These charts have two axes: angular and radial. Charts that plot values using the polar coordinates are pie and radar.

The spacefilling chart

Ext.chart.SpaceFillingChart (xtype: spacefilling)


These charts fill the complete area of the chart.

Bar and column charts


For bar and column charts, at the minimum, you need to provide a store, axes, and series.

The basic column chart


Let's start with a simple basic column chart. First, let's create a simple tree store with the inline hardcoded data as follows:

Ext.define('MyApp.model.Population', {
extend: 'Ext.data.Model',
fields: ['year', 'population']
});

Ext.define('MyApp.store.Population', {
extend: 'Ext.data.Store',
storeId: 'population',
model: 'MyApp.model.Population',
data: [
{ "year": "1610","population": 350 },
{ "year": "1650","population": 50368 },
{ "year": "1700", "population": 250888 },
{ "year": "1750","population": 1170760 },
{ "year": "1800","population": 5308483 },
{ "year": "1900","population": 76212168 },
{ "year": "1950","population": 151325798 },
{ "year": "2000","population": 281421906 },
{ "year": "2010","population": 308745538 },
]
});
var store = Ext.create("MyApp.store.Population");

Now, let's create the chart using Ext.chart.CartesianChart (xtype: cartesian or chart ) and use the store created above.

Ext.create('Ext.Container', {
renderTo: Ext.getBody(),
width: 500,
height: 500,
layout: 'fit',
items: [{
   xtype: 'chart',
   insetPadding: { top: 60, bottom: 20, left: 20, right: 40 },
   store: store,
   axes: [{
     type: 'numeric',
     position: 'left',
     grid: true,
     title: { text: 'Population in Millions', fontSize: 16 },
   }, {
     type: 'category',
     title: { text: 'Year', fontSize: 16 },
     position: 'bottom',
   }
   ],
   series: [{
     type: 'bar',
     xField: 'year',
     yField: ['population']
   }],
   sprites: {
     type: 'text',
     text: 'United States Population',
     font: '25px Helvetica',
     width: 120,
     height: 35,
     x: 100,
     y: 40
   }
} ]
});


Important things to note in the preceding code are axes, series, and sprite. Axes can be of one of the three types: numeric, time, and category.

In series, you can see that the type is set to bar. In Ext JS, to render the column or bar chart, you have to specify the type as bar, but if you want a bar chart, you have to set flipXY to true in the chart config.

The sprites config used here is quite straightforward. Sprites is optional, not a must. The grid property can be specified for both the axes, although we have specified it only for one axis here.

The insetPadding is used to specify the padding for the chart to render other information, such as the title. If we don't specify insetPadding, the title and other information may get overlapped with the chart.

The output of the preceding code is shown here:

working-charts-img-0

The bar chart


As mentioned before, in order to get the bar chart, you can just use the same code, but specify flipXP to true and change the positions of axes accordingly, as shown in the following code:

Ext.create('Ext.Container', {
renderTo: Ext.getBody(),
width: 500,
height: 500,
layout: 'fit',
items: [{
   xtype: 'chart',
   flipXY: true,
   insetPadding: { top: 60, bottom: 20, left: 20, right: 40 },
   store: store,
   axes: [{
     type: 'numeric',
     position: 'bottom',
     grid: true,
     title: { text: 'Population in Millions', fontSize: 16 },
   }, {
     type: 'category',
     title: { text: 'Year', fontSize: 16 },
     position: 'left',
   }
   ],
   series: [{
     type: 'bar',
     xField: 'year',
     yField: ['population']
   }
   ],
   sprites: {
     type: 'text',
     text: 'United States Population',
     font: '25px Helvetica',
     width: 120,
     height: 35,
     x: 100,
     y: 40
   }
} ]
});


The output of the preceding code is shown in the following screenshot:

working-charts-img-1

The stacked chart


Now, let's say you want to plot two values in each category in the column chart. You can either stack them or have two bar columns for each category.

Let's modify our column chart example to render a stacked column chart. For this, we need an additional numeric field in the store, and we need to specify two fields for yField in the series. You can stack more than two fields, but for this example, we will stack only two fields. Take a look at the following code:

Ext.define('MyApp.model.Population', {
extend: 'Ext.data.Model',
fields: ['year', 'total','slaves']
});

Ext.define('MyApp.store.Population', {
extend: 'Ext.data.Store',
storeId: 'population',
model: 'MyApp.model.Population',
data: [
{ "year": "1790", "total": 3.9, "slaves": 0.7 },
{ "year": "1800", "total": 5.3, "slaves": 0.9 },
{ "year": "1810", "total": 7.2, "slaves": 1.2 },
{ "year": "1820", "total": 9.6, "slaves": 1.5 },
{ "year": "1830", "total": 12.9, "slaves": 2 },
{ "year": "1840", "total": 17, "slaves": 2.5 },
{ "year": "1850", "total": 23.2, "slaves": 3.2 },
{ "year": "1860", "total": 31.4, "slaves": 4 },
]
});
var store = Ext.create("MyApp.store.Population");

Ext.create('Ext.Container', {
renderTo: Ext.getBody(),
width: 500,
height: 500,
layout: 'fit',
items: [{
   xtype: 'cartesian',
   store: store,
   insetPadding: { top: 60, bottom: 20, left: 20, right: 40 },
   axes: [{
     type: 'numeric',
     position: 'left',
     grid: true,
     title: { text: 'Population in Millions', fontSize: 16 },
   }, {
     type: 'category',
     title: { text: 'Year', fontSize: 16 },
     position: 'bottom',
   }
   ],
   series: [{
     type: 'bar',
     xField: 'year',
     yField: ['total','slaves']
   }
   ],
   sprites: {
     type: 'text',
     text: 'United States Slaves Distribution 1790 to 1860',
     font: '20px Helvetica',
     width: 120,
     height: 35,
     x: 60,
     y: 40
   }
}
]
});


The output of the stacked column chart is shown here:

working-charts-img-2

If you want to render multiple fields without stacking, then you can simply set the stacked property of the series to false to get the following output:

working-charts-img-3

There are so many options available in the chart. Let's take a look at some of the commonly used options:

  • tooltip: This can be added easily by setting a tooltip property in the series
  • legend: This can be rendered to any of the four sides of the chart by specifying the legend config
  • sprites: This can be an array if you want to specify multiple informations, such as header, footer, and so on


Here is the code for the same store configured with some advanced options:

Ext.create('Ext.Container', {
renderTo: Ext.getBody(),
width: 500,
height: 500,
layout: 'fit',
items: [{
   xtype: 'chart',
   legend: { docked: 'bottom' },
   insetPadding: { top: 60, bottom: 20, left: 20, right: 40 },
   store: store,
   axes: [{
     type: 'numeric',
     position: 'left',
     grid: true,
     title: { text: 'Population in Millions', fontSize: 16 },
     minimum: 0,

   }, {
     type: 'category',
     title: { text: 'Year', fontSize: 16 },
     position: 'bottom',
   }
   ],
   series: [{
     type: 'bar',
     xField: 'year',
     stacked: false,
     title: ['Total', 'Slaves'],
     yField: ['total', 'slaves'],
     tooltip: {
       trackMouse: true,
       style: 'background: #fff',
       renderer: function (storeItem, item) {
         this.setHtml('In ' + storeItem.get('year') + ' ' + item.field + ' population was ' + storeItem.get(item.field) + ' m');
       }
     }
   ],
   sprites: [{
     type: 'text',
     text: 'United States Slaves Distribution 1790 to 1860',
     font: '20px Helvetica',
     width: 120,
     height: 35,
     x: 60,
     y: 40
   },
   {
     type: 'text',
     text: 'Source: http://www.wikipedia.org',
     fontSize: 10,
     x: 12,
     y: 440
   }]
}]
});


The output with tooltip, legend, and footer is shown here:

working-charts-img-4

The 3D bar chart


If you simply change the type of the series to 3D bar instead of bar, you'll get the 3D column chart, as show in the following screenshot:

working-charts-img-5

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime

Area and line charts


Area and line charts are also cartesian charts.

The area chart


To render an area chart, simply replace the series in the previous example with the following code:

series: [{
type: 'area',
xField: 'year',
stacked: false,
title: ['Total','slaves'],
yField: ['total', 'slaves'],
style: {
   stroke: "#94ae0a",
   fillOpacity: 0.6,
}
}]


The output of the preceding code is shown here:

working-charts-img-6

Similar to the stacked column chart, you can have the stacked area chart as well by setting stacked to true in the series. If you set stacked to true in the preceding example, you'll get the following output:

 working-charts-img-7Figure 7.1


The line chart


To get the line chart shown in Figure 7.1, use the following series config in the preceding example instead:

series: [{
type: 'line',
xField: 'year',
title: ['Total'],
yField: ['total']
},
{
type: 'line',
xField: 'year',
title: ['Slaves'],
yField: ['slaves']
}],


working-charts-img-8

The pie chart


This is one of the frequently used charts in many applications and reporting tools. Ext.chart.PolarChart (xtype: polar) should be used to render a pie chart.

The basic pie chart


Specify the type as pie, and specify the angleField and label to render a basic pie chart, as as shown in the following code:

Ext.define('MyApp.store.Expense', {
extend: 'Ext.data.Store',
alias: 'store.expense',
fields: [ 'cat', 'spent'],
data: [
{ "cat": "Restaurant", "spent": 100},
{ "cat": "Travel", "spent": 150},
{ "cat": "Insurance", "spent": 500},
{ "cat": "Rent", "spent": 1000},
{ "cat": "Groceries", "spent": 400},
{ "cat": "Utilities", "spent": 300},
]
});
var store = Ext.create("MyApp.store.Expense");

Ext.create('Ext.Container', {
renderTo: Ext.getBody(),
width: 600,
height: 500,
layout: 'fit',
items: [{
   xtype: 'polar',
   legend: { docked: 'bottom' },
   insetPadding: { top: 100, bottom: 20, left: 20, right: 40 },
   store: store,
   series: [{
    type: 'pie',
     angleField: 'spent',
     label: {
       field: 'cat',
     },
     tooltip: {
       trackMouse: true,
       renderer: function (storeItem, item) {
         var value = ((parseFloat(storeItem.get('spent') / storeItem.store.sum('spent')) * 100.0).toFixed(2));
         this.setHtml(storeItem.get('cat') + ': ' + value + '%');
       }
     }
   }]
}]
});


working-charts-img-9

The donut chart


Just by setting the donut property of the series in the preceding example to 40, you'll get the following chart. Here, donut is the percentage of the radius of the hole compared to the entire disk:

working-charts-img-10

The 3D pie chart


In Ext JS 6, there were some improvements made to the 3D pie chart. The 3D pie chart in Ext JS 6 now supports the label and configurable 3D aspects, such as thickness, distortion, and so on.

Let's use the same model and store that was used in the pie chart example and create a 3D pie chart as follows:

Ext.create('Ext.Container', {
renderTo: Ext.getBody(),
width: 600,
height: 500,
layout: 'fit',
items: [{
   xtype: 'polar',
   legend: { docked: 'bottom' },
   insetPadding: { top: 100, bottom: 20, left: 80, right: 80 },
   store: store,
   series: [{
     type: 'pie3d',
     donut: 50,
     thickness: 70,
     distortion: 0.5,
    angleField: 'spent',
     label: { field: 'cat' },
     tooltip: {
       trackMouse: true,
       renderer: function (storeItem, item) {
         var value = ((parseFloat(storeItem.get('spent') / storeItem.store.sum('spent')) * 100.0).toFixed(2));
         this.setHtml(storeItem.get('cat') + ': ' + value + '%');
       }
     }
   }]
}]
});


The following image shows the output of the preceding code:

working-charts-img-11

The expense analyzer – a sample project


Now that you have learned the different kinds of charts available in Ext JS, let's use them to create a sample project called Expense Analyzer. The following screenshot shows the design of this sample project:

working-charts-img-12

working-charts-img-13

Let's use Sencha Cmd to scaffold our application. Run the following command in the terminal or command window:

sencha -sdk <path to SDK>/ext-6.0.0.415/ generate app EA ./expense-analyzer

Now, let's remove all the unwanted files and code and add some additional files to create this project. The final folder structure and some of the important files are shown in the following Figure 7.2:

The complete source code is not given in this article. Here, only some of the important files are shown. In between, some less important code has been truncated. The complete source is available at https://github.com/ananddayalan/extjs-by-example-expense-analyzer.

 working-charts-img-14Figure 7.2


Now, let's create the grid shown in the design. The following code is used to create the grid. This List view extends from Ext.grid.Panel, uses the expense store for the data, and has three columns:

Ext.define('EA.view.main.List', {
extend: 'Ext.grid.Panel',
xtype: 'mainlist',
maxHeight: 400,
requires: [ 'EA.store.Expense'],
title: 'Year to date expense by category',
store: { type: 'expense' },
columns: {
   defaults: { flex:1 },
   items: [{
     text: 'Category',
     dataIndex: 'cat'
   }, {
     formatter: "date('F')",
     text: 'Month',
     dataIndex: 'date'
   }, {
     text: 'Spent',
     dataIndex: 'spent'
   }]
}
});


Here, I have not used the pagination. The maxHeight is used to limit the height of the grid, and this enables the scroll bar as well because we have more records that won't fit the given maximum height of the grid.

The following code creates the expense store used in the preceding example. This is a simple store with the inline data. Here, we have not created a separate model and added fields directly in the store:

Ext.define('EA.store.Expense', {
extend: 'Ext.data.Store',
alias: 'store.expense',
storeId: 'expense',
fields: [{
   name:'date',
 type: 'date'
},
'cat',
'spent'
],
data: {
   items: [
   { "date": "1/1/2015", "cat": "Restaurant", "spent": 100 },
   { "date": "1/1/2015", "cat": "Travel", "spent": 22 },
   { "date": "1/1/2015", "cat": "Insurance", "spent": 343 },
   // Truncated code
]},
proxy: {
   type: 'memory',
   reader: {
     type: 'json',
     rootProperty: 'items'
   }
}
});


Next, let's create the bar chart shown in the design. In the bar chart, we will use another store called expensebyMonthStore, in which we'll populate data from the expense data store.

The following 3D bar chart has two types of axis: numeric and category. We have used the month part of the date field as a category. A renderer is used to render the month part of the date field:

Ext.define('EA.view.main.Bar', {
extend: 'Ext.chart.CartesianChart',

requires: ['Ext.chart.axis.Category',
'Ext.chart.series.Bar3D',
'Ext.chart.axis.Numeric',
'Ext.chart.interactions.ItemHighlight'],

xtype: 'mainbar',
height: 500,
padding: { top: 50, bottom: 20, left: 100, right: 100 },
legend: { docked: 'bottom' },
insetPadding: { top: 100, bottom: 20, left: 20, right: 40 },
store: { type: 'expensebyMonthStore' },
axes: [{
   type: 'numeric',
   position: 'left',
   grid: true,
   minimum: 0,
   title: {
     text: 'Spendings in $',
     fontSize: 16
   },
}, {
   type: 'category', position: 'bottom',
   title: {
     text: 'Month',
     fontSize: 16
   },
   label: {
     font: 'bold Arial',
     rotate: { degrees: 300 }
   },
   renderer: function (date) {
     return ["Jan", "Feb", "Mar", "Apr", "May"][date.getMonth()];
   }
} ],
series: [{
   type: 'bar3d',
   xField: 'date', stacked: false,
   title: ['Total'], yField: ['total']
}],
sprites: [{
   type: 'text',
   text: 'Expense by Month',
   font: '20px Helvetica',
   width: 120,
   height: 35,
   x: 60,
   y: 40
}]
});


Now, let's create the MyApp.model.ExpensebyMonth store used in the preceding bar chart view. This store will display the total amount spent in each month. This data is populated by grouping the expense store with the date field. Take a look at how the data property is configured to populate the data:

Ext.define('MyApp.model.ExpensebyMonth', {
extend: 'Ext.data.Model',
fields: [{name:'date', type: 'date'}, 'total']
});

Ext.define('MyApp.store.ExpensebyMonth', {
extend: 'Ext.data.Store',

alias: 'store.expensebyMonthStore',
model: 'MyApp.model.ExpensebyMonth',

data: (function () {
   var data = [];

   var expense = Ext.createByAlias('store.expense');
   expense.group('date');
   var groups = expense.getGroups();

   groups.each(function (group) {
     data.push({ date: group.config.groupKey, total: group.sum('spent') });
   });
   return data;
})()
});


Then, the following code is used to generate the pie chart. This chart uses the expense store, but only shows one selected month of data at a time. A drop-down box is added to the main view to select the month.

The beforerender is used to filter the expense store to show the data only for the month of January on the load:

Ext.define('EA.view.main.Pie', {
extend: 'Ext.chart.PolarChart',
requires: ['Ext.chart.series.Pie3D'],
xtype: 'mainpie',
height: 800,
legend: {
   docked: 'bottom'
},
insetPadding: {
   top: 100,
   bottom: 20,
   left: 80,
   right: 80
},
listeners: {
   beforerender: function () {
     var dateFiter = new Ext.util.Filter({
       filterFn: function(item) {
         return item.data.date.getMonth() ==0;
       }
     });
     Ext.getStore('expense').addFilter(dateFiter);
   }
},
store: {
   type: 'expense'
},
series: [{
   type: 'pie3d',
   donut: 50,
   thickness: 70,
   distortion: 0.5,
   angleField: 'spent',
   label: {
    field: 'cat',
   }
}]
});


So far, we have created the grid, the bar chart, the pie chart, and the stores required for this sample application. Now, we need to link them together in the main view. The following code shows the main view from the classic toolkit. The main view is simply a tab control and specifies what view to render for each tab:

Ext.define('EA.view.main.Main', {
extend: 'Ext.tab.Panel',
xtype: 'app-main',

requires: [
'Ext.plugin.Viewport',
'Ext.window.MessageBox',
'EA.view.main.MainController',
'EA.view.main.List',
'EA.view.main.Bar',
'EA.view.main.Pie'
],

controller: 'main',
autoScroll: true,
ui: 'navigation',
// Truncated code
items: [{
   title: 'Year to Date',
   iconCls: 'fa-bar-chart',
 items: [ {
     html: '<h3>Your average expense per month is: ' + Ext.createByAlias('store.expensebyMonthStore').average('total') + '</h3>',
     height: 70,
   },
   { xtype: 'mainlist'},
   { xtype: 'mainbar' }
   ]
},
{
   title: 'By Month',
   iconCls: 'fa-pie-chart',
   items: [{
     xtype: 'combo',
     value: 'Jan',
     fieldLabel: 'Select Month',
     store: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
     listeners: {
       select: 'onMonthSelect'
     }
   }, {
     xtype: 'mainpie'
   }]
}]
});

Summary


In this article, we looked at the different kinds of charts available in Ext JS. We also created a simple sample project called Expense Analyzer and used some of the concepts you learned in this article.

Resources for Article:





Further resources on this subject: