0

I need to create a chart in react native that takes data (Array of integer) from a native module every 500 m/s and plots them in live update, to do this I used "react-native-svg", I can actually update the chart but performance is very slow and and crashes are frequent.

Array of result accept a maximum of 1800 results, after which the graph scrolls

...
 const [data, setData] = useState(new Array(1800).fill(0));
...

In listener take data from native module and update array, from the native module I pass an array of 60 elements, since it takes 60 elements every 500 m/s (e.values is the array of 60 integers)

...
setData(state => {
    state.splice(0, 60)
    return [...state, ...e.values]
})
...

The chart

...
    <LineChart
            style={ { flex: 1 } }
            data={data.map(dt => {
                return dt
            })}
            svg={ {
                strokeWidth: 2,
                stroke: '#2171bf',
            } }
            yMin={-5000}
            yMax={10000}
            numberOfTicks={25}
        >
            <CustomGrid belowChart={true} />
     </LineChart>
...

I tried other charts libs but they all give the same result

P.S. Sorry if the language is not perfect.

pippoBe
  • 26
  • 5

1 Answers1

1

I've struggled with performance when plotting in React Native with all of the SVG-based libraries I've tried. I recently decided to try using a couple canvas-based plotting libraries within a WebView and had very good results. I ended up making a simple package: https://www.npmjs.com/package/@dpwiese/react-native-canvas-charts.

Should you not want to use this package and instead do it yourself, it's quite straightforward. While the package source code is probably the best resource I'll summarize the steps below:

  1. Create an HTML file and import it into your component:
    const htmlTemplate = require("./index.html");
    
    where the HTML contains the JavaScript for the charting library of choice. The linked package above currently supports Chart.js v3 and uPlot. In the steps below I'll show a Chart.js configuration.
  2. Create a ref, for example let webref.
  3. Create a WebView and onLoadEnd you can inject some JavaScript into the WebView that will configure and create your chart
    <WebView
      originWhitelist={["*"]}
      ref={r  => (webref = r)}
      source={htmlTemplate}
      onLoadEnd={() => { addChart(config) }}
    />
    
    where addChart looks something like:
    const addChart = config => {
      webref.injectJavaScript(`const el = document.createElement("canvas");
        document.body.appendChild(el);
        window.canvasLine = new Chart(el.getContext('2d'), ${JSON.stringify(config)});`);
    };
    
    and config is a valid Chart.js configuration.
  4. To update the chart data simply inject some JavaScript to update the data. In the case of Chart.js here, that'd look like:
    const setData = dataSets => {
      if (dataSets) {
        dataSets.forEach((_, i) => {
          webref.injectJavaScript(`window.canvasLine.config.data.datasets[${i}].data = ${JSON.stringify(dataSets[i])};
          window.canvasLine.update();`);
        });
      }
    };
    
    where dataSets are valid Chart.js data sets.
  5. That's it! I've only played around with these two plotting libraries via the https://www.npmjs.com/package/@dpwiese/react-native-canvas-charts package, but so far performance has been really good, even with the JSON stringification of all the passed chart data. I haven't quantified it thoroughly, but both libraries are orders of magnitude more performant than any of the SVG-based ones I've tried.
Dharman
  • 30,962
  • 25
  • 85
  • 135
Daniel Wiese
  • 131
  • 2