I’m working on a page which reads GPX files (a series of lat/lon GPS points) and plots the route using React Leaflet as well as showing an elevation profile using react-chartjs-2.
When hovering over the elevation profile, the nearest data/GPS point is displayed on the map via a marker like so:
Unfortunately this causes a re-render every time, and results in laggy/stuttering performance when there are more than a few hundred GPS points (most of the GPX files I’m dealing with contain thousands).
I’m aware of hooks such as useMemo and useCallback but I’m not sure if/how they can be applied to my setup.
Any advice would be appreciated.
I attempted to make an interactive code sample earlier but it proved quite difficult due to the large amount of code as well as the various plugin imports/requirements, so here’s a rough outline of how it works:
function App() {
// Array containing several thousand GPS point objects
const gpsPoints = [
{
lat: 36.05287,
lon: -112.08383,
ele: 2193.501708984375,
time: '2020-03-21T14:19:02.000Z',
},
...
];
// The current index into the gpsPoints array, set when hovering over the elevation profile
const [pointIndex, setPointIndex] = useState(0);
return (
<>
<RouteMap gpsPoints={gpsPoints} pointIndex={pointIndex} />
<HeightMap gpsPoints={gpsPoints} setPointIndex={setPointIndex} />
</>
);
}
// Using React Leaflet library
function RouteMap({ gpsPoints, pointIndex }) {
const start = gpsPoints[0];
const position = gpsPoints[pointIndex];
return (
<MapContainer center={start}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Polyline positions={gpsPoints} />
<Marker position={position} />
</MapContainer>
);
}
// Using react-chartjs-2 library
function HeightMap({ gpsPoints, setPointIndex }) {
const options = { ... };
const data = { ... };
// Chart.js plugin API - calling setPointIndex(...) here is what causes performance to suffer
const plugins = [
{
id: 'show-marker',
afterDraw: (chart) => {
if (chart.tooltip?._active?.length) {
setPointIndex(chart.tooltip._active[0].index);
} else {
setPointIndex(0);
}
},
},
];
return <Line options={options} data={data} plugins={plugins} />;
}