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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 16:41:01