Chart.js 环形图

在 React 项目中使用 Chart.js 创建环形图(Doughnut Chart)是一种常见的数据可视化方式,适合展示数据的比例或分布情况,如市场份额、分类占比等。结合 react-chartjs-2 库,环形图可以通过 React 组件化方式快速实现。本文以中文讲解 Chart.js 环形图的创建过程,涵盖基本用法、动态数据、样式定制、与 React Router 和 Tailwind CSS 的结合,以及注意事项,力求简洁清晰,并提供实用示例。


1. 环形图概述

环形图(Doughnut Chart)是饼图(Pie Chart)的一种变体,中心有一个空洞,适合展示多个类别的比例数据。Chart.js 的环形图支持:

  • 多数据集:显示多组数据(多环)。
  • 交互效果:支持悬停提示、点击事件。
  • 响应式:自动适配容器大小。
  • 高度可定制:调整颜色、边框、动画等。

在 React 中,使用 react-chartjs-2<Doughnut /> 组件渲染环形图。


2. 基本环形图实现

以下是在 React 中使用 Chart.js 创建一个简单环形图的示例,展示类别数据的占比。

示例代码

import { Doughnut } from 'react-chartjs-2';
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';

// 注册必要模块
ChartJS.register(ArcElement, Tooltip, Legend);

function DoughnutChart() {
  // 数据配置
  const data = {
    labels: ['苹果', '香蕉', '橙子', '葡萄'],
    datasets: [
      {
        label: '水果销量占比',
        data: [120, 190, 300, 50],
        backgroundColor: [
          'rgba(255, 99, 132, 0.5)', // 红色
          'rgba(54, 162, 235, 0.5)', // 蓝色
          'rgba(255, 206, 86, 0.5)', // 黄色
          'rgba(75, 192, 192, 0.5)', // 青色
        ],
        borderColor: [
          'rgba(255, 99, 132, 1)',
          'rgba(54, 162, 235, 1)',
          'rgba(255, 206, 86, 1)',
          'rgba(75, 192, 192, 1)',
        ],
        borderWidth: 1,
      },
    ],
  };

  // 选项配置
  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top', // 图例位置
        labels: { font: { size: 12 } },
      },
      tooltip: {
        backgroundColor: '#1f2937', // 提示框背景
        callbacks: {
          label: (context) => {
            const label = context.label || '';
            const value = context.raw;
            const total = context.dataset.data.reduce((a, b) => a + b, 0);
            const percentage = ((value / total) * 100).toFixed(1);
            return `${label}: ${value} (${percentage}%)`;
          },
        },
      },
      title: {
        display: true,
        text: '2025 年水果销量占比',
      },
    },
    cutout: '50%', // 控制环形图中心空洞大小
  };

  return (
    <div className="w-full max-w-md mx-auto p-6 bg-white rounded-lg shadow-md">
      <Doughnut data={data} options={options} />
    </div>
  );
}

export default DoughnutChart;

说明

  • 注册模块
  • ArcElement:环形图的核心元素。
  • TooltipLegend:提供交互和图例支持。
  • 数据(data)
  • labels:定义每个扇区的名称(如水果类型)。
  • datasets.data:每个扇区的数据值。
  • backgroundColor/borderColor:为每个扇区设置颜色。
  • 选项(options)
  • responsive: true:适配容器大小。
  • cutout:设置中心空洞比例(默认 50%,饼图为 0%)。
  • tooltip.callbacks.label:自定义提示框,显示数值和百分比。
  • 容器:使用 Tailwind CSS 类(如 bg-whiterounded-lg)美化容器。

3. 多数据集环形图

环形图支持多个数据集,显示多层环形图,适合比较多组数据的分布。

示例:多数据集环形图

function MultiDoughnutChart() {
  const data = {
    labels: ['苹果', '香蕉', '橙子'],
    datasets: [
      {
        label: '2024 年销量',
        data: [120, 190, 300],
        backgroundColor: ['#ff6384', '#36a2eb', '#ffce56'],
        borderWidth: 1,
      },
      {
        label: '2025 年销量',
        data: [150, 200, 250],
        backgroundColor: ['#ff9f40', '#4bc0c0', '#9966ff'],
        borderWidth: 1,
      },
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: { position: 'top' },
      title: { display: true, text: '2024 vs 2025 年水果销量' },
    },
    cutout: '50%',
  };

  return (
    <div className="w-full max-w-md mx-auto p-6 bg-white rounded-lg shadow-md">
      <Doughnut data={data} options={options} />
    </div>
  );
}

说明

  • 多数据集:每个 dataset 形成一个环,颜色区分不同年份。
  • 视觉效果:多环并排显示,适合对比多组数据。

4. 动态数据更新

结合 React 的 useStateuseEffect Hooks,实现环形图的动态更新。

示例:动态环形图

import { useState, useEffect } from 'react';
import { Doughnut } from 'react-chartjs-2';
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';

ChartJS.register(ArcElement, Tooltip, Legend);

