33

I am using leaflet.js to allow web users to select a region. Valid regions are US states, Canadian providences, and world countries (except for US and Canada). I constructed a shapefile myself using Qgis and saved it as a geojson. I simplified the geometries as much as I could.

The resulting shapefile is 400kb, but the geojson is over a megabyte. This is bigger than I would like. I need to reduce the network overhead involved in transferring this information.

What is the right way to do this?

The options I can imagine are:

  1. Serve the geojson file gzipped, unpack on the client.
  2. Parse the shapefile on the client to geojson
  3. Generate my own tiles from the shapefile and serve those
PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Mike Furlender
  • 587
  • 1
  • 6
  • 14

6 Answers6

30

Mapshaper.org is a handy free online tool that allows you to upload a geojson file, display it as a map, then choose one of three simplification algorithms which you can adjust the strength of with a slider.

It updates the map and highlights in red any places where there's a loss of integrity like an overlap between two regions. There's a 'fix' button that usually (but not always) fixes such problems.

You can find a level of simplification that is acceptable and export the newly simplified geojson file.

Obviously this depends on what level of detail you need, but the results can be impressive. For example, here's map of Scotland from a 40MB geojson file:

enter image description here

A 99% application reduces it to a 441KB file with no overlaps and loss of detail that is invisible at this zoom level:

enter image description here

A 99.95% application (down to 29KB) shows what sort of path simplification is being applied (and still manages to avoid overlaps, and is perfectly suitable for uses like national-level chloropleth):

enter image description here

yamanidev
  • 103
  • 3
15

Before going down any more laborious paths, the simplest option is to reduce the geometry. What are your source datasets? How did you simplify them? How much did this reduce the geojson file size?

If you are confident that you have done all you can on the above, then the lowest hanging fruit of your options is

  1. Serve the geojson file gzipped, unpack on the client.

All modern browsers do the unpacking of gzipped data automatically, so it's just a case of setting up your web server to pack up the data before sending. This is normally a relatively straight forward, with much material around out there for Apache, IIS or Nginx

My tip would be to try this first, test, then if latency / response / data size is not acceptable, then move to other options. I would also be wary of trying to optimise prematurely, I would be looking to determine why you need to reduce the data size, and once you have hard reasons (and numbers) for doing so, then iteratively implementing changes and re testing to see what gains you are getting.

Kelso
  • 1,916
  • 13
  • 20
8

I wonder if you could make use of the compression found in this answer that talks about compressing the GeoJSON with topojson.

I don't know if Leaflet will still be able to read the GeoJSON - something to try =)

More about topojson: https://github.com/mbostock/topojson/

SaultDon
  • 10,389
  • 1
  • 43
  • 78
3

I agree with @Kelso above on simplifying your geometry.

If you don't have access to your server to deflate the data with gzip easily you could take a look at the MessagePack library to serialise your geoJSON into binary data. There are libraries in Python and JavaScript (among others) that you can use to serialise/deserialise the data.

PolyGeo
  • 65,136
  • 29
  • 109
  • 338
om_henners
  • 15,642
  • 2
  • 46
  • 86
2

Working a lot on webproject with GeoJSONs, I had this issue frequently. My solution: The GeoJSON-related filetype BrokJSON (brokjson.dev). Depending on your GeoJSON it can reduce the size dramatically without loosing any data.

Look at this GeoJSON with two points and some data:

{
  "type": "FeatureCollection",
  "features": [
  {
    "type": "Feature",
    "properties": {
      "id": 1,
      "title": "Datapoint 1",
      "value": 343
    },
    "geometry": {
      "type": "Point",
      "coordinates": [8.5402,47.3782]
    }
  },
  {
    "type": "Feature",
    "properties": {
      "id": 1,
      "title": "Datapoint 2",
      "value": 14
    },
    "geometry": {
      "type": "Point",
      "coordinates": [8.5637,47.4504]
    }
  }]
}

Transformed to BrokJSON it looks like this:

{
  "properties": ["id", "title", "value"],
  "geometries": [{
    "type": "Point",
    "features": [
      [[8.5402, 47.3782], [1, "Datapoint 1", 343]],
      [[8.5637, 47.4504], [1, "Datapoint 2", 14]]
    ]
  }
]}

I store my geodata as a BrokJSON and transform them for MapBox or leaflet on runtime to GeoJSON.

More details: https://www.brokjson.dev

PolyGeo
  • 65,136
  • 29
  • 109
  • 338
1

I would suggest just creating your own procedural array of Leaflet Polygon objects. I agree with GeoJSON being way too big. The object key names are very descriptive but maybe unnecessarily long as well. I do this kind of thing:

objects = [];
objects.push( new L.polygon([[1,1],[1,2],[3,4]],options );
objects.push( new L.polygon([[4,7],[8,27],[35,66]],options );
objects.push( new L.polygon([[3,5],[56,24],[13,49]],options );
objects.push( new L.polygon([[13,7],[7,68],[23,9]],options );
layerGroup = L.layerGroup(objects).addTo(map);

It's straightforward. It's much more lightweight than GeoJSON like this:

{ "type": "FeatureCollection",
  "features": [
    { "type": "Feature",
      "geometry": {"type": "Polygon",
      "coordinates": [1,1],[1,2],[3,4]},
      },

    //etc...

And Repeat for every single polygon... ugh... way too bloated imo. Adds a lot of bytes to your JS. Like I said, the key names are nice and descriptive... but they are long and add a lot of unnecessary byes to your JS.

Jake Wilson
  • 111
  • 3