
本文详解如何在 react 中使用 chart.js + react-chartjs-2 在环形图(doughnut)中心精准绘制动态数值文本,解决因插件注册位置错误导致的文本不显示问题,并提供可直接运行的完整实现方案。
在 Chart.js(v3+)中为 Doughnut 图表添加中心文本,不能将自定义绘图逻辑直接写在 options.plugins 内联对象中——这是原代码失效的根本原因。Chart.js v3 的插件系统要求:插件必须作为独立对象定义,并通过
以下是修正后的关键步骤与完整实践代码:
✅ 正确做法:分离插件定义 + 正确传入
// 1. 定义独立插件(注意:必须有唯一 id)
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 28px Inter, sans-serif'; // 推荐使用系统字体栈
ctx.fillStyle = '#E53E3E';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(`${Math.round(chart.data.datasets[0].data[0])}%`, centerX, centerY);
ctx.restore();
}
};
// 2. options 中 plugins 保持为空对象(或仅含配置项)
const doughnutOptions = {
responsive: true,
cutout: '75%',
layout: { padding: 16 },
plugins: {
// ⚠️ 这里只放配置(如 tooltip.enabled = false),不放函数!
}
};✅ 在组件中正确使用
? 常见陷阱与注意事项
- chart.ctx 安全性:确保在 beforeDraw 钩子中操作 ctx,此时 canvas 上下文已就绪;避免在 afterDraw 或其他钩子中误用。
- 动态数据同步:文本内容(如 ${input1})需随 data 实时更新。本例中 input1 是响应式 state,插件内直接读取 chart.data.datasets[0].data[0] 更健壮(自动跟随数据变化)。
- 字体与抗锯齿:添加 ctx.lineJoin = 'round' 和 ctx.imageSmoothingQuality = 'high' 可提升文本渲染质量。
-
多图表复用:若多个 Doughnut 需不同中心文本,可将插件封装为工厂函数:
const createCenterTextPlugin = (getText: (chart: Chart) => string) => ({ id: 'dynamicCenterText', beforeDraw: (chart: Chart) => { const ctx = chart.ctx; const { left, top, right, bottom } = chart.chartArea; ctx.save(); ctx.font = 'bold 24px sans-serif'; ctx.fillStyle = '#2D3748'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(getText(chart), (left + right) / 2, (top + bottom) / 2); ctx.restore(); } }); // 使用:plugins={[createCenterTextPlugin((c) => `${c.data.datasets[0].data[0]}%`)]}
✅ 最终效果保障
- 文本始终居中(利用 textAlign='center' + textBaseline='middle' + 准确计算中心坐标);
- 动态响应数据变化(state 更新 → re-render → 插件重新执行);
- 不干扰其他图表功能(tooltip、动画、响应式等均正常)。
通过将插件逻辑解耦并严格遵循 Chart.js v3 插件注入规范,即可稳定、高效地在环形图中心渲染任意文本——这是生产环境推荐的标准实践。