function DynamicDoughnutChart() {
  const [data, setData] = useState({
    labels: ['苹果', '香蕉', '橙子'],
    datasets: [
      {
        label: '实时销量',
        data: [100, 150, 200],
        backgroundColor: ['#ff6384', '#36a2eb', '#ffce56'],
        borderWidth: 1,
      },
    ],
  });

  useEffect(() => {
    const interval = setInterval(() => {
      setData(prev => ({
        ...prev,
        datasets: [
          {
            ...prev.datasets[0],
            data: prev.datasets[0].data.map(() => Math.floor(Math.random() * 200) + 50),
          },
        ],
      }));
    }, 3000); // 每 3 秒更新
    return () => clearInterval(interval);
  }, []);

  const options = {
    responsive: true,
    plugins: { title: { display: true, text: '实时销量占比' } },
    cutout: '60%', // 更大空洞
  };

  return (
    <div className="w-full max-w-md mx-auto p-6 bg-white rounded-lg shadow-md">
      <Doughnut data={data} options={options} />
    </div>
  );
}

说明

  • 动态更新useEffect 每 3 秒生成随机数据,更新环形图。
  • 性能优化:可用 useMemo 缓存 data
  const memoizedData = useMemo(() => data, [data]);

5. 与 React Router 结合

将环形图嵌入 React Router 页面,适合数据仪表盘。

示例

import { Routes, Route, NavLink } from 'react-router-dom';
import DoughnutChart from './DoughnutChart';
import MultiDoughnutChart from './MultiDoughnutChart';

function App() {
  return (
    <div className="p-6">
      <nav className="mb-6 space-x-4">
        <NavLink
          to="/doughnut"
          className={({ isActive }) =>
            isActive ? 'text-blue-500 font-bold' : 'text-gray-500'
          }
        >
          标准环形图
        </NavLink>
        <NavLink
          to="/multi-doughnut"
          className={({ isActive }) =>
            isActive ? 'text-blue-500 font-bold' : 'text-gray-500'
          }
        >
          多环形图
        </NavLink>
      </nav>
      <Routes>
        <Route path="/doughnut" element={<DoughnutChart />} />
        <Route path="/multi-doughnut" element={<MultiDoughnutChart />} />
      </Routes>
    </div>
  );
}

说明

  • NavLink:切换不同环形图页面,动态添加激活样式。
  • Routes:映射环形图组件到路由路径。

6. 与 Tailwind CSS 结合

环形图渲染在 Canvas 上,外部容器可用 Tailwind CSS 美化。

示例

function DoughnutChart() {
  const data = { /* 同上 */ };
  const options = { /* 同上 */ };

  return (
    <div className="bg-white p-6 rounded-lg shadow-md max-w-md mx-auto">
      <h2 className="text-xl font-semibold mb-4 text-center">水果销量分布</h2>
      <Doughnut data={data} options={options} />
    </div>
  );
}

说明

  • 容器样式:Tailwind 类(如 bg-whiterounded-lg)美化容器。
  • Canvas 样式:环形图内部样式由 dataoptions 控制。

7. 自定义环形图样式

通过 optionsdata 自定义环形图的外观。

示例:自定义样式

const options = {
  responsive: true,
  plugins: {
    legend: { position: 'bottom', labels: { font: { size: 12 } } },
    tooltip: {
      backgroundColor: '#111827',
      callbacks: {
        label: (context) => {
          const label = context.label || '';
          const value = context.raw;
          const total = context.dataset.data.reduce((a, b) => a + b, 0);
          return `${label}: ${value} (${((value / total) * 100).toFixed(1)}%)`;
        },
      },
    },
    title: { display: true, text: '自定义环形图' },
  },
  cutout: '70%', // 更大空洞
  rotation: 45, // 旋转角度
  circumference: 270, // 显示 3/4 圆
};

说明

  • 空洞大小cutout 控制中心空洞比例(字符串如 '70%' 或数字)。
  • 旋转rotation 设置图表起始角度。
  • 弧度circumference 控制显示的圆弧范围(默认 360°)。
  • Tooltip:自定义提示框显示百分比。

8. 注意事项

  1. 模块注册
  • 确保注册 ArcElement,否则报错(如“Arc is not a registered element”)。
  1. 数据格式
  • labelsdatasets.data 长度必须一致。
  • 数据值应为正数,避免负值或空数据。
  1. 性能优化
  • 使用 useMemo 缓存 dataoptions
    jsx const memoizedData = useMemo(() => data, [data]);
  • 动态更新时限制数据量,避免性能问题。
  1. 容器尺寸
  • 环形图适合较小容器(如 max-w-md),避免过大影响美观。
  • 可设置 options.maintainAspectRatio: false 调整尺寸:
    jsx options: { maintainAspectRatio: false, height: 300 }
  1. 调试
  • 检查浏览器开发者工具,确保 Canvas 渲染正常。
  • 验证 dataoptions 格式,排除配置错误。

9. 资源

  • Chart.js 环形图文档:https://www.chartjs.org/docs/latest/charts/doughnut.html
  • react-chartjs-2 示例:https://react-chartjs-2.js.org/examples/doughnut-chart
  • 中文社区:搜索“Chart.js 环形图 中文教程”或参考掘金、知乎。

如果需要更详细的讲解(如多环形图配置、动画效果或交互优化),请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注