2

I'm using GeoJson of react-leaflet to display all polygons of an area. However, when the amount of data increase to 10000, the performance turns bad and my app has performance issues, cause it slow and laggy. How can I improve GeoJSon's performance on big data? My code :

 <Header />
      <MapContainer center={[10.7743, 106.6669]} zoom={5}>
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        <GeoJSON
          style={LayerStyle}
          data={polygonData.features}
          onEachFeature={onEachContry}
        />
      </MapContainer>

The data of polygonData.features is very big, it has 100k records

kboul
  • 13,836
  • 5
  • 42
  • 53
Nguyen Tu
  • 159
  • 4
  • 11
  • One solution could be to show geojson subsets conditionally depending on the area of the map you are when you zoom for instance on the map. If you have such a huge amount of data you should not visualize them all at once. – kboul Dec 23 '20 at 10:03
  • But I need this feature to display heatmap on my map. Do you know any solution ? – Nguyen Tu Dec 23 '20 at 11:16
  • If you could somehow share the geojson data in a github repo for example or something similar or share a url link where you fetch the data, I could try to help. – kboul Dec 23 '20 at 11:31
  • https://drive.google.com/file/d/1LQPGidSU52xXM-Pn6GXlVqVPmjKOo4lM/view?usp=sharing This is my geojson file data I want to display. The amount of data is very big. Thank you in advance – Nguyen Tu Dec 25 '20 at 10:04
  • thank you for accepting the answer. It would be nice if you could also upvote it. – kboul Dec 27 '20 at 15:11
  • Thank you. But your solution is only correct in case of small geojson data. I tried converting my geojson data ( 55MB) to Topojson and paste it in, the performance of app is still very bad and very slowly. Can you give me other solutions ? – Nguyen Tu Dec 28 '20 at 06:07
  • You a provided a geojson which size was 17.1 mb not 55mb so I was able to reproduce that specific case not with a bigger one. Other solutions for bigger data might involve serving your geojson via tiles but that includes serving your tiles via a server (geoserver f.i). – kboul Dec 28 '20 at 08:03

3 Answers3

3

You can try converting your big geojson into topojson. Because

topojson eliminates redundancy, allowing related geometries to be stored efficiently in the same file

as mentioned here, you can achieve significant smaller file size and thus better performance when you render it on your leaflet map.

You can use this site to convert your huge geojson(17.1mb) to topojson(2.7mb). You can see the difference in size after converting it. Note that it does not have unlimited free conversion capability.

After that you can create your own react wrapper to render a topojson. For this purpose you can use Vadim's answer on this stackoverflow post. It needs some adaptation to be compatible with react-leaflet v.3.x, and be able to add popups in each prefecture for instance, but after making some small changes you are able to visualize your huge geojson in topojson as it was a normal geojson.

function TopoJSON(props) {
  const layerRef = useRef(null);
  const { data, ...otherProps } = props;

  function addData(layer, jsonData) {
    if (jsonData.type === "Topology") {
      for (let key in jsonData.objects) {
        let geojson = topojson.feature(jsonData, jsonData.objects[key]);
        layer.addData(geojson);
      }
    } else {
      layer.addData(jsonData);
    }
  }

  function onEachFeature(feature, layer) {
    if (feature.properties) {
      const { VARNAME_3, NAME_0 } = feature.properties;
      layer.bindPopup(`${VARNAME_3}, ${NAME_0}`);
    }
  }

  useEffect(() => {
    const layer = layerRef.current;
    addData(layer, props.data);
  }, [props.data]);

  return (
    <GeoJSON ref={layerRef} {...otherProps} onEachFeature={onEachFeature} />
  );
}

and use it like this:

import topojson from "./phuong.json";

 <MapContainer ..>
      ...
     <TopoJSON data={topojson} />
  </MapContainer>

Demo

kboul
  • 13,836
  • 5
  • 42
  • 53
1

One way could be to reduce the features in your GeoJSON. The GeoJSON is huge (55MB) because it has a lot of geographic points, which could be simplified using the tool Mapshaper (mapshaper.org).

Before

enter image description here

After

enter image description here

0

So, the other way to approach this is using the Canvas Renderer. There's a package for a Leaflet Canvas marker layer. The issue is by default, Leaflet creates dom nodes for each feature that really hit performance with big layers like yours. The marker primitives, like Circle Marker can be rendered to canvas by default, but things like Icons take a little more work to render.

nizz0k
  • 471
  • 1
  • 8
  • 23