Ext JS Charts — Bar, Line, Pie, and Interactive Data Visualization
In this tutorial, you will learn about Ext JS Charts. We cover key concepts, practical examples, and best practices to help you master this topic.
Ext JS Charts provide data visualization with bar, line, pie, scatter, radar, and area series types, supporting interactive tooltips, legends, axis configuration, themes, and Store binding.
What You'll Learn
- Creating bar, line, and pie charts
- Configuring axes, legends, and series
- Binding Charts to Stores with live data
- Chart interactions and tooltips
- Chart themes and styling
Why It Matters
Data visualization turns raw numbers into insights. Enterprise dashboards require charts that update with live data, support drill-down interaction, and render consistently across browsers. Ext JS Charts render using Canvas or SVG with a unified API.
Real-World Use
A sales dashboard with a bar chart showing monthly revenue, a line chart tracking user growth over time, a pie chart breaking down sales by category, and a scatter plot mapping customer spend vs frequency — all bound to live data Stores.
Chart Architecture
flowchart TD
A[Chart Panel] --> B[Axes]
A --> C[Series]
A --> D[Legend]
A --> E[Interactions]
B --> F[Category Axis]
B --> G[Numeric Axis]
B --> H[Time Axis]
C --> I[Bar Series]
C --> J[Line Series]
C --> K[Pie Series]
E --> L[Tooltip]
E --> M[Highlight]
E --> N[Zoom]
style A fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px
Bar Chart
Ext.create('Ext.chart.CartesianChart', {
title: 'Monthly Revenue',
width: 700,
height: 400,
renderTo: Ext.getBody(),
store: {
fields: ['month', 'revenue'],
data: [
{ month: 'Jan', revenue: 45000 },
{ month: 'Feb', revenue: 52000 },
{ month: 'Mar', revenue: 48000 },
{ month: 'Apr', revenue: 61000 },
{ month: 'May', revenue: 58000 },
{ month: 'Jun', revenue: 72000 }
]
},
axes: [{
type: 'category',
position: 'bottom',
fields: ['month'],
title: 'Month'
}, {
type: 'numeric',
position: 'left',
fields: ['revenue'],
title: 'Revenue ($)',
grid: true,
minimum: 0,
renderer: function(axis, value) {
return '$' + Ext.util.Format.number(value, '0,000');
}
}],
series: [{
type: 'bar',
xField: 'month',
yField: 'revenue',
style: {
fill: '#4a90d9',
stroke: '#2c5f9a',
strokeWidth: 1
},
highlight: {
fillStyle: '#ff9800',
strokeStyle: '#e65100'
},
label: {
display: 'insideEnd',
field: 'revenue',
renderer: function(value) {
return '$' + Ext.util.Format.number(value, '0,000');
}
}
}],
interactions: [{
type: 'itemhighlight',
// Hover to highlight
}, {
type: 'iteminfo',
// Click to show tooltip
listeners: {
show: function(interaction, item, infoPanel) {
var record = item.record;
infoPanel.setHtml(
'<b>' + record.get('month') + '</b><br>' +
'Revenue: $' + Ext.util.Format.number(record.get('revenue'), '0,000')
);
}
}
}]
});
Expected output: A bar chart with six bars showing monthly revenue. Hovering highlights a bar. Clicking shows a tooltip with details. Y-axis labels show currency format.
Line Chart
Ext.create('Ext.chart.CartesianChart', {
title: 'User Growth',
width: 700,
height: 400,
store: {
fields: ['quarter', 'users', 'premium'],
data: [
{ quarter: 'Q1', users: 1200, premium: 300 },
{ quarter: 'Q2', users: 1800, premium: 450 },
{ quarter: 'Q3', users: 2400, premium: 680 },
{ quarter: 'Q4', users: 3100, premium: 920 }
]
},
axes: [{
type: 'category',
position: 'bottom',
fields: ['quarter'],
title: 'Quarter'
}, {
type: 'numeric',
position: 'left',
fields: ['users', 'premium'],
title: 'Users',
grid: true
}],
series: [{
type: 'line',
xField: 'quarter',
yField: 'users',
title: 'Total Users',
style: { stroke: '#4a90d9', lineWidth: 3 },
marker: { type: 'circle', size: 6, fill: '#4a90d9' },
smooth: false,
fill: true,
fillOpacity: 0.1
}, {
type: 'line',
xField: 'quarter',
yField: 'premium',
title: 'Premium Users',
style: { stroke: '#ff9800', lineWidth: 3 },
marker: { type: 'diamond', size: 6, fill: '#ff9800' },
smooth: true
}],
legend: {
docked: 'bottom'
},
interactions: [{
type: 'crosshair',
axes: {
left: { label: { renderer: function(value) { return value; } } },
bottom: {}
}
}]
});
Expected output: A multi-line chart with two series. Total Users is a straight line with circle markers. Premium Users is a smooth line with diamond markers. Crosshair follows the cursor. Legend toggles series visibility.
Pie Chart
Ext.create('Ext.chart.PolarChart', {
title: 'Sales by Category',
width: 600,
height: 450,
store: {
fields: ['category', 'amount'],
data: [
{ category: 'Electronics', amount: 125000 },
{ category: 'Clothing', amount: 89000 },
{ category: 'Food', amount: 72000 },
{ category: 'Books', amount: 34000 },
{ category: 'Other', amount: 18000 }
]
},
series: [{
type: 'pie',
angleField: 'amount',
labelField: 'category',
donut: 20, // percentage of donut hole
highlight: true,
label: {
field: 'category',
display: 'outside',
calloutLine: true
},
style: {
stroke: '#fff',
strokeWidth: 2
}
}],
interactions: [{
type: 'rotate'
}],
legend: {
docked: 'right'
}
});
Expected output: A donut pie chart with five slices. Each slice is labeled on the outside with a callout line. Clicking and dragging rotates the chart. Legend on the right shows categories.
Scatter Chart
Ext.create('Ext.chart.CartesianChart', {
title: 'Customer Spend vs Frequency',
width: 700,
height: 400,
store: {
fields: ['spend', 'frequency', 'segment'],
data: (function() {
var data = [];
for (var i = 0; i < 100; i++) {
data.push({
spend: Math.round(Math.random() * 500),
frequency: Math.round(Math.random() * 50),
segment: ['A', 'B', 'C'][Math.floor(Math.random() * 3)]
});
}
return data;
})()
},
axes: [{
type: 'numeric',
position: 'bottom',
fields: ['spend'],
title: 'Average Spend ($)'
}, {
type: 'numeric',
position: 'left',
fields: ['frequency'],
title: 'Purchase Frequency',
grid: true
}],
series: [{
type: 'scatter',
xField: 'spend',
yField: 'frequency',
marker: {
type: 'circle',
size: 6
},
highlight: {
fillStyle: '#ff9800',
radius: 10
},
// Color by segment
renderer: function(sprite, config, data) {
var colors = { A: '#4a90d9', B: '#ff9800', C: '#4caf50' };
config.fillStyle = colors[data.record.get('segment')];
}
}]
});
Expected output: A scatter plot with 100 points. Each point represents a customer, colored by segment. Hovering highlights a point. Axes show spend and frequency ranges.
Chart Themes
// Apply a theme to a chart
Ext.create('Ext.chart.CartesianChart', {
theme: 'blue',
// Built-in themes: 'default', 'blue', 'green', 'red', 'sky', 'yellow', 'category1-6'
// Or custom theme:
theme: {
baseColor: '#4a90d9',
colors: ['#4a90d9', '#ff9800', '#4caf50', '#f44336', '#9c27b0'],
axis: {
stroke: '#ccc',
label: { fill: '#666', fontSize: 12 }
},
series: {
stroke: '#fff',
strokeWidth: 1
}
}
});
// Custom theme via Ext.define
Ext.define('MyApp.chart.theme.Custom', {
extend: 'Ext.chart.theme.Base',
constructor: function(config) {
this.callParent([Ext.apply({
colors: ['#1a237e', '#ff6f00', '#00695c', '#bf360c', '#4a148c'],
axis: {
defaults: {
style: { stroke: '#bdbdbd' },
label: { fill: '#616161', fontSize: 11 },
title: { fill: '#212121', fontSize: 13 }
}
}
}, config)]);
}
});
Expected output: Charts render with custom color palettes and axis styling. Themes ensure consistent appearance across all charts in the application.
Live Data Updates
var chart = Ext.create('Ext.chart.CartesianChart', {
title: 'Live Data',
width: 700,
height: 350,
store: {
fields: ['time', 'value'],
data: []
},
axes: [{
type: 'numeric',
position: 'left',
fields: ['value'],
title: 'Value'
}, {
type: 'numeric',
position: 'bottom',
fields: ['time'],
title: 'Time (s)',
renderer: function(axis, value) { return value.toFixed(1); }
}],
series: [{
type: 'line',
xField: 'time',
yField: 'value',
style: { stroke: '#4a90d9', lineWidth: 2 },
fill: true,
fillOpacity: 0.1
}]
}).renderTo(Ext.getBody());
// Simulate live data
var t = 0;
setInterval(function() {
t += 0.1;
var value = Math.sin(t) * 50 + 50 + Math.random() * 10;
chart.getStore().add({ time: t, value: value });
if (chart.getStore().getCount() > 100) {
chart.getStore().removeAt(0);
}
}, 100);
Expected output: A real-time line chart that updates every 100ms with new data points. Old points slide off as new ones arrive, creating a scrolling waveform effect.
Common Mistakes
Not matching field names between Store and series - xField and yField must exactly match Store field names. Mismatched names produce empty charts.
Using a Numeric axis for category data - Category data (months, names) needs a category axis, not numeric. Numeric axes try to interpret string values as numbers.
Forgetting to set renderTo - Unlike other components, charts don't auto-render. Always set renderTo or wrap them in a container that adds them to the document.
Not handling empty Stores - Charts break silently with empty Stores. Check store.getCount() before creating the chart, or show an empty state message.
Overloading charts with too many series - More than 4-5 series on one chart becomes unreadable. Use faceted charts or interactive toggles instead.
Practice Questions
- What is the difference between CartesianChart and PolarChart?
- How do you add a tooltip that shows on hover for bar charts?
- How do you create a donut chart (pie with a hole)?
- What is the purpose of the axes array in a chart config?
- How do you update chart data in real time?
Challenge: Build an analytics dashboard with: a bar chart showing daily page views for the last 7 days, a line chart showing user signups vs churn over 12 months, a pie chart showing traffic sources (organic, paid, referral, social), a scatter plot of session duration vs pages per session, and a theme that matches the application's brand colors.
FAQ
Mini Project
Build an executive dashboard with: a top-level summary KPI row (revenue, users, orders), a bar chart showing monthly revenue with drill-down to weekly, a line chart tracking user growth with a toggle for total vs premium, a pie chart breaking down revenue by product category, a live data chart showing real-time server requests, and a theme that applies consistent colors across all charts.
What's Next
Charts visualize data from Stores. Learn how Ext JS MVC Architecture organizes application code with Models, Views, and Controllers for maintainable large-scale apps.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro