
本文详解如何在 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 中不应包含插件实现,仅保留图表行为配置;插件需通过
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
通过以上调整,文本将稳定、居中、随数据实时更新地渲染在甜甜圈图正中央。










