The Chirp

GeoJSON to Shapefile

6/9/2020


No secret, I like geojson as geospatial data format. I just think it is simple, flexible, and interoperable. However, most of the GIS world likes shapefiles. They won't go away and it is probably the snarkiest data format on twitter. When people want geospatial data, they want a shapefile. Slightly depressing but it is still mostly true from my experience.

You know what gives me comfort? ––
You know, I know, all my detractors know: when the chips are down y'all will "Export to shapefile" pic.twitter.com/xoBxpbzWJj

— ShapefiIe (@shapefiIe) October 22, 2018

This past month, I updated my web-based geojson editor vector.rocks to have the option to download the data as shapefile. Not surprisingly, this was one of the first requests I got when I first shared this project with my coworkers. My first thought was to use shp-write to do the conversion. This project doesn't seem to be well maintained and intially didn't work for me, but I did get shp-write working after browsing some of the issues. I also noticed it didn't handle multi-part features and I wanted to minimize adding JavaScript so I kept looking.

I next turned to ogr2ogr web client. I have been using this site for years to quickly convert data back and forth between geojson and other formats. At the bottom of the page is a short section for 'Acessing Ogre using a POST request'. No examples are given and I only have a little experience doing POST requests. I struggled for a bit to get this implemination right. Intitally it was getting the header information correct, then it was handling the response as a blob.

In this example I used the fetch browser API instead of an XHR request. I actually put together this exact same function as an XHR request as well, but for some reason I gravitate to fetch because I feel it is simple. Any thoughts on prefered async techniques?


function convertGeoJsonToShpThenDownload(geoJson,filename){
  var url = "https://ogre.adc4gis.com/convertJson";
  var options = {
    method: "POST",
    headers: {"Content-type":"application/x-www-form-urlencoded"}, 
    body: "json=" + JSON.stringify(geoJson)
  };
  fetch(url,options)
  .then(function(response){
    return response.blob();
  })
  .then(function(data){
    var link = document.createElement("a");
    document.body.append(link);
    link.href = URL.createObjectURL(data);
    link.download = filename + ".zip";
    link.click();
  });
}

What this function does is take the response as a blob, creates an anchor element and then invokes a click event on it to start the download. The anchor element does not appear to be visible in your page. This initally was a concern of mine, but I found it not to be a problem for my use.

The one concern with this technique is geoJSON of differing geomeries as shapefiles can only support 1 geometry type, but this was not a concern of mine for Vector.

Add this function to any button's event listener and all of a sudden you have a shiny button to download some geoJSON as a shapefile. The one unsolved concern is how to set the name of the shapefile itself from the resulting zipped download.