Address lookups with Leaflet and Nominatim
I recently wrote a patch for joind.in to add a map of an event's location to the event detail page. With the same patch, I also replaced the location part of the event edit page with a solution that uses JQuery, Leaflet as map API, OpenStreetMap tiles and Nominatim for doing address lookups. This article forms a small tutorial on how to use this same set-up yourself.
The Basics
To start, we create a new directory for our project:
mkdir addresses cd addresses
Then I downloaded the Leaflet and jQuery libraries and extracted them in the js directory of the project:
mkdir js curl -L https://github.com/CloudMade/Leaflet/zipball/v0.4.5 -o leaflet.zip unzip leaflet.zip mv CloudMade-Leaflet-*/dist/* js rm -rf CloudMade-Leaflet-* rm leaflet.zip curl http://code.jquery.com/jquery-1.8.2.min.js -o js/jquery-1.8.2.min.js
As first step, we are simply going to show a map on a web page. The map is going to be full screen, and will not have any bells and whistles. The code to embed a map is small, but we will separate it into three files for clarity: a CSS file for our styles (site.css), an HTML file for the structure (index.html) and a JS file for all our JavaScript functions (js/map.js).
Let's start with the HTML file:
<html>
<head>
<title>Leaflet and Nominatim example</title>
<link rel="stylesheet" href="js/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="js/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" type="text/css" href="site.css">
<script src="js/leaflet.js"></script>
<script src="js/jquery-1.8.2.min.js"></script>
</head>
<body>
<div id="map"/>
<script src="js/map.js"></script>
</body>
</html>
This HTML file includes the Leaflet and jQuery libraries, as well as the default CSS file that Leaflet needs. We are also including our own CSS file (site.css):
body {
margin: 0;
}
div#map {
width: 100%;
height: 100%;
}
In the body of the HTML file, we place a <div> as contained for the map, and then include a JavaScript file that is responsible for embedding them map:
var map;
function load_map() {
map = new L.Map('map', {zoomControl: false});
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
osmAttribution = 'Map data © 2012 <a href="http://openstreetmap.org">OpenStreetMap</a> contributors',
osm = new L.TileLayer(osmUrl, {maxZoom: 18, attribution: osmAttribution});
map.setView(new L.LatLng(51.538594, -0.198075), 12).addLayer(osm);
}
window.onload = load_map;
If you request the index.html page now through the browser, you will see something like:
Adding the Address Search
In order to add an address lookup form, we need to add more HTML. Our HTML will feature an input box (for the address), a submit button, and a place holder to show our results in. We add this code between the <div id="map"/> and the <script... tags:
<div id="search"> <input type="text" name="addr" value="" id="addr" size="10" /> <button type="button" onclick="addr_search();">Search</button> <div id="results"/> </div>
To style this, we add the following at the end of our CSS file:
div#search {
background-color: white;
position: absolute;
bottom: 40px;
left: 40px;
width: auto;
height: auto;
padding: 10px;
}
div#search input {
width: 200px;
}
div#results {
font-style: sans-serif;
color: black;
font-size: 75%;
}
If we reload the page in our browser, we will see something like:
Now the only thing left to do is to implement the addr_search function. In our JS file (js/map.js) we add before window.onload = load_map; the following lines (split over multiple sections in this tutorial):
function addr_search() {
var inp = document.getElementById("addr");
$.getJSON('http://nominatim.openstreetmap.org/search?format=json&limit=5&q=' + inp.value, function(data) {
This above line uses jQuery's AJAX capabilities to request a URL, parse the JSON result and issue a callback if it worked. We query Nominatim here, with as format json and limiting the result to 5 items. Nominatim also supports other parameters, which are documented here.
var items = [];
$.each(data, function(key, val) {
items.push(
"<li><a href='#' onclick='chooseAddr(" +
val.lat + ", " + val.lon + ");return false;'>" + val.display_name +
'</a></li>'
);
});
For each of the items in our result, we create an <li> element which has an <a href containing a call to a JavaScript function (chooseAddr). This function is responsible for re-centering the map according to the picked latitude and longitude.
$('#results').empty();
if (items.length != 0) {
$('<p>', { html: "Search results:" }).appendTo('#results');
$('<ul/>', {
'class': 'my-new-list',
html: items.join('')
}).appendTo('#results');
} else {
$('<p>', { html: "No results found" }).appendTo('#results');
}
});
}
This processes the results that came back from Nominatim. If there are results, we shows those including a Search results: header, and if there are no results, we show No results found.
Then we need to add one more function, the chooseAddr function which looks like:
function chooseAddr(lat, lng, type) {
var location = new L.LatLng(lat, lng);
map.panTo(location);
if (type == 'city' || type == 'administrative') {
map.setZoom(11);
} else {
map.setZoom(13);
}
}
We simply use the latitude and longitude from the function invocation, and in order to make things slightly nicer we zoom in a bit less if the item type is either a city or an administrative border. As each of the returned results actually includes a full bounding box, we probably can use that to zoom in better, but I will leave that for your own experiments - you'd want the panInsideBounds() method of Leaflet's Map class for that.
In the end, if we click on the Search button, a list is presented of all our search results:
And after clicking one of the links, we see the map centered on Paris:
The code for this example is available on github in my osm-tools repository at https://github.com/derickr/osm-tools/tree/master/leaflet-nominatim-example
Life Line
Updated a waste_basket
Created 11 benches, 2 life_rings, and 3 other objects; Updated 8 benches and a waste_basket; Deleted a bench and a log; Confirmed a cafe
I walked 7.8km in 1h52m27s
Tomorrow we have elections in the UK!
Lots of local authorities, all London Councils, the Welsh Senedd, and the Scottish Parliament.
Don't forget to vote if you have the right.
I get to vote for myself again 😎.
Benches, and corrections for the QE II Gardens
Addresses on College Road
Created 2 main entrances and an entrance; Updated an entrance, a residential building, and a house building
Created an apartments building and a main entrance
I walked 9.5km in 2h21m10s
Created a waste_basket
I walked 6.6km in 1h13m23s
On my walk from Aylesbury to Princes Risborough I spotted a few new bird species. I didn't get all the best photos though!
A Common Buzzard, a Yellow Wagtail, a Greater White throat, and a Green Woodpecker.
#photography #Birds #BirdPhotogaphy #BirdsOfMastodon #nature #Buckinghamshire
Updated an alcohol shop
I walked 9.4km in 1h58m25s
Updated 2 benches
Created a bench; Updated a bench
I hiked 19.0km in 4h35m50s
I hiked 19.0km in 4h35m50s
I walked 6.8km in 1h15m36s
Updated an estate_agent office
I walked 4.1km in 55m33s
I walked 1.1km in 10m05s
My First Lapwing!
I went to the London Wetland Centre yesterday, for a day out in nature.
While hiding in a hide, this chap and a friend showed up starting to forage for grubs.
#BirdPhotography #BirdsOfMastodon #Photography #Birds #London #Nature
Created a waste_basket; Updated a cafe and a restaurant; Confirmed an estate_agent office
I walked 6.6km in 1h8m53s



Shortlink
This article has a short URL available: https://drck.me/addrlookup-9mg