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

如何在React-ChartJS-2+TypeScript中使用beforeDraw插件?

在TypeScript中为React-ChartJS-2环形图添加内部标题插件的解决方案

我需要将Doughnut环形图的标题移至图表内部,尝试通过beforeDraw插件实现,但在TypeScript环境下遇到两个错误:

遇到的TypeScript错误

  • 在beforeDraw函数中访问chart.chart时,提示:Property 'chart' does not exist on type 'Chart<keyof ChartTypeRegistry, (number | [number, number] | Point | BubbleDataPoint | null)[], unknown>'.ts(2339)
  • 将plugins传入Doughnut组件时,提示:const plugins: Plugin<"doughnut", AnyObject> | undefined; Type 'Plugin<"doughnut", AnyObject> | undefined' is not assignable to type 'Plugin<"doughnut", AnyObject>'; Type 'undefined' is not assignable to type 'Plugin<"doughnut", AnyObject>'.ts(2322)

错误原因与修复方案

1. 修复chart.chart属性不存在的问题

Chart.js新版本中,插件钩子的beforeDraw参数本身就是完整的Chart实例,无需通过chart.chart嵌套访问。直接使用chart.width、chart.height、chart.ctx即可,旧写法是兼容旧版本的遗留代码,TypeScript严格遵循类型定义,因此需要调整访问逻辑。

2. 修复插件类型不匹配的问题

useState初始值设为undefined时,插件类型需要明确包含undefined;同时传入Doughnut组件时,要确保插件数组中无undefined值,可通过过滤逻辑或设置初始空插件对象解决。

修正后的完整代码

import { useState } from 'react';
import {
  Chart as ChartJS,
  Tooltip,
  Legend,
  ArcElement,
  Title,
  Plugin,
} from 'chart.js';
import { Doughnut } from 'react-chartjs-2';
import type { ChartData, ChartOptions } from 'chart.js';

ChartJS.register(
  ArcElement,
  Tooltip,
  Legend,
  Title,
);

// 为状态指定正确的TypeScript类型
const [data, setData] = useState<ChartData<'doughnut'>>();
const [options, setOptions] = useState<ChartOptions<'doughnut'>>();
const [plugins, setPlugins] = useState<Plugin<'doughnut'> | undefined>();

// 假设field1/field2/field3是表单传入的数值
const foods = [
  { value: field1, label: 'Orange' },
  { value: field2, label: 'Banana' },
  { value: field3, label: 'Strawberry' },
];

function PieData() {
  setData({
    labels: foods.map(food => food.label),
    datasets: [
      {
        label: 'Foods',
        data: foods.map(food => food.value),
        backgroundColor: [
          'rgba(255, 99, 132, 0.2)',
          'rgba(54, 162, 235, 0.2)',
          'rgba(255, 206, 86, 0.2)',
        ],
        borderColor: [
          'rgba(255, 99, 132, 1)',
          'rgba(54, 162, 235, 1)',
          'rgba(255, 206, 86, 1)',
        ],
        borderWidth: 1,
      },
    ],
  });

  setOptions({
    responsive: true,
    plugins: {
      legend: {
        position: 'right',
        rtl: true,
        labels: {
          usePointStyle: true,
          pointStyle: 'circle',
        },
      },
    },
  });

  // 修正beforeDraw中的Chart实例访问逻辑
  setPlugins({
    id: "tooltipLine",
    beforeDraw: (chart) => {
      const width = chart.width;
      const height = chart.height;
      const ctx = chart.ctx;
      ctx.restore();
      const fontSize = (height / 160).toFixed(2);
      ctx.font = `${fontSize}em sans-serif`;
      ctx.textBaseline = "middle";
      const text = "Foo-bar";
      const textX = Math.round((width - ctx.measureText(text).width) / 2);
      const textY = height / 2;
      ctx.fillText(text, textX, textY);
      ctx.save();
    },
  });
}

// 传入插件时过滤undefined,避免类型错误
return (
  <div>
    <button onClick={PieData}>更新图表</button>
    <Doughnut 
      id="pieChart" 
      data={data} 
      options={options} 
      plugins={plugins ? [plugins] : []} 
    />
  </div>
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:45:29