You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Chart.js 条形图标签显示在条形上的实现问题

解决React Chart.js水平条形图数据标签显示问题

问题根源

  1. 未注册数据标签插件:Chart.js 本身不包含数据标签功能,需单独安装并注册 chartjs-plugin-datalabels 插件。
  2. 随机数据生成重复调用:两次调用 generateRandomData() 导致图表数据与条形颜色不匹配。
  3. 数据标签配置适配错误:水平条形图(indexAxis: 'y')的标签锚点与对齐方式设置不符合需求。

修复步骤

1. 安装数据标签插件

执行命令安装依赖:

npm install chartjs-plugin-datalabels
# 或使用 yarn
yarn add chartjs-plugin-datalabels

2. 导入并注册插件

在代码中添加插件的导入与注册:

import ChartDataLabels from 'chartjs-plugin-datalabels';

// 在已有的Chart.register中加入ChartDataLabels
Chart.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, ChartDataLabels);

3. 修正数据生成逻辑

将随机数据生成结果存入变量,避免重复调用导致的数据不一致:

const chartData = generateRandomData(); // 只生成一次数据

const data = {
  labels: labels,
  datasets: [
    {
      label: 'Dataset 1',
      data: chartData,
      backgroundColor: chartData.map((value) => getColor(value)), // 复用同一份数据
      barPercentage: 1,
      categoryPercentage: 1,
    },
  ],
};

4. 调整数据标签配置

针对水平条形图,修改 datalabels 的锚点与对齐方式,确保标签显示在条形上:

datalabels: {
  anchor: 'end', // 锚定到条形末端
  align: 'center', // 垂直居中对齐
  color: 'black',
  font: {
    weight: 'bold',
  },
  formatter: (value) => `${value}%`,
  // 移除多余的labels配置,默认即可显示数值
},

完整修正后的代码

import { Bar } from 'react-chartjs-2';
import {
  Chart,
  CategoryScale,
  LinearScale,
  BarElement,
  Title,
  Tooltip,
  Legend,
} from 'chart.js';
import ChartDataLabels from 'chartjs-plugin-datalabels'; // 新增导入
import {
  ChartName,
  ChartSubtitle,
  ChartWrapper,
} from './HorizontalChartStyles';

// 注册包含数据标签的所有插件
Chart.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, ChartDataLabels);

const HorizontalChart = () => {
  const options = {
    maintainAspectRatio: true,
    indexAxis: 'y',
    elements: {
      bar: {
        borderWidth: 0,
      },
    },
    responsive: true,
    plugins: {
      legend: {
        display: false,
      },
      title: {
        display: false,
        text: 'Attendance per lecture',
      },
      tooltip: {
        enabled: false,
      },
      datalabels: {
        anchor: 'end',
        align: 'center',
        color: 'black',
        font: {
          weight: 'bold',
        },
        formatter: (value) => `${value}%`,
      },
    },
    scales: {
      y: {
        display: false,
      },
      x: {
        ticks: {
          display: true,
        },
        grid: {
          display: false,
        },
        scaleLabel: {
          display: true,
          labelString: 'Percentage',
        },
      },
    },
    layout: {
      padding: {
        right: 20,
      },
    },
  };

  const labels = [
    '1. Introduction:',
    '2. HTML & CSS:',
    '3. Version Control System:',
    '4. Advanced CSS:',
    '5. Intro to JS:',
    '6. Advanced JS:',
    '7. Intro to React:',
  ];

  const getRandomNumber = (min, max) => {
    return Math.floor(Math.random() * (max - min + 1) + min);
  };

  const generateRandomData = () => {
    return labels.map(() => getRandomNumber(0, 100));
  };

  const getColor = (value) => {
    if (value === 100) return '#CB7B2C';
    if (value >= 90) {
      const transparency = (value - 90) / 10;
      return `rgba(203, 123, 44, ${transparency})`;
    }
    if (value >= 70) return '#CB7B2C';
    return '#DCDEDF';
  };

  // 生成一次数据并复用
  const chartData = generateRandomData();

  const data = {
    labels: labels,
    datasets: [
      {
        label: 'Dataset 1',
        data: chartData,
        backgroundColor: chartData.map((value) => getColor(value)),
        barPercentage: 1,
        categoryPercentage: 1,
      },
    ],
  };

  return (
    <ChartWrapper>
      <ChartName>Attendance per lecture (%)</ChartName>
      <ChartSubtitle>Your attendance</ChartSubtitle>
      <Bar data={data} options={options} style={{ flex: 1 }} />
    </ChartWrapper>
  );
};

export default HorizontalChart;

内容的提问来源于stack exchange,提问作者Friki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 04:32:45