Chart.js 在甜甜圈图表中心显示文本的正确实现方法

14次阅读

Chart.js 在甜甜圈图表中心显示文本的正确实现方法

本文详解如何在 chart.js 的 doughnut 图表中心精准渲染动态文本,重点纠正插件注册位置错误、坐标计算逻辑缺陷及 react 状态同步问题,并提供可直接运行的完整解决方案。

在使用 react-chartjs-2 实现甜甜圈图(Doughnut)时,许多开发者尝试通过 options.plugins.beforedraw 直接注入绘图逻辑来居中显示数值,但常遇到文本不显示、偏移或闪烁等问题。根本原因在于:Chart.js 插件必须作为独立对象传入组件的 plugins prop,而非嵌套在 options.plugins 内部——后者仅用于配置已注册插件,无法定义新插件逻辑。

✅ 正确做法:分离插件定义与配置

首先,将自定义插件提取为独立对象,并赋予唯一 id(这是 Chart.js 插件系统的强制要求):

const centerTextPlugin = {   id: 'centerText',   beforeDraw: (chart) => {     const { ctx, chartArea: { left, top, right, bottom } } = chart;     const centerX = left + (right - left) / 2;     const centerY = top + (bottom - top) / 2;      ctx.save();     ctx.font = 'bold 24px sans-serif';     ctx.fillStyle = '#333';     ctx.textAlign = 'center';     ctx.textBaseline = 'middle';     ctx.fillText(`${chart.data.datasets[0].data[0]}`, centerX, centerY);     ctx.restore();   } };

⚠️ 注意:chart.ctx 和 chart.chartArea 在 beforeDraw 阶段已完全就绪,但需确保 chart.data 已同步更新(见下文状态处理)。

✅ 配置 options 与 plugins 分离

options 中不应包含插件实现,仅保留图表行为配置;插件需通过 组件的 plugins 属性显式传入:

const options = {   responsive: true,   cutout: '75%', // 建议用百分比而非字符串('80%' → 80)   layout: { padding: 16 },   plugins: {     legend: { display: false }, // 可选:隐藏图例以突出中心文本     tooltip: { enabled: false }  // 可选:禁用悬停提示   } };  // 使用时: 

✅ 处理 React 状态与动画同步问题

原代码中 useEffect 的依赖项 [count, targetValue] 会导致无限循环(count 更新触发 effect,effect 又更新 count)。应改为:

useEffect(() => {   const durations = [5000, 5000, 5000];   const increment = targetValue.map((val, i) => Math.ceil(val / durations[i] * 10));    const timer = setTimeout(() => {     setCount(prev =>        prev.map((c, i) => (c < targetValue[i] ? c + increment[i] : c))     );   }, 10);    return () => clearTimeout(timer); }, [targetValue]); // ✅ 仅依赖 targetValue,避免循环

同时,确保 data 动态绑定最新值(如 data.datasets[0].data[0] 对应 input1),插件内 fillText 才能实时反映变化。

✅ 完整可运行示例(精简版)

import { Doughnut } from 'react-chartjs-2'; import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';  ChartJS.register(ArcElement, Tooltip, Legend);  const centerTextPlugin = { /* 如上定义 */ };  export default function RoundedStats() {   const [input1, setInput1] = useState(0);   // ... 其他 state 同理    useEffect(() => {     // 初始化逻辑(略)   }, []);    const data = {     datasets: [{       data: [input1, 100 - input1],       backgroundColor: ['red', '#071952']     }]   };    const options = { /* 如上配置 */ };    return (     

No of Visitors

{/* 其他两个图表同理 */}
); }

? 常见错误排查清单

  • ❌ 错误:plugins 写在 options.plugins 里 → ✅ 应传给组件 plugins prop
  • ❌ 错误:未设置 id 字段 → ✅ 插件必须有唯一 id
  • ❌ 错误:chartArea 计算使用 chart.chartArea.left 等 → ✅ 应解构 chart.chartArea 或用 chart.boxes(更健壮)
  • ❌ 错误:input1 未及时同步到 data → ✅ 确保 data 是响应式引用最新 state

通过以上调整,文本将稳定、居中、随数据实时更新地渲染在甜甜圈图正中央。

text=ZqhQzanResources