This is an optional advanced topic on the GeoJSON data format, which those of you who are ahead might want to look at.
GeoJSON is a relatively new format for representing geographical data. As the name implies, it is based on JSON. It is typically supplied to clients by a web service; for instance, we might have a web service which supplies the location of points of interest close to a given latitude and longitude in GeoJSON format. Because GeoJSON is JSON based, it is easily parsed by JavaScript-based clients.
GeoJSON consists of a series of objects. These are:
Here is an example of some GeoJSON.
{ type: "FeatureCollection": features: [ { type: "Feature", geometry: { type: "Point", coordinates: [-1, 51] }, properties: { featureClass: "pub", name: "The Red Lion" } }, { type: "Feature", geometry: { type: "Point", coordinates: [-0.9, 51.1] }, properties: { featureClass: "restaurant", name: "Sams Burger Joint" } }, { type: "Feature", geometry: { type: "LineString", coordinates: [ [-1, 51], [-1.01, 50.99], [-1.01, 50.98], [-1.02, 50.97], [-1.04, 50.96] ] }, properties: { featureClass: "main road", number: "A987", name: "High Street" } } ] }Note how this GeoJSON consists of a FeatureCollection. The FeatureCollection in turn contains an array of Feature objects, each of which contains three fields:
Interpreting GeoJSON is the same as interpreting any other type of JSON. A client would typically send an AJAX request to a web service supplying GeoJSON, and then evaluate the GeoJSON returned to load it into a JavaScript variable, e.g. with JSON.parse() in standards-compliant browsers. We can then access the GeoJSON collection using JavaScript syntax. For example, in an AJAX callback:
function responseReceived(e) { var geojsonData=JSON.parse(e.target.responseText); alert(geojsonData.features[0].properties.name); // name of 1st feature //type of geometry of 1st feature alert(geojsonData.features[0].geometry.type); //longitude of 1st feature, assuming it's a point alert(geojsonData.features[0].geometry.coordinates[0]); //latitude of 1st feature, assuming it's a point alert(geojsonData.features[0].geometry.coordinates[1]); // longitude and latitude of 1st point of 3rd feature, assuming it's // a LineString alert(geojsonData.features[2].geometry.coordinates[0][0]); alert(geojsonData.features[2].geometry.coordinates[0][1]); }
If we are using Leaflet, however, it's easier than that. Leaflet comes with GeoJSON parsing built-in. Within Leaflet, you can create a GeoJSON Layer. With a GeoJSON layer, different types of GeoJSON feature will be automatically added as a corresponding Leaflet layer type (marker, polyline or polygon). So GeoJSON points will be added as Leaflet markers, and GeoJSON polylines and polygons as Leaflet polylines and polygons. Here is how to do this
First you add a GeoJSON layer in your init() function (note that geojsonLayer would need to be a global variable, declared outside of any function, so that the AJAX parsing function can access it):
var geojsonLayer = L.geoJSON();
The marker (or polyline or polygon, depending on the type of GeoJSON feature) is passed in to this anonymous function via the layer parameter. The marker, polyline or polygon has a feature property representing the GeoJSON feature. Using the feature we can then access its geometry or properties from JavaScript, so that, for example, feature.properties.name represents the name property of the current feature.
The above code defines the GeoJSON layer and defines how popups will appear, based on the feature's properties. However, we also need to actually add the features to the GeoJSON layer. This is typically done in an AJAX callback function, from an AJAX call to a web service which provides data as GeoJSON.
You loop through your GeoJSON features, and add them to your layer. To do this you use the geojsonLayer.addData() method, for example:
function resultsReturned (e) { var geojson = JSON.parse(e.target.responseText); for(var i=0; i<geojson.features.length; i++) { geojsonLayer.addData(geojson.features[i]); } }
On Edward2, at https://edward2.solent.ac.uk/wad/restaurants.php is a web service which generates GeoJSON of all restaurants within a given area stored in the restaurants table in the dftitutorials database. (This data is taken from OpenStreetMap, data copyright OSM contributors, licenced under Open Database Licence).
This takes one query string parameter, bbox (a bounding box). This consists of four values separated by commas: the western, southern, eastern and northern bounds of the area to query respectively. So if bbox is -1,51,0,52 for instance, only restaurants between longitude -1 and longitude 0 (1 West and 0) and latitude 51 North and 52 North will be returned. To call the script and instruct it to generate GeoJSON, use:
https://edward2.solent.ac.uk/wad/restaurants.php?bbox=west,south,east,north&format=geojson
var west= map.getBounds().getSouthWest().lng; var south= map.getBounds().getSouthWest().lat; var east = map.getBounds().getNorthEast().lng; var north= map.getBounds().getNorthEast().lat;You can also detect when a user stops dragging the map by reacting to the dragend event, eg:
map.on("dragend", onDragEnd);where onDragEnd would be a function to handle a drag end event.
What would be useful is to display some information about the feature when the user clicks the marker.
You specify an onEachFeature function when you create your L.GeoJSON object. The idea is that when a GeoJSON feature is added to the GeoJSON layer, the function specified in the onEachFeature property is called. Here is how this could be done: (the popup will remain hidden until the user clicks the feature)
var geojsonLayer = new L.GeoJSON(null, {onEachFeature: feature,layer => { layer.bindPopup("Name=" + feature.properties.name); } } );Note that this is an arrow function, which you first encountered in the AJAX topic. The function is automatically supplied with two parameters, feature, the GeoJSON feature we are adding, and layer, the marker we are adding the feature too. So feature.properties will contain the properties of the feature. So, the effect of this code is to attach a popup to the layer (the marker) associated with the feature, containing the feature's name.
for(var i=0; i<geojson.features.length; i++) { var id=geojson.features[i].properties.id; if (!indexedFeatures[id]) { indexedFeatures[id] = geojson.features[i]; geojsonLayer.addData(geojson.features[i]); } }Implement this. The GeoJSON contains a record of each feature's ID. You will need to make the array global, so that any function can access it, and create memory for the array in your init() function with:
indexedFeatures=new Array();
On Edward2, under the dftitutorials database, there is a table called restaurants representing restaurants. It contains lat, lon, and name columns.
list($w,$s,$e,$n) = explode(",", $_GET["bbox"]);This "explodes" the bbox variable into an array (the comma is the separator character), and list() then extracts the four elements of the array into the variables $w, $s, $e and $n.