React Chart.js插件渲染陈旧数据:中心文本显示错误排查
Doughnut图表搜索后中心文本显示错误问题排查
我通过插件渲染一系列带中心文本的Doughnut图表,初始渲染效果符合预期。但实现客户端搜索功能并重新渲染图表系列后,插件获取了无关的数据集,导致中心文本显示错误。
注意:搜索后Doughnut图表本身渲染正常,仅中心文本存在问题。
已尝试方案:将插件方法从beforeDatasetsDraw更换为其他插件生命周期方法,尝试解决渲染生命周期相关问题,但未取得效果。
截图说明
Doughnut组件代码
<> {props.microservices && Array.isArray(props.microservices) && props.microservices.map((e) => ( <> <p>{e?.serviceInfo?.name}</p> <DoughnutChart containerClassName="h-[75px] flex justify-center" data={{ datasets: [ { data: [Math.round(e.cpu), 100 - Math.round(e.cpu)], weight: 3, backgroundColor: Math.round(e.cpu) === 0 ? ["transparent", "transparent"] : ["#BB723F", "#21262D"], borderColor: "#232323", borderWidth: 0, }, { weight: 3, data: [100], borderColor: "#232323", borderWidth: 0, backgroundColor: Math.round(e.cpu) === 0 || Math.round(e.memory) === 0 ? ["transparent"] : ["#29292A"], }, { data: [Math.round(e.memory), 100 - Math.round(e.memory)], weight: 3, borderColor: "#232323", borderWidth: 0, backgroundColor: Math.round(e.memory) === 0 ? ["transparent", "transparent"] : ["#31737B", "transparent"], }, ], }} options={{ responsive: true, cutout: "80%", plugins: { tooltip: { enabled: false, }, datalabels: { display: false, }, }, }} plugins={[ centerText({ text: e.serviceInfo?.name, fillColor: Math.round(e.cpu) === 0 || Math.round(e.memory) === 0 ? "#3E4249" : "#0C1117", arcX: props.isPopUp ? 30 : 34, arcY: 38, arcRadius: props.isPopUp ? 24 : 27, arcStart: 0, arcEnd: 2 * Math.PI, activePods: e.serviceInfo?.activePods, totalPods: 16, isDisabledDoughNut: Math.round(e.cpu) === 0 || Math.round(e.memory) === 0, }), ]} isDisabledDoughNut={ Math.round(e.cpu) === 0 || Math.round(e.memory) === 0 } onClickHandler={(_) => { const { cpu, memory, traffic, errorRate, serviceInfo: { instance, activePods }, } = e; props.setOverLayData({ cpu, memory, traffic, errorRate, activePods, totalPods: 99, title: instance?.split("-").join(" "), }); props.op.current?.toggle(_); }} /> </> ))} </>
Center Text Plugin代码
const centerText = ({ text = "HELLO WORLD", fillColor = "#F86E6E", textColor = "#fff", arcX = 220, arcY = 230, arcRadius = 200, arcStart = 0, arcEnd = 2 * Math.PI, isDisabledDoughNut = false, activePods = 0, totalPods = 0, }) => ({ id: "centerText", beforeDatasetsDraw(chart) { let warningIcon; if (isDisabledDoughNut) { warningIcon = new Image(); warningIcon.src = `data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMS41ODIiIGhlaWdodD0iMTAiIHZpZXdCb3g9IjAgMCAxMS41ODIgMTAiPgogIDxwYXRoIGlkPSJ3YXJuaW5nX0ZJTEwxX3dnaHQzMDBfR1JBRDBfb3BzejI0IiBkPSJNNzQuNjE4LTgzMGw1Ljc5MS0xMEw4Ni4yLTgzMFptNS43OTEtMS41MzlhLjQ0Ni40NDYsMCwwLDAsLjMyOS0uMTMzLjQ0Ni40NDYsMCwwLDAsLjEzMy0uMzI5LjQ0Ny40NDcsMCwwLDAtLjEzMy0uMzI5LjQ0Ny40NDcsMCwwLDAtLjMyOS0uMTMzLjQ0Ny40NDcsMCwwLDAtLjMyOS4xMzMuNDQ3LjQ0NywwLDAsMC0uMTMzLjMyOS40NDYuNDQ2LDAsMCwwLC4xMzMuMzI5QS40NDYuNDQ2LDAsMCwwLDgwLjQwOS04MzEuNTM2Wm0tLjQyOS0xLjQ5NGguODU3di0yLjg1N2gtLjg1N1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC03NC42MTggODM5Ljk5NykiIGZpbGw9IiNmYmZiZmMiLz4KPC9zdmc+Cg==`; } const { ctx } = chart; ctx.save(); const x = chart.getDatasetMeta(0).data[0].x; const y = chart.getDatasetMeta(0).data[0].y; ctx.beginPath(); ctx.arc(arcX, arcY, arcRadius, arcStart, arcEnd); ctx.fillStyle = fillColor; ctx.fill(); ctx.stroke(); ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.font = "12px Helvetica"; ctx.fillStyle = textColor; ctx.fillText(text, x - 1, y - 5); if (!isDisabledDoughNut) { ctx.font = "8px Helvetica"; ctx.fillText(`${activePods}/${totalPods}`, x, y + 10); } if (isDisabledDoughNut && warningIcon.complete) { ctx.drawImage(warningIcon, x - 5, y + 5, 10, 10); } }, });
问题原因与解决方案
核心原因
- 所有图表的插件共用同一个
id: "centerText",Chart.js会复用旧插件实例,导致搜索后新图表的插件参数被旧实例缓存覆盖。 - 通过
chart.getDatasetMeta(0).data[0].x获取中心坐标的方式,在图表复用/重建时可能指向旧数据集的位置。
修复步骤
给每个插件实例分配唯一ID
修改插件调用和定义,确保每个图表的插件独立:// 组件中调用插件时传入唯一ID plugins={[ centerText({ id: `centerText-${e.serviceInfo?.name}`, // 用服务名称做唯一标识 text: e.serviceInfo?.name, // 其他参数保持不变 }), ]} // 插件定义中接收并使用传入的ID const centerText = ({ id = "centerText", text = "HELLO WORLD", // 其他参数 }) => ({ id, beforeDatasetsDraw(chart) { // 原有逻辑不变 }, });正确获取当前图表的中心坐标
放弃依赖数据集索引,改用图表自身区域计算中心:// 替换插件中x、y的获取逻辑 const chartArea = chart.chartArea; const x = (chartArea.left + chartArea.right) / 2; const y = (chartArea.top + chartArea.bottom) / 2;给图表组件添加唯一key
确保React在搜索后能正确重建图表组件,而非复用旧实例:props.microservices.map((e, index) => ( <div key={e.serviceInfo?.name || index}> <p>{e?.serviceInfo?.name}</p> <DoughnutChart // 原有属性不变 /> </div> ))
以上三步结合即可解决搜索后中心文本显示错误的问题。
内容的提问来源于stack exchange,提问作者Rajkumar Somasundaram
相关产品推荐
相关产品推荐



