如何在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
相关产品推荐
相关产品推荐

