如何在Material UI LineChart上绘制非数据集内的点?
在MUI X LineChart中绘制独立精准点的解决方案
针对你在React项目中使用MUI X LineChart时,需要绘制一个不依赖现有数据集的精准点的问题,这里提供两种可行方案:
方案1:在MUI X LineChart中叠加自定义SVG点
MUI X Charts支持在图表内部添加自定义SVG元素,通过获取图表的比例尺可以精准计算目标点的画布坐标,无需修改原有数据集:
import { LineChart, useChart } from '@mui/x-charts/LineChart'; import { useEffect, useState } from 'react'; interface ChartProps { heights: number[]; windSpeeds: number[]; inputWindSpeed: number; desiredOutputHeight: number; } // 自定义点组件,利用图表比例尺计算坐标 function CustomTargetPoint({ inputWindSpeed, desiredOutputHeight }: Pick<ChartProps, 'inputWindSpeed' | 'desiredOutputHeight'>) { const chart = useChart(); const [pointPos, setPointPos] = useState<{x: number, y: number} | null>(null); useEffect(() => { if (!chart) return; // 获取x轴和y轴的比例尺对象 const xScale = chart.xAxisScales[0]; const yScale = chart.yAxisScales[0]; // 将业务值转换为SVG画布坐标 const canvasX = xScale(inputWindSpeed); const canvasY = yScale(desiredOutputHeight); // 仅当坐标有效时更新状态 if (!isNaN(canvasX) && !isNaN(canvasY)) { setPointPos({ x: canvasX, y: canvasY }); } }, [chart, inputWindSpeed, desiredOutputHeight]); if (!pointPos) return null; return ( <circle cx={pointPos.x} cy={pointPos.y} r={6} fill="#ff0000" stroke="#ffffff" strokeWidth={2} style={{ pointerEvents: 'none' }} // 避免干扰图表的交互事件 /> ); } export default function Chart({ heights, windSpeeds, inputWindSpeed, desiredOutputHeight }: ChartProps) { return ( <LineChart xAxis={[{ data: windSpeeds.length > 0 ? windSpeeds : [], label: 'Wind Speed [m/s]', labelFontSize: 20, tickFontSize: 18, valueFormatter: (value) => value.toString(), }]} series={[{ data: heights.length > 0 ? heights : [], showMark: false, }]} yAxis={[{ label: 'Height [m]', labelFontSize: 20, tickFontSize: 18, }]} grid={{ vertical: true, horizontal: true }} > {/* 插入自定义点 */} <CustomTargetPoint inputWindSpeed={inputWindSpeed} desiredOutputHeight={desiredOutputHeight} /> </LineChart> ); }
这个方法的核心是利用useChart钩子获取图表的比例尺,直接将目标的风速和高度值转换为画布上的坐标,无论该点是否存在于现有数据集中,都能精准绘制。
方案2:更换为Recharts库(更灵活的自定义点支持)
如果MUI X Charts的自定义方式过于繁琐,Recharts提供了更直接的独立点绘制能力,无需额外计算坐标:
import { LineChart, Line, XAxis, YAxis, Dot, CartesianGrid } from 'recharts'; interface ChartProps { heights: number[]; windSpeeds: number[]; inputWindSpeed: number; desiredOutputHeight: number; } export default function Chart({ heights, windSpeeds, inputWindSpeed, desiredOutputHeight }: ChartProps) { // 转换为Recharts需要的数据集格式 const chartData = windSpeeds.map((speed, index) => ({ windSpeed: speed, height: heights[index] })); return ( <LineChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: 5 }} > <CartesianGrid strokeDasharray="3 3" /> <XAxis dataKey="windSpeed" label={{ value: 'Wind Speed [m/s]', fontSize: 20, position: 'bottom' }} tick={{ fontSize: 18 }} /> <YAxis label={{ value: 'Height [m]', fontSize: 20, angle: -90, position: 'left' }} tick={{ fontSize: 18 }} /> <Line type="monotone" dataKey="height" stroke="#8884d8" dot={false} /> {/* 直接绘制独立点 */} <Dot cx={inputWindSpeed} cy={desiredOutputHeight} r={6} fill="#ff0000" stroke="#fff" strokeWidth={2} /> </LineChart> ); }
Recharts会自动根据轴的比例尺转换cx和cy的业务值,直接渲染到正确位置,代码更简洁。
内容的提问来源于stack exchange,提问作者Mason Willman
相关产品推荐
相关产品推荐

