said al hendi
said al hendi

Reputation: 49

Performance Issues with Rendering Large Datasets in Recharts – How to Optimize?

I'm working on a data visualization app using React and Recharts, and I'm facing performance issues when rendering large datasets. My data consists of three variables: voltage, current, and distance, each containing at least 20,000 data points. While fetching the data from the database (MariaDB) via a Node.js server is quick, the bottleneck occurs during rendering the data in the chart.

Here’s an overview of how I’m currently managing the data and rendering the chart:

import { useState, useMemo } from 'react'
import {
  LineChart,
  Line,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  Legend,
  ResponsiveContainer,
  Brush,
  ReferenceLine,
} from 'recharts'
import { useAppSelector } from '@/Hooks/useReduxHook'
import type { RootState } from '@/store'
import { Switch } from '@/components/ui/switch'

interface ChartDataItem {
  time: number
  voltage: number
  current: number
  distance: number
}

const CenteredZeroProcessDataChart: React.FC = () => {
  const { currentWeld } = useAppSelector((state) => state.weld)
  const [isZoomingEnabled, setZoomingEnabled] = useState(true)
  const { theme } = useAppSelector((state: RootState) => state.themeState)
  const [brushDomain, setBrushDomain] = useState<[number, number] | null>(null)

  const data: ChartDataItem[] = useMemo(() => {
    if (!currentWeld) return []

    const curve1Data = currentWeld.Curves_Data.curves.curve_1.curveData || []
    const curve2Data = currentWeld.Curves_Data.curves.curve_2.curveData || []
    const curve3Data = currentWeld.Curves_Data.curves.curve_3.curveData || []

    const maxLength = Math.max(
      curve1Data.length,
      curve2Data.length,
      curve3Data.length
    )

    return Array.from({ length: maxLength }, (_, i) => ({
      time: i,
      current: curve1Data[i]?.y || 0,
      voltage: curve2Data[i]?.y || 0,
      distance: curve3Data[i]?.y || 0,
    }))
  }, [currentWeld])

  const { maxAbsValue } = useMemo(() => {
    let max = 0
    data.forEach((item) => {
      max = Math.max(
        max,
        Math.abs(item.voltage),
        Math.abs(item.current),
        Math.abs(item.distance)
      )
    })

    return { maxAbsValue: max }
  }, [data])

  const handleToggleZooming = () => {
    setZoomingEnabled((prev) => !prev)
  }

  const handleBrushChange = (domain: [number, number]) => {
    setBrushDomain(domain)
  }

  return (
    <div className='border-2 rounded-md px-1'>
      <div className='flex justify-between'>
        <div className='flex items-center mt-2 gap-x-2 py-1.5'>
          <Switch
            checked={isZoomingEnabled}
            onCheckedChange={handleToggleZooming}
          />
          <span className=''>
            {isZoomingEnabled
              ? 'Switch to Cursor Mode'
              : 'Switch to Zooming Mode'}
          </span>
        </div>
        <div className='flex items-center mt-2 gap-x-2'>
          <Switch checked={false} />
          <span className=''>Soll-Kurve</span>
        </div>
      </div>

      <div className='w-full wide:h-[40vh] desktop:h-[35vh]'>
        <ResponsiveContainer width='100%' height='100%'>
          <LineChart
            data={data}
            margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
          >
            <CartesianGrid strokeDasharray='3 3' />
            <XAxis
              dataKey='time'
              type='number'
              domain={brushDomain || ['dataMin', 'dataMax']}
              tickFormatter={(value) => value.toFixed(0)}
            />
            <YAxis
              domain={[-maxAbsValue, maxAbsValue]}
              tickFormatter={(value) => value.toFixed(2)}
            />
            <Tooltip />
            <Legend />
            <ReferenceLine y={0} stroke='gray' strokeDasharray='3 3' />
            <Line
              type='monotone'
              dataKey='voltage'
              stroke='#00B2D9'
              dot={false}
              name='Spannung (V)'
            />
            <Line
              type='monotone'
              dataKey='current'
              stroke='#D75900'
              dot={false}
              name='Strom (A)'
            />
            <Line
              type='monotone'
              dataKey='distance'
              stroke='#911EB4'
              dot={false}
              name='Weg (m)'
            />
            <Brush dataKey='time' height={30} stroke='#8884d8' />
          </LineChart>
        </ResponsiveContainer>
      </div>
    </div>
  )
}

export default CenteredZeroProcessDataChart


What optimizations or techniques can you recommend for handling large datasets like this efficiently in Recharts?

Additionally, any tips on improving performance with React in general for this use case would be greatly appreciated!

Upvotes: 0

Views: 71

Answers (0)

Related Questions