ECharts là một thư viện biểu đồ JavaScript mã nguồn mở mạnh mẽ, cung cấp khả năng trực quan hóa dữ liệu một cách trực quan, sinh động, tương tác và có thể tùy chỉnh cao. Được phát triển ban đầu bởi đội ngũ Baidu, ECharts đã được chuyển giao cho Apache Foundation vào đầu năm 2018 và trở thành một dự án ươm tạo của ASF.
1. Cấu hình cơ bản của ECharts
ECharts hoạt động dựa trên một đối tượng cấu hình (option) lớn để định nghĩa mọi khía cạnh của biểu đồ. Dưới đây là các thành phần cấu hình chính:
title: Thành phần tiêu đề biểu đồ
Dùng để đặt tiêu đề chính cho biểu đồ của bạn.
title: {
text: 'Thông Tin Biểu Đồ' // Văn bản hiển thị của tiêu đề
}
tooltip: Thành phần hộp gợi ý
Hiển thị thông tin chi tiết khi người dùng di chuột qua các phần tử biểu đồ.
// Cấu hình hộp gợi ý khi di chuột
tooltip: {
trigger: "Phương thức kích hoạt hộp gợi ý", // Xác định cách hộp gợi ý xuất hiện
formatter: "Hàm hoặc chuỗi định dạng nội dung hiển thị trong hộp gợi ý"
}
Các giá trị phổ biến cho trigger:
'axis': Kích hoạt theo trục. Thường dùng cho biểu đồ cột, biểu đồ đường khi cần hiển thị thông tin của tất cả các chuỗi dữ liệu tại một điểm trên trục.'item': Kích hoạt theo từng phần tử. Thích hợp cho biểu đồ tròn, biểu đồ phân tán hoặc các biểu đồ không có trục danh mục rõ ràng.'none': Không kích hoạt hộp gợi ý.
legend: Thành phần chú giải
Dùng để hiển thị các ký hiệu và tên của từng chuỗi dữ liệu trong biểu đồ, giúp người đọc dễ dàng nhận biết.
// Chú giải biểu đồ
legend: {
data: ['Chuỗi A', 'Chuỗi B', 'Chuỗi C'] // Danh sách tên các chuỗi dữ liệu
}
xAxis: Trục hoành (trục X)
Cấu hình cho trục nằm ngang, thường biểu diễn các danh mục hoặc thời gian.
// Cấu hình trục X
xAxis: {
type: 'category', // Loại trục: 'category' (danh mục), 'value' (giá trị), 'time' (thời gian), 'log' (logarit)
boundaryGap: false, // Loại bỏ khoảng cách ở hai đầu trục (mặc định là true)
data: ['Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy', 'Chủ Nhật'] // Dữ liệu danh mục
}
type: 'category': Trục danh mục, phù hợp cho dữ liệu rời rạc. Khi sử dụng loại này, bạn phải cung cấp dữ liệu danh mục thông qua thuộc tínhdata.boundaryGap: false: Khi làfalse, các điểm dữ liệu sẽ nằm sát vào hai đầu trục. Khitrue(mặc định), các điểm sẽ nằm giữa các vạch chia.
yAxis: Trục tung (trục Y)
Cấu hình cho trục thẳng đứng, thường biểu diễn giá trị số.
// Cấu hình trục Y
yAxis: {
type: "value" // Loại trục: 'value' là mặc định cho trục số, có thể bỏ qua
}
Trục Y thường tự động điều chỉnh thang đo dựa trên dữ liệu, nên bạn không cần cấu hình quá nhiều trừ khi có yêu cầu đặc biệt.
series: Danh sách chuỗi dữ liệu (Quan trọng)
Đây là phần quan trọng nhất, nơi bạn định nghĩa từng chuỗi dữ liệu và loại biểu đồ của chúng. Mỗi đối tượng trong mảng series đại diện cho một chuỗi dữ liệu hoặc một biểu đồ riêng biệt.
series: [{
name: 'Tên chuỗi', // Tên hiển thị trong chú giải và tooltip
type: 'bar', // Loại biểu đồ: 'bar' (cột), 'line' (đường), 'pie' (tròn), v.v.
data: [100, 120, 150, 180, 200], // Dữ liệu của chuỗi
barWidth: 30, // Chiều rộng của cột (chỉ áp dụng cho biểu đồ cột)
stack: 'Tổng', // Nếu nhiều chuỗi có cùng giá trị 'stack', chúng sẽ được chồng lên nhau
smooth: true, // Làm mượt đường cong (chỉ áp dụng cho biểu đồ đường)
areaStyle: {}, // Đổ màu vùng dưới đường (chỉ áp dụng cho biểu đồ đường)
emphasis: { // Cấu hình kiểu khi di chuột vào phần tử
label: {
show: true,
textStyle: {
color: '#ff6600',
fontWeight: 'bold'
}
}
}
}]
Mỗi đối tượng trong mảng series tạo ra một chuỗi dữ liệu trên biểu đồ. Các thuộc tính chính:
type: Xác định loại biểu đồ. Các loại phổ biến:'bar'(cột),'line'(đường),'pie'(tròn).name: Tên của chuỗi dữ liệu, được sử dụng trongtooltipvàlegend.stack: Chuỗi dữ liệu có cùng giá trịstacksẽ được chồng lên nhau.data: Mảng chứa các giá trị dữ liệu. Có thể là mảng số hoặc mảng các đối tượng{name: '...', value: ...}(thường dùng cho biểu đồ tròn).
Các tùy chỉnh nâng cao theo loại biểu đồ:
-
Biểu đồ đường (
type: 'line'):smooth: true: Biến đường thẳng thành đường cong mượt mà.areaStyle: {}: Đổ màu vùng bên dưới đường để tạo biểu đồ diện tích. Ví dụ:areaStyle: { color: '#f70' }.
-
Biểu đồ tròn (
type: 'pie'):radius: [innerRadius, outerRadius]: Xác định bán kính bên trong và bên ngoài. Có thể dùng số pixel ([50, 100]) hoặc phần trăm (['10%', '70%']).center: [x, y]: Vị trí tâm biểu đồ. Ví dụ:['50%', '50%']để căn giữa.roseType: 'radius'hoặc'area': Biểu đồ cánh hoa hồng, trong đó bán kính hoặc diện tích của các phần tử tỷ lệ với giá trị.- Dữ liệu
datacho biểu đồ tròn thường là mảng đối tượng:data: [ {name: "JavaScript", value: 90}, {name: "HTML/CSS", value: 85}, {name: "Vue.js", value: 70} ]
2. Ứng dụng ECharts trong Vue.js
Để tích hợp ECharts vào ứng dụng Vue.js, bạn cần thực hiện các bước sau:
Cài đặt ECharts
npm install echarts
Import ECharts
Trong thành phần Vue của bạn, import thư viện ECharts:
import * as echarts from 'echarts';
Chuẩn bị vùng chứa DOM
ECharts cần một phần tử DOM có chiều rộng và chiều cao cụ thể để render biểu đồ. Đặt một div trong template của bạn:
<!-- Vùng chứa DOM cho biểu đồ ECharts -->
<div id="chart-container" style="width: 100%; height: 350px; border: 1px solid #ddd;"></div>
Khởi tạo và cấu hình biểu đồ
Sử dụng hook onMounted của Vue để đảm bảo DOM đã sẵn sàng trước khi khởi tạo biểu đồ:
// Trong <script setup> của Vue 3
import { onMounted } from 'vue';
import * as echarts from 'echarts';
onMounted(() => {
// 1. Lấy phần tử DOM
const chartDom = document.getElementById("chart-container");
if (!chartDom) return;
// 2. Khởi tạo một thể hiện ECharts
const chartInstance = echarts.init(chartDom);
// 3. Định nghĩa đối tượng cấu hình biểu đồ
const chartOptions = {
title: {
text: "Tiêu đề biểu đồ mẫu"
},
tooltip: {},
legend: {
data: ["Số liệu"]
},
xAxis: {
data: ["Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5"]
},
yAxis: {},
series: [{
name: "Số liệu",
type: "bar",
data: [5, 20, 36, 10, 10]
}]
};
// 4. Áp dụng cấu hình vào thể hiện biểu đồ
chartInstance.setOption(chartOptions);
});
3. Các ví dụ thực tế
Dưới đây là một số ví dụ minh họa cách sử dụng ECharts với Vue.js để tạo các loại biểu đồ khác nhau.
<template>
<div style="display: flex; flex-wrap: wrap; justify-content: space-around;">
<div id="stacked-bar-chart" style="width: 48%; height: 300px; border: 1px solid #eee; margin-bottom: 15px;"></div>
<div id="pie-chart" style="width: 48%; height: 300px; border: 1px solid #eee; margin-bottom: 15px;"></div>
<div id="basic-bar-chart" style="width: 48%; height: 300px; border: 1px solid #eee; margin-bottom: 15px;"></div>
<div id="complex-chart" style="width: 48%; height: 300px; border: 1px solid #eee; margin-bottom: 15px;"></div>
</div>
</template>
<script setup>
import * as echarts from "echarts";
import { onMounted, reactive } from "vue";
// Dữ liệu mẫu cho các biểu đồ
const chartData = reactive({
stackedBarSeries: [
{
name: 'Người A',
type: 'bar',
stack: 'Tổng Cộng',
data: [180, 250, 200, 230, 160, 250, 280, 120],
},
{
name: 'Người B',
stack: 'Tổng Cộng',
data: [130, 200, 210, 190, 140, 220, 240, 90],
type: 'bar'
}
],
pieCategories: [
{ value: 1100, name: 'Công cụ tìm kiếm' },
{ value: 750, name: 'Truy cập trực tiếp' },
{ value: 600, name: 'Email Marketing' },
{ value: 500, name: 'Quảng cáo liên kết' },
{ value: 320, name: 'Quảng cáo video' }
]
});
onMounted(() => {
// Biểu đồ cột chồng (Stacked Bar Chart)
const stackedBarDom = document.getElementById('stacked-bar-chart');
if (stackedBarDom) {
const stackedBarInstance = echarts.init(stackedBarDom);
stackedBarInstance.setOption({
title: {
text: 'Dữ liệu đa chuỗi'
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: ['T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'CN', 'Khác']
},
yAxis: {
type: 'value'
},
series: chartData.stackedBarSeries
});
}
// Biểu đồ tròn (Pie Chart)
const pieChartDom = document.getElementById('pie-chart');
if (pieChartDom) {
const pieChartInstance = echarts.init(pieChartDom);
pieChartInstance.setOption({
title: {
text: 'Phân tích nguồn truy cập'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: 'Nguồn truy cập',
type: 'pie',
radius: '60%', // Bán kính 60%
data: chartData.pieCategories,
emphasis: { // Hiệu ứng khi di chuột
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
});
}
// Biểu đồ cột đơn giản
renderBasicBarChart();
// Biểu đồ phức hợp (cột, đường, tròn)
renderComplexChart();
});
const renderBasicBarChart = () => {
const basicBarDom = document.getElementById("basic-bar-chart");
if (!basicBarDom) return;
const basicBarInstance = echarts.init(basicBarDom);
const basicBarOptions = {
title: {
text: "Biểu đồ cột đơn giản"
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ["Thời lượng"]
},
xAxis: {
data: ["T2", "T3", "T4", "T5", "T6", "T7", "CN"]
},
yAxis: {},
series: [
{
name: "Thời lượng",
type: "bar",
data: [7, 9, 3, 6, 8, 5, 7]
}
]
};
basicBarInstance.setOption(basicBarOptions);
};
const renderComplexChart = () => {
const complexChartDom = document.getElementById("complex-chart");
if (!complexChartDom) return;
const complexChartInstance = echarts.init(complexChartDom);
const complexChartOptions = {
title: {
text: "Biểu đồ tổng hợp hoạt động"
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' }
},
legend: {
data: ['Giờ ngủ', 'Giờ chơi game', 'Giờ học', 'Điểm thi']
},
xAxis: {
type: 'category',
boundaryGap: true,
data: ['Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy', 'Chủ Nhật']
},
yAxis: {
type: 'value',
name: 'Số giờ / Điểm số'
},
series: [
{
name: "Giờ ngủ",
type: "bar",
data: [8, 9, 5, 7, 8, 4, 9]
},
{
name: "Giờ chơi game",
type: "line",
data: [2, 3, 1, 4, 5, 7, 4]
},
{
name: "Giờ học",
type: "line",
smooth: true,
data: [6, 7, 5, 8, 6, 2, 1],
areaStyle: {
color: 'rgba(255, 120, 70, 0.4)' // Màu cam nhạt
}
},
{
name: "Điểm thi",
type: "pie", // Biểu đồ tròn lồng ghép
radius: [40, 70], // Bán kính trong và ngoài
center: ['80%', '20%'], // Vị trí tâm biểu đồ tròn
data: [
{name: "JS", value: 92},
{name: "HTML", value: 88},
{name: "CSS", value: 95},
{name: "Vue", value: 80},
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
complexChartInstance.setOption(complexChartOptions);
};
</script>
<style scoped>
/* Các style cục bộ cho thành phần Vue */
</style>