Trực Quan Hóa Dữ Liệu Với ECharts Trong Ứng Dụng Vue.js

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ính data.
  • boundaryGap: false: Khi là false, các điểm dữ liệu sẽ nằm sát vào hai đầu trục. Khi true (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 trong tooltip và legend.
  • stack: Chuỗi dữ liệu có cùng giá trị stack sẽ đượ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 data cho 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>

Thẻ: echarts Vue.js data visualization JavaScript Charting Frontend Development

Đăng vào ngày 29 tháng 10 lúc 12:40