Geocoding with Albuquerque Open Data

16 Jan

Albuquerque provides a large assortment of open data on their website. One service that I would find useful is a geocoding service. Digging around, I was able to find one that was not listed on the open data page. In my previous post, I showed you how to fake a geocoding service using the address points data set, but it had a serious flaw – it required an exact match. In this post, I will show you the correct way to geocode using the proper service.

Geocoding an Address

The first step is to create a widget that will allow a user to enter the address we want to find. The CSS and HTML below will create the widget for us.

#AddressSearchBox{
background-color: rgba(255, 255, 255, 0.5);
border: 1px solid #000;
-moz-border-radius: 15px;
border-radius: 15px;
height:40px;
width:350px;
padding-top:10px;
padding-left:5px;
position: absolute;
left: 40%;
top: 3px;
z-index: 100000;
}

<div style=”text-align: center”><div style=”text-align: left; margin: 0 auto; width: 50%;”>
<div id=”AddressSearchBox”> <center><b>Address:</b><input type=’text’ id=’addr’ name=’to’><button onclick=’GeocodeAddress()’>Search</button><center></div>
</div></div>

Now that we can accept user input, we need to write the GeocodeAddress function. The function is an AJAX call to the geocoding service. It will return a series of candidates with scores, however, for this example I will just grab the first result.  The code below sends an address, asks for the results in wkid:4326 and as JSON. We grab the first result, add a marker to the map and zoom.

function GeocodeAddress(){
var params = “Street=”+document.getElementById(“addr”).value+”&f=json&outSR=4326″;
var url = “http://coagisweb.cabq.gov/arcgis/rest/services/locators/CABQ_Composite/GeocodeServer/findAddressCandidates&#8221;
http=new XMLHttpRequest();
http.open(“POST”, url, true);
http.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
var thexy= JSON.parse(http.responseText);
x=thexy.candidates[0].location.x;
y=thexy.candidates[0].location.y;
console.log(x+”,”+y);
var yousearchedfor = L.marker([thexy.candidates[0].location.y,thexy.candidates[0].location.x]).addTo(map).bindPopup(‘<h3>’+thexy.candidates[0].address+'</h3>’).openPopup();
map.setView([thexy.candidates[0].location.y,thexy.candidates[0].location.x],18);
}}
http.send(params);}

That is all there is to it. The image below shows the results for 123 Sentral. Notice the street name is actually central. Because we are using a real geocoding service in this example we do not need exact matches.

Searching for Sentral

Now you can enter an address and find the result on a map. But with ESRI gecoding services you can also reverse geocode.

Reverse Geocoding

Reverse geocoding takes a point and returns the address. We will allow the user to click on the map and will return a marker with the address of the click. Our map will return coordinates in wkid:4326 (lat,long) but the service we are using is using wkid:3857. Now we have a problem – the points we will pass do not match the expected input to the service and we will receive no results back. I addressed projections in a previous post and  how we could pass an inSR and an outSR to the service. If you look again at the code above, we asked the geocoding service to outSR=4326, so can’t we just do that again in this example? No. The reverse geocoding service will not take inSR as a parameter. Here is the solution:

when an ESRI service does not allow an inSR parameter – for example adding a feature or reverse geocoding – you can assign the inSR value in the geometry you are sending.

What does this mean? It means that when the user clicks we need to send a point object to the service that looks like:

 location = {x:-106 , y:35, “spatialReference” : {“wkid” : 4326}}

Now we can code the reverse geocoding portion of our application. using Leaflet.js we can write:

map.on(“click”,function(e){ CODE HERE});

Inside the function, we need to make an AJAX call to the service passing the geometry as a parameter – with our spatial reference – and then get the results, draw a marker, and zoom. The code is shown below.

map.on(“click”,function(e){
var marker=L.marker(e.latlng);
coords=marker.toGeoJSON();
var urlgeocode=”http://coagisweb.cabq.gov/arcgis/rest/services/locators/CABQ_Composite/GeocodeServer/reverseGeocode&#8221;;
a1=”location={x:”;
a2=String(coords.geometry.coordinates[0]);
a3=”,y:”;
a4=String(coords.geometry.coordinates[1]);
a5=’,”spatialReference” : {“wkid” : 4326}}&distance=1000&f=json&outSR=4326′;
var geocodeparams =a1.concat(a2,a3,a4,a5);
var http=new XMLHttpRequest();
http.open(“POST”, urlgeocode, true);
http.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
results=JSON.parse(http.responseText);
L.marker([results.location.y,results.location.x]).addTo(map)
.bindPopup(‘<h3>’+results.address.Street+'</h3>’)
.openPopup();
map.setView([results.location.y,results.location.x],18);
}}
http.send(geocodeparams);
});

Now when a user clicks on the map, they will get the image below.

Reverse Geocoding

Reverse Geocoding

Advertisements

One Response to “Geocoding with Albuquerque Open Data”

Trackbacks/Pingbacks

  1. Reverse Geocoding a Line | Architecture and Planning - March 3, 2015

    […] Geocoding with ABQ Open Data, I showed you how to geocode an address and how to reverse geocode a point when the user clicks on […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: