Chart.js Advanced Features
After learning Chart.js basic usage and style customization, let's explore some more advanced features. These features can help you create more complex and interactive charts.
Dataset Configuration
Chart.js provides rich dataset configuration options, allowing you to more precisely control display of each data series.
Dataset Properties
const config = {
type: 'line',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [{
label: 'Sales Data',
data: [10, 20, 30, 40, 50],
// Dataset-specific configuration
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderWidth: 2,
pointRadius: 4,
pointBackgroundColor: 'rgb(75, 192, 192)',
pointBorderColor: '#fff',
pointBorderWidth: 1,
// Control whether to show data points
showLine: true,
// Control whether to fill area under curve
fill: false,
// Control line tension (0 is straight line, 1 is curve)
tension: 0.1
}]
}
};Multiple Datasets
You can display multiple datasets in one chart:
const config = {
type: 'line',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [
{
label: 'Product A',
data: [10, 20, 30, 40, 50],
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.2)'
},
{
label: 'Product B',
data: [15, 25, 35, 45, 55],
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.2)'
}
]
}
};Interactive Features
Chart.js provides rich interactive features to enhance user experience.
Tooltip Configuration
const config = {
type: 'bar',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [{
label: 'Sales Data',
data: [10, 20, 30, 40, 50],
backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderColor: 'rgb(75, 192, 192)',
borderWidth: 1
}]
},
options: {
plugins: {
tooltip: {
// Enable tooltip
enabled: true,
// Tooltip position
position: 'average',
// Custom tooltip content
callbacks: {
title: function(context) {
return 'Month: ' + context[0].label;
},
label: function(context) {
return context.dataset.label + ': ' + context.parsed.y + ' units';
}
},
// Tooltip style
backgroundColor: 'rgba(0, 0, 0, 0.8)',
titleColor: '#fff',
bodyColor: '#fff',
borderColor: 'rgba(0, 0, 0, 0.1)',
borderWidth: 1
}
}
}
};Legend Configuration
const config = {
type: 'line',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [
{
label: 'Product A',
data: [10, 20, 30, 40, 50],
borderColor: 'rgb(75, 192, 192)'
},
{
label: 'Product B',
data: [15, 25, 35, 45, 55],
borderColor: 'rgb(255, 99, 132)'
}
]
},
options: {
plugins: {
legend: {
// Display legend
display: true,
// Legend position
position: 'top',
// Legend alignment
align: 'center',
// Legend label configuration
labels: {
color: '#333',
font: {
size: 12,
family: 'Arial'
},
// Behavior when clicking legend items
usePointStyle: true
}
}
}
}
};Event Handling
Chart.js allows you to add event handlers to charts to respond to user interactions.
Click Event
const config = {
type: 'bar',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [{
label: 'Sales Data',
data: [10, 20, 30, 40, 50],
backgroundColor: 'rgba(75, 192, 192, 0.2)'
}]
},
options: {
onClick: function(event, elements) {
if (elements.length > 0) {
const element = elements[0];
const datasetIndex = element.datasetIndex;
const index = element.index;
console.log('Clicked data point:');
console.log('Dataset index:', datasetIndex);
console.log('Data point index:', index);
console.log('Label:', this.data.labels[index]);
console.log('Value:', this.data.datasets[datasetIndex].data[index]);
}
}
}
};
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, config);Hover Event
const config = {
type: 'line',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [{
label: 'Sales Data',
data: [10, 20, 30, 40, 50],
borderColor: 'rgb(75, 192, 192)'
}]
},
options: {
onHover: function(event, elements) {
// Change mouse cursor style
event.native.target.style.cursor = elements.length > 0 ? 'pointer' : 'default';
}
}
};Dynamic Chart Updates
Chart.js supports dynamic chart data updates, very useful for real-time data visualization.
Update Data
// Assume we have already created a chart instance
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [{
label: 'Sales Data',
data: [10, 20, 30, 40, 50],
borderColor: 'rgb(75, 192, 192)'
}]
}
});
// Add new data point
function addData(chart, label, data) {
chart.data.labels.push(label);
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
chart.update();
}
// Remove data point
function removeData(chart) {
chart.data.labels.pop();
chart.data.datasets.forEach((dataset) => {
dataset.data.pop();
});
chart.update();
}
// Update existing data point
function updateData(chart, index, newData) {
chart.data.datasets.forEach((dataset) => {
dataset.data[index] = newData;
});
chart.update();
}Real-time Data Example
// Create a real-time updating chart
const ctx = document.getElementById('realTimeChart').getContext('2d');
const realTimeChart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Real-time Data',
data: [],
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
fill: true
}]
},
options: {
scales: {
x: {
display: true,
title: {
display: true,
text: 'Time'
}
},
y: {
display: true,
title: {
display: true,
text: 'Value'
}
}
},
animation: {
duration: 0 // Generally disable animation for real-time data
}
}
});
// Simulate real-time data updates
setInterval(function() {
const now = new Date();
const timeString = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
const newValue = Math.floor(Math.random() * 100);
// Add new data point
realTimeChart.data.labels.push(timeString);
realTimeChart.data.datasets[0].data.push(newValue);
// Keep maximum 20 data points
if (realTimeChart.data.labels.length > 20) {
realTimeChart.data.labels.shift();
realTimeChart.data.datasets[0].data.shift();
}
realTimeChart.update();
}, 1000);Plugin System
Chart.js has a powerful plugin system, allowing you to extend chart functionality.
Create Custom Plugin
// Create a simple plugin to display text on chart
const textPlugin = {
id: 'textPlugin',
beforeDraw: function(chart) {
const ctx = chart.ctx;
const width = chart.width;
const height = chart.height;
const text = 'Chart.js Advanced Features';
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '16px Arial';
ctx.fillStyle = '#666';
ctx.fillText(text, width / 2, height / 2);
ctx.restore();
}
};
// Register plugin
Chart.register(textPlugin);
// Use plugin in chart configuration
const config = {
type: 'bar',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [{
label: 'Sales Data',
data: [10, 20, 30, 40, 50],
backgroundColor: 'rgba(75, 192, 192, 0.2)'
}]
},
plugins: [textPlugin] // Use plugin
};Custom Chart Types
You can also create custom chart types to meet specific needs.
Extend Existing Chart Type
// Extend line chart to add custom functionality
class CustomLineController extends Chart.controllers.line {
draw() {
// Call parent class draw method
super.draw(arguments);
// Add custom drawing logic
const ctx = this.chart.ctx;
const chartArea = this.chart.chartArea;
// Draw a custom line on chart
ctx.save();
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(chartArea.left, chartArea.top + (chartArea.bottom - chartArea.top) / 2);
ctx.lineTo(chartArea.right, chartArea.top + (chartArea.bottom - chartArea.top) / 2);
ctx.stroke();
ctx.restore();
}
}
// Register custom controller
Chart.register(CustomLineController);
// Use custom chart type
const config = {
type: 'customLine', // Use custom type
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [{
label: 'Sales Data',
data: [10, 20, 30, 40, 50],
borderColor: 'rgb(75, 192, 192)'
}]
}
};Export and Import
Export Chart as Image
function exportChart(chart, filename) {
const url = chart.toBase64Image();
const link = document.createElement('a');
link.download = filename;
link.href = url;
link.click();
}
// Export with options
function exportChartWithOptions(chart, filename, options = {}) {
const url = chart.toBase64Image(options);
const link = document.createElement('a');
link.download = filename;
link.href = url;
link.click();
}
// Usage
exportChart(myChart, 'chart.png');
exportChartWithOptions(myChart, 'chart.jpg', { type: 'image/jpeg', quality: 0.9 });Import Chart Configuration
// Save chart configuration
function saveChartConfig(chart) {
const config = chart.config;
const configJSON = JSON.stringify(config, null, 2);
// Save to localStorage
localStorage.setItem('chartConfig', configJSON);
// Or download as file
const blob = new Blob([configJSON], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.download = 'chart-config.json';
link.href = url;
link.click();
}
// Load chart configuration
function loadChartConfig(canvasId) {
const configJSON = localStorage.getItem('chartConfig');
if (configJSON) {
const config = JSON.parse(configJSON);
const ctx = document.getElementById(canvasId).getContext('2d');
return new Chart(ctx, config);
}
return null;
}Summary
In this chapter, we learned some advanced features of Chart.js:
- Dataset Configuration - Detailed configuration for each data series display
- Interactive Features - Tooltips, legends, and event handling
- Dynamic Updates - Real-time chart data updates
- Plugin System - Extend chart functionality
- Custom Chart Types - Create charts for specific needs
- Export and Import - Save and load chart configurations
These advanced features can help you create more complex and interactive charts, improving user experience. In next chapter, we will learn how to integrate Chart.js with popular frontend frameworks.