Hi, in this quick tutorial we will have a look at a new JavaScript mapping library, Leaflet using it to help load JSON features from a GeoCommons dataset. We will add our Acetate tile layer to the map, and use the cool API feature filtering functionalities to get just the features we want from the server, show them on a Leaflet map, add popups to the features, style the features according to what the feature is, and add some further interactivity. This blog follows up from two posts on my personal blog, showing GeoCommons features with OpenLayers and with Polymaps.

The dataset we will use is Leeds Buildings 2011 – it’s shows all the buildings in the District of Leeds, UK, that were in the OpenStreetMap database as of July 2011. I made it from the England shapefile export from GeoFabrik.de, and can highly recommend checking out the download pages at GeoFabrik if you want to play with some OpenStreetMap data yourself.

Leaflet is a modern, lightweight BSD-licensed JavaScript library for making tile-based interactive maps for both desktop and mobile web browsers, developed by CloudMade. I think it’s pretty nice, and they have some good examples. I’d be interested to hear if you can view this map with mobile devices.



Get Leaflet.

First go ahead an get Leaflet from http://leaflet.cloudmade.com/. Make sure you add on your page the link to the correct js file in the dist directory.



Make a Map

We set up everything on the init function called by the body onload event. var myMap = new L.Map('map'); sets everything up with a div in the body with the id as “map” <div id="map" style="height: 90%;"></div>



Add Acetate tile layer

Acetate is the result of GeoIQ’s set of Mapnik stylesheets and algorithms to create good quality basemaps especially for overlaying data on top.
It’s a tile layer, and tile layers are usually defined according to the ZXY scheme. An example tile URL would be http://a2.acetate.geoiq.com/tiles/acetate/13/4059/2638.png

var acetateUrl =  'http://{s}.acetate.geoiq.com/tiles/acetate/{z}/{x}/{y}.png';
var acetateAttrib = '2011 GeoIQ &#038; Stamen, Data from OSM and Natural Earth';
var acetate = new L.TileLayer(acetateUrl, {maxZoom: 18, attribution: acetateAttrib, subdomains: ['a1', 'a2', 'a3']});

The first line, we define the pattern for Leaflet to understand. The second line defines the attribution to show with the layer, and the last line, creates the TileLayer and passed in some options, the main thing here is the use of the {s} variable in the url and the subdomains option. {s} will be replaced with a1, a2 or a3, to create a proper image, like above.

var leeds = new L.LatLng(53.796, -1.551);
myMap.setView(leeds, 14).addLayer(acetate);

Now we create a LatLng object, centred over Leeds, UK, and then set the view for the map, and method chain adding the acetate layer to it. Once you’ve done this, you will actually see a map!



GeoiQ Features API & Get JSON Features

The features REST API allows a developer to get all the features within a radius, specifying the lat lon of the centre of the radius and the distance.

var geojsonLayer = new L.GeoJSON();

var url = "http://geocommons.com/datasets/168923/features.json?lat=53.796&amp;lon=-1.551&amp;radius=3&amp;callback=?"; 

jQuery.getJSON(url, function(data){
	jQuery.each(data, function(i,f) {
		f.properties = {name: f.name, osm_id: f.osm_id, type: f.type};
		f.type = "Feature";
		// Now Push into geojson layer each feature
		geojsonLayer.addGeoJSON(f);
	});
});

myMap.addLayer(geojsonLayer);

lat=53.796&lon=-1.551&radius=3 Is our spatial filtering. It says, given a point at Lat 53.796 and Lon -1.551, give me all the features within a radius of 3KM. Interestingly, we can also use the units param to specify the units of distance, if you like your imperial units!

I’m using JQuery here, as it’s got some nice helpers. This grabs the JSON, and loops over the features, adding features to the geojson layer. Using the addGeoJSON method call.

Did you know that the features API also has the ability to filter by many different ways, for example by polygon, and by buffered polygon? polygon=-77,34,-78.5,34.5,-82,32,-79,30,-77,34&amp;radius=100. I particularly like the filter functionality. In our example, we could have just filtered the map to just show hospital buildings.
http://geocommons.com/datasets/168923/features.json?filter[type][][equals]=hospital&amp;callback=?



Add popup

We have to use the featureparse event on the geojsonLayer, and specify this before any things are added to the map.

geojsonLayer.on("featureparse", function (e) {
if (e.properties &#038;& e.properties.name){
   e.layer.bindPopup(e.properties.name +"<br />"+e.properties.type);
}

The featureparse event is called just before features are added to the layer. Here it’s looking at the feature, and if it has a name in the properties, then to create a popup, showing the name and type



Add click handler

We add a click handler within the same feature parse event handler.


if (e.properties &#038;& e.properties.osm_id) {
 e.layer.on('click', function(ee){
   Query(".info").html("<a href='http://www.openstreetmap.org/browse/way/" +
   e.properties.osm_id+"'>OSM ID: "+e.properties.osm_id + "</a><em> Name: </em>"+
   e.properties.name + "  (<em>type: </em>" +e.properties.type+")");
 });
 }

Here, we use a bit of Jquery to update the value of a div with the details of the feature. It shows the osm id, and a link to the openstreetmap website for that feature, and some values.



Add categorical styling

This bit is a bit more complex, but essentially, the SVG features are styled using CSS, and can be styled accordingly. Within the same featureparse event handler, again, set up before features are added to the layer, we look to see if the feature has a type (like, hospital, retail etc), and if it has, then it’s given a style. We only really change the style colour.


if (e.properties &#038;& e.properties.type &#038;& e.layer.setStyle){
      var color = "#334DCC";
      var t = e.properties.type;
      var colormap = {
        "hospital":"#CC3399",
        "residential":"#CC6633",
        "house":"#CCB333",
        "school":"#99CC33",
        "retail":"#D864B1",
        "commercial":"#006600"};
      
      color = colormap[t] || color;

 e.layer.setStyle({"color":color,"weight": 2,"opacity": 1 });
}


Give it a go!

Try out the playable demo, and if you want you can have a look at the code too.
All the code can be found here:
And a playable dem

 

Comments are closed.