On the client side, we need a basic HTML page with a Bing Maps map. We also need to perform two tasks:
- Write a mechanism for connecting to the geocoder HttpHandler
- Write a mechanism for users to enter and address and see the resulting geocode location.
We will also add another method for displaying a regular geocoded point in order to see the difference.
The Basic Page
Since you already have an ASP.NET web project, create a simple HTML page called Rooftop.html. Replace the contents of the page with the following:
<html >
<head>
<title>Rooftop Geocoding</title>
<script type="text/javascript"
src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5"></script>
<script type="text/javascript">
var map;
function OnPageLoad()
{
map = new VEMap('myMap');
map.LoadMap();
}
//Add Additional Code Here
</script>
</head>
<body onload="OnPageLoad();">
<div id="myMap" style="position:relative;width:600px;height:400px;"></div>
</body>
</html>Listing 4: Rooftop.html basic page
This basic page will display a map. In addition to the map, we need a field for the user to input an address and several other functions to help display the pushpins.
Adding Controls
Adding a text input box to our map will give the user a place to enter an address. Add the following <div> tag to Listing 4:
<div id="SearchPanel">
<table border=0 width='100%'>
<tr><td bgcolor='#C0C0CF'><p align='center'>Search</p></td></tr>
<tr><td><p align='left'>
Address
<INPUT id="txtWhere" type="text" value="" name="txtWhere" style="width: 225px">
</td></tr>
<tr><td bgcolor='#E0E0E0'><p align='center'>
<input type="button" value="Geocode" onclick="Geocode();"
id="Geocode" name="Geocode" />
</td></tr>
<table>
</div>Listing 5: Adding the controls
Next, we need to add a CSS style section to make the control easier to see:
<style type="text/css" media="screen">
#SearchPanel
{
width: 300px;
border-style: solid;
border-width: 1px;
border-color: lightgray;
background: white;
}
</style>Listing 6: CSS Styling for Find Control
Finally, we need to change the OnPageLoad method in Listing 4 to register the SearchPanel div and position it properly. Add the following lines to the end of OnPageLoad:
var geocode = document.getElementById('SearchPanel');
map.AddControl(geocode);
geocode.style.left = "300px";
geocode.style.top = "5px";Listing 7: Registering the control
If we load up the HTML page, it should look like this:
.jpg)
Figure 2: The Basic Page with the Find Control
Working with Pushpins
When a user enters an address and presses the Geocode button, we want to create two pushpins. One pin will be generated using rooftop geocoding. The other will be generated using the default Bing Maps geocoding. We can start by creating a method to draw custom HTML pins for each of our pushpins. Our method will accept a string indicating the geocode method and a VELatLong indicating the point.
function CreatePin(type, point)
{
if (point != 'Unavailable')
{
var icon = "<div style='font-size:12px;font-weight:bold;
border:solid 2px Black;background-color:Aqua;width:200px;'>"
icon += type + ":" + point.Latitude + " : " + point.Longitude;
icon += "<div>";
var spec = new VECustomIconSpecification();
spec.CustomHTML = icon;
var pin = new VEShape(VEShapeType.Pushpin, point);
pin.SetCustomIcon(spec);
map.AddShape(pin);
}
}Listing 8: Pin Generation
The next step is to add the methods for creating the default Bing Maps geocoded pin:
function AddRegularGeocode(address)
{
map.Find(null, address, null, null, 0, 10, false, false, false, true, ProcessResults)
}
function ProcessResults(layer, results, places, hasmore)
{
CreatePin("Default", places[0].LatLong);
}Listing 9: Adding a default geocoded pushpin
We need one last method to link our text box to the geocoding methods. Add the following function to respond to when the user pushes the "geocode" button:
function Geocode()
{
var where = document.getElementById('txtWhere').value;
AddRegularGeocode(where);
AddRooftopGeocode(where);
}Listing 10: The Geocode method
We now only need to figure out the AddRooftopGeocode method, which will be our link between the server side HttpHandler and the client side Bing Maps map.
The AJAX plumbing
In order to connect our client side JavaScript to our server side call to the MapPoint Web Service geocoder, we need to add three more methods:
- A mechanism for creating an XMLHttp Object to allow us to make HTTP calls.
- A callback method to handle the response from the HTTP request
- The AddRooftopGeocode method to make the HTTP request.
Creating an XMLHTTP object
Given that we want our application to run in several different types of browser, we can use a standard method for creating our XMLHttp object:
var xmlhttp=false;
function InitXmlHttp() {
// Attempt to initialize xmlhttp object
try
{
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
// Try to use different activex object
try
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (E)
{
xmlhttp = false;
}
}
// If not initialized, create XMLHttpRequest object
if (!xmlhttp && typeof XMLHttpRequest!='undefined')
{
xmlhttp = new XMLHttpRequest();
}
// Define function call for when Request obj state has changed
xmlhttp.onreadystatechange=SearchHandler;
}Listing 11: Creating an XMLHttp Object
This object will allow us to submit HTTP requests from the client side. When the response comes back, it will be processed by the SearchHandler function.
The SearchHandler function
The SearchHandler function is fairly simple. All we need to do is ensure that we've received the full response and then simply evaluate the response:
function SearchHandler()
{
if (xmlhttp.readyState==4)
{
eval(xmlhttp.responseText);
}
}Listing 12: The SearchHandler
The AddRoofTopGeocode Method
The last step is to use the XMLHttp object to call the GeocodingHandler in our server part of the application.
function AddRooftopGeocode(address)
{
InitXmlHttp();
var msg = "GeoCodingHandler.ashx?addr="+escape(address);
xmlhttp.open("GET", msg, true);
xmlhttp.send(null);
}Listing 13: Calling the HTTPHandler
The handler will return a result containing a call to the CreatePin method we defined in Listing 8.