I have a dataset of 4360 geomarkers that I want to display on the Leaflet map. CircleMarker works just fine and the performance of the constructed map is ok. However, constructing the map takes too much time (around 20 seconds). Without react it takes a fraction of second to construct the markers. Is there a some performance hint or trick that can be used to make it construct the map faster?
import * as React from 'react';
import { Component } from 'react';
import { LatLng } from 'leaflet';
import { Map, TileLayer, CircleMarker, Popup } from 'react-leaflet';
export default class Editor extends Component {
state = {
lat: 51.505,
lng: -0.09,
zoom: 13,
markers : [ ]
}
componentDidMount() {
// data.csv contains several thousands of items
fetch('data.csv')
.then(res => res.json())
.then(data => this.setState({ markers: data.items.map(v => new LatLng(v.lat, v.lng)) }));
}
render() {
const markers = this.state.markers.map((v, i) =>
<CircleMarker key={i} center={v} radius={3} />);
return (
<Map center={new LatLng(51.505, -0.09)} zoom={this.state.zoom}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
{markers}
</Map>
)
}
}
Direct DOM manipulation does it in a fraction of a second:
export default class ItemsMap extends React.Component {
state = { items : [ ] };
map : L.Map;
componentDidUpdate(prevProps : any, prevState : any) {
this.renderItems(this.state.items);
}
componentDidMount() {
const node : any = ReactDOM.findDOMNode(this);
this.map = L.map(node).setView([51.505, -0.09], 13);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 }).addTo(this.map);
fetch('data.csv')
.then(res => res.json())
.then(data => this.setState({ items: data.items.map(v => new LatLng(v.lat, v.lng)) }));
}
renderItems(items : Array<any>) {
items.forEach(item => {
L.circleMarker(
[ item.lat, item.lng ],
{ radius : 3 }
).addTo(this.map);
});
}
render() {
return (
<div id="mapid" style={{ height: '100%' }} />
);
}
}
Now, let’s say you have a React-based website ( check out this starter I set up for you on Stack Blitz ), and you want to add a Leaflet map to showcase your mapping skills. There is actually a React binding for Leaflet, React-Leaflet.
The map is produced using Leaflet, which I want to publish on my blogdown site. However, with 60,000 points, the map is understandably quite slow. Here's a simplified example of what my code and map look like:
From the React-Leaflet docs: React Leaflet provides bindings between React and Leaflet. It does not replace Leaflet, but leverages it to abstract Leaflet layers as React components. As such, it can behave differently from how other React components work. So, let’s go over how to build a Leaflet map component inside of a React application!
I've been doing a big project with Leaflet over the last few months and started hitting performance problems with raster layers, so I'm interested to see how you go. You can verify whether you're actually using the Canvas renderer by right-clicking on the map. If it gives you image-related menu options, you're working with Canvas.
One technique to consider would be to render only a subset of markers within a given map boundary, it can dramatically reduce the time it takes to re-render the components as well as the number of DOM nodes created:
componentDidMount() {
fetch('data.csv')
.then(res => res.json())
.then(data => {
this.allMarkers = data.items.map(v => new LatLng(v.lat, v.lng));
displayMarkers();
});
}
where
displayMarkers() {
const map = this.mapRef.current.leafletElement;
const markers = this.allMarkers.filter(m =>
map.getBounds().contains(m)
);
this.setState({
markers: markers
});
}
Demo
Another optimization (leaflet specific) would be to set preferCanvas
to true
to render markers on canvas instead of SVG:
Whether Paths should be rendered on a Canvas renderer. By default, all Paths are rendered in a SVG renderer.
<Map
preferCanvas={true}
center={new LatLng(51.505, -0.09)}
zoom={this.state.zoom}
>
...
</Map>
The following demo demonstrates how to render 20k markers via react-leaflet
My problem was slightly different in that the points rendered in an acceptable period of time, but the pan and zoom are deathly slow. My native javascript application works fine. None of the suggestions here helped.
Why is Leaflet so slow at pan and zoom inside React?
I solved the problem by putting my native javascript map application inside an iframe on the react page. It is not an ideal solution and my hope is that a better one presents itself, but my guess is that it will require an update to either leaflet or react.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With