GEOG 585
Open Web Mapping

Working with GeoJSON

Print

GeoJSON is a widely-used data format for displaying vectors in web maps. It is based on JavaScript object notation, a simple and minimalist format for expressing data structures using syntax from JavaScript. In GeoJSON, a vector feature and its attributes are represented as a JavaScript object, allowing for easy parsing of the geometry and fields.

GeoJSON is less bulky than XML-based structures such as KML; however, GeoJSON does not always contain styling information like KML does. You must define the styling on the client, which in your case means writing JavaScript code or taking the Leaflet's default styling. This is covered in the next section of the lesson.

GeoJSON's simplicity and loading speed have made it popular, perhaps even trendy, among developers in the FOSS world. For example, in a tongue-in-cheek Internet poll, GIS practitioners recently voted "The answer is always GeoJSON" as the most likely attribute to define a 'GeoHipster'.

Here's what a piece of GeoJSON looks like. GeoJSON vectors are commonly bundled into a unit called a FeatureCollection. The FeatureCollection below holds just one feature (the state of Montana) but could hold other features. The bulk of the GeoJSON below contains the vertices that define the state outline, but you should also notice a few attributes, such as "fips" and "name":

{"type":"FeatureCollection","features":[{"type":"Feature","id":"USA-MT","properties":{"fips":"30","name":"Montana"},"geometry":{"type":"Polygon","coordinates":[[[-104.047534,49.000239],[-104.042057,47.861036],[-104.047534,45.944106],[-104.042057,44.996596],[-104.058488,44.996596],[-105.91517,45.002073],[-109.080842,45.002073],[-111.05254,45.002073],[-111.047063,44.476286],[-111.227803,44.580348],[-111.386634,44.75561],[-111.616665,44.547487],[-111.819312,44.509148],[-111.868605,44.563917],[-112.104113,44.520102],[-112.241036,44.569394],[-112.471068,44.481763],[-112.783254,44.48724],[-112.887315,44.394132],[-113.002331,44.448902],[-113.133778,44.772041],[-113.341901,44.782995],[-113.456917,44.865149],[-113.45144,45.056842],[-113.571933,45.128042],[-113.736241,45.330689],[-113.834826,45.522382],[-113.807441,45.604536],[-113.98818,45.703121],[-114.086765,45.593582],[-114.333228,45.456659],[-114.546828,45.560721],[-114.497536,45.670259],[-114.568736,45.774321],[-114.387997,45.88386],[-114.492059,46.037214],[-114.464674,46.272723],[-114.322274,46.645155],[-114.612552,46.639678],[-114.623506,46.705401],[-114.886399,46.809463],[-114.930214,46.919002],[-115.302646,47.187372],[-115.324554,47.258572],[-115.527201,47.302388],[-115.718894,47.42288],[-115.724371,47.696727],[-116.04751,47.976051],[-116.04751,49.000239],[-111.50165,48.994762],[-109.453274,49.000239],[-104.047534,49.000239]]]}}]}

In the GeoJSON above, notice the use of several JavaScript objects embedded within one another. At the lowest level, you have a Polygon object. The Polygon object is contained within a Feature object. The feature is part of a FeatureCollection object. The GeoJSON specification (originally published in 2008 but replaced by a new specification in 2016) gives precise details about how these objects are to be structured. It's important to be familiar with these structures, although you will rarely have to read or write them directly. You will typically use convenience classes or converter programs that have been developed to simplify the experience of working with GeoJSON.

You can use GeoJSON within your main JavaScript code file, but, to keep your things looking simple, it's most common to maintain the GeoJSON in its own separate file. You then reference this file from the appropriate place in your code. With Leaflet you have to define the GeoJSON as a JavaScript variable (seen here) using syntax such as

var <yourVariableName> = <yourGeoJSON>;

You would save this text in a file with a .js extension. For example, I could create a file titled myfeatures.js containing something like the following:

var myGardenJson = {"type":"FeatureCollection","features":[{"type":"Feature","id":"USA-MT","properties":{"fips":"30","name":"Montana"},"geometry":{"type":"Polygon","coordinates":[[[-104.047534,49.000239], . . . ]]}}]};

Then at the top of my HTML page, I need to put a reference to this file:

<script src="myfeatures.js"></script>

This allows me to reference the variable myGardenJson within my JavaScript code. Making a GeoJSON layer in Leaflet then becomes very simple:

var geojsonLayer = L.geoJSON(myGardenJson);
geojsonLayer.addTo(map);

It is important to note that L.geoJSON(…) expects all coordinates in the GeoJSON file to be WGS84 coordinates. That is why all GeoJSON files used in this lesson and Lesson 8 will use EPSG:4326. If instead you want to directly work with a GeoJSON file that uses a different projection (so without first reprojecting it to EPSG:4326), you can use the Proj4js Javascript library together with the Proj4Leaflet extension to enable support for coordinate reference systems not built into Leaflet. To do so, you would first have to add the lines to load the respective Javascript libraries at the beginning of the html file

<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.4.3/proj4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4leaflet/1.0.1/proj4leaflet.min.js"></script>

and then create the layer with

var geojsonLayer = L.Proj.geoJson(myGardenJson);

to have the code read what projection the GeoJSON file is in and then reproject the data accordingly on the fly. Leaflet, by the way, internally uses pixel coordinates for all data, so it understands locations with respect to the coordinate system of the map pane. That means that there is always a transformation process involved when loading vector data, independent of what projection the data comes in.

You can save any vector layer in QGIS as GeoJSON, and most web mapping APIs offer easy-to-use classes for GeoJSON as a vector display format. In the proprietary software realm, Esri has dragged its feet on GeoJSON support, offering its own JSON-based geometry formats as part of the GeoServices REST Specification and the ArcGIS REST API; however, Esri has informally shared an open source JavaScript library to convert between the two formats, which is now deprecated and replaced by their Terraformer tool.

The GeoJSON specification is not an OGC specification. At the time of this writing, OGC conspicuously lacks a JSON-based specification for defining vector GIS objects (OGC publishes the XML-based GML specification for vectors). This lack of an OGC-endorsed JSON specification played a role in the FOSS community's 2013 debate about whether the OGC should adopt the Esri-generated GeoServices REST Specification. The specification would have given OGC a JSON-based GIS data format, but some were wary of the format's association with a proprietary software company. The geoMusings "OGC Abandons the Web" blog post gives one FOSS geo-developer's opinion on the episode (read the comments, too).