CoverStory
LANGUAGES: JavaScript | VB.NET
ASP.NET VERSIONS: 2.0
Geo-tag Your Photos Using ASP.NET and Google Maps: Part I
Getting Started with the Google Maps API
By Wei-Meng Lee
The Google Maps API is a free mapping service that allows
you to embed maps into your Web pages using JavaScript. Besides displaying
maps, Google Maps enables you to insert markers at landmarks of interest. This
feature is very exciting because you can use it to associate photos with
different geographical locations (a process known as geo-tagging). For example,
you can display your vacation photos in Google Maps so that, besides viewing
the photos, you know the exact location where you took the photos.
This two-part series demonstrates how to build an ASP.NET
Web application that allows users to upload photos and geo-tag them using
Google Maps. Part I shows you how to get started with the Google Maps API.
Using Google Maps
To use Google Maps, you must sign up for a Maps API key at
http://www.google.com/apis/maps/signup.html.
However, the key for which you apply is only valid for a particular directory
on your Web server. For example, if you want to display a map on
www.mysite.com/myApp/mypage.html, you must apply for a Maps API key for
www.mysite.com/myApp/; this key will only work for the pages in this directory.
Note: Because the
Google Maps API key is tied to the URL of your Web application, you cannot use
Google Maps within a Windows application.
Creating the Application
Using Visual Studio 2005, create a new ASP.NET
AJAX-enabled Web Site project and name it GoogleMaps. Once the project is
created, press F5 to run it. The main purpose is to get the URL for the Web
application so you can apply for a valid Maps API key for this application. I m
using the built-in Web server that shipped with Visual Studio 2005, so my URL
looks something like this: localhost:2139/GoogleMaps/. You ll most likely have
a different port number (2139, in my case), but use your own URL to apply for a
Maps API key.
Tip: For development purposes, it is good to set the Use
dynamic ports property of the project to False so Visual Studio 2005 will
always use the same port number for your project (set the port number in the
Port number property; see Figure 1).
Figure 1: Use a static port number
for your ASP.NET Web application.
Once you have a valid Maps API key, you can use Google
Maps easily. Insert in the Source View of the Default.aspx page the <script>
element containing the JavaScript that will load the Google Maps, as shown in
bold in Figure 2.
<head id="Head1" runat="server">
<title>Untitled
Page</title>
<script src="http://maps.google.com/maps?file=api&
v=2&key=ABQIAAAA26ROxQdKhHJQA3ZbT3HkSBTWrCUD1_
1cGNyM6E4_IspVr1prIxQPz04xVq0xNfzxTGPpQ_lcCEcotQ"
type="text/javascript">
</script>
<script
type="text/javascript">
function load() {
if (GBrowserIsCompatible()) {
var map = new
GMap2(document.getElementById("map"));
//---set the center point for the map---
map.setCenter(new
GLatLng(37.65528588731535,
-122.40726470947265), 13);
}
}
</script>
</head>
Figure 2: The <script>
element containing the JavaScript that will load the Google Maps.
Note that you must replace the following:
key=ABQIAAAA26ROxQdKhHJQA3ZbT3HkSBTWrCUD1_1cGNyM6E4_
IspVr1prIxQPz04xVq0xNfzxTGPpQ_lcCEcotQ
with your own key:
key=your_own_valid_Maps_API_key
Also, insert the following (shown in bold) in the <body>
element so that, when the page is loaded, the JavaScript load function will be
invoked to load the Google Maps:
<body onload="load()">
<form
id="form1" runat="server">
<div id="map" style="width: 500px; height:
300px"></div>
</form>
</body>
That s it! Press F5 to test the application. You should
now be able to see the Google Maps (see Figure 3).
Figure 3: Viewing Google Maps on the
Default.aspx page.
Map Navigation
Now that you have Google Maps working, let s modify the
application so we can get more out of Google Maps. (You ll find the online
documentation of the API very useful as you dive deeper into the Google Maps
API: http://www.google.com/apis/maps/documentation/reference.html#GMap2.)
First, let s add two TextBox controls and one button
control to the Default.aspx page (see Figure 4). Figure 5 shows how the
Default.aspx page should now look.
<form id="form1" runat="server">
<div
id="map" style="width: 500px; height: 300px">
</div>
Latitude
<asp:TextBox ID="txtLatitude"
runat="server"></asp:TextBox>
<br />
Longitude
<asp:TextBox ID="txtLongitude"
runat="server"></asp:TextBox>
<br />
<input id="btnGotoLocation"
type="button"
value="Go to Location"
onclick="goto_map_position()" />
<br />
</form>
Figure 4: Add two
TextBox controls and one button control to the Default.aspx page.
Figure 5: The Design View of
Default.aspx.
For the button control, I used the HTML Input element
instead of the ASP.NET Button control. This is because I don t need a postback
to occur when the button is clicked. Instead, it will directly invoke the
JavaScript goto_map_position function (as set in the onclick attribute) when
clicked.
Here are the new features to be added to our application:
- As the map is dragged, the latitude and
longitude will be updated on the two TextBox controls.
- You can also go to a specific location by
entering the latitude and longitude of the new location and clicking the Go to
Location button.
Back in the Source View of Default.aspx, move the
declaration of the map variable to the top, making it a global variable:
<script type="text/javascript">
var map = null;
Next, rewrite the load function as shown in Figure 6.
function load() {
if
(GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
//---display
navigational controls---
map.addControl(new
GSmallMapControl());
//---display
Map/Satellite/Hybrid---
map.addControl(new
GMapTypeControl());
//---fired when the map
is dragged---
GEvent.addListener(map,
"moveend",
function()
{
var center =
map.getCenter();
//---update the
lat and lng in the TextBox controls---
document.forms[0].txtLatitude.value = center.lat();
document.forms[0].txtLongitude.value = center.lng();
}
);
//---display a
particular location on the map---
map.setCenter(new
GLatLng(37.65528588731535, -122.40726470947265), 13);
}
}
Figure 6: Rewrite
the load function.
The load function essentially adds to the map the
navigation controls, as well as the types of map controls. You then add an
event handler (moveend) so that when the user employs the mouse to drag the
map, you ll display the latitude and longitude information in the two TextBox controls
when they release the mouse button. Note that the latitude and longitude
information displayed always refers to the center of the map.
Figure 7 shows that the changes made in the load function
will cause the map to display the navigational controls, as well as the
different types of maps from which you can choose (Map, Satellite, or Hybrid).
Figure 7: Displaying the additional
controls on the map.
Next, define the goto_map_position function, which is
invoked when the user clicks the Go to Location button:
//---navigate to a particular location---
function goto_map_position()
{
//---extract the lat and
lng from the TextBox controls---
var lat =
document.forms[0].txtLatitude.value;
var lng =
document.forms[0].txtLongitude.value;
map.panTo(new
GLatLng(lat,lng));
}
The goto_map_position function moves the map to the
location specified using the panTo method.
To test the application, press F5 in Visual Studio 2005.
Drag the map and observe the change in the latitude and longitude information.
To centralize a location on the map, double-click on the location and the
selected location will appear in the center of the map (see Figure 8).
Figure 8: Navigating to a particular
location.
Adding a Marker to the Map
Now that you ve successfully loaded Google Maps on your
page, let s add some new interesting features to it. You can add a marker to a
location so you can use it as a reference point. To do so, let s first define
the AddMarker JavaScript function:
function AddMarker()
{
//---set the location to
add the photo---
var centerPoint = new
GPoint(
document.forms[0].txtLongitude.value,
document.forms[0].txtLatitude.value);
//---create a new marker
object---
var marker = new
GMarker(centerPoint);
//---add the marker---
map.addOverlay(marker);
}
The AddMark function creates a marker, then adds it to the
map using the latitude and longitude specified in the two TextBox controls. Next,
add the AJAX ScriptManager control to the top of the page and set its
EnablePartialRendering attribute to true:
<body onload="load()">
<form id="form1"
runat="server">
<asp:ScriptManager ID="ScriptManager1"
runat="server"
EnablePartialRendering="true">
</asp:ScriptManager>
<div id="map"
style="width: 500px; height: 300px">
</div>
Insert an UpdatePanel control on the page; within its <ContentTemplate>
element, add an Add Marker button:
<input
id="btnGotoLocation" type="button"
value="Go to
Location" onclick="goto_map_position()" />
<br />
<br />
<asp:UpdatePanel
ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Button
ID="btnAddMarker" runat="server"
Text="Add Marker"
Width="104px"
OnClientClick="AddMarker()" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
Notice that I ve used a Button control instead of the HTML
Input element. Either method is acceptable. For the Button control, set the
OnClientClick attribute to AddMarker so it will invoke the AddMarker function
when clicked. Figure 9 shows how the page should look.
Figure 9: Default.aspx with the new
controls added.
Press F5 in Visual Studio 2005 to test the application.
Select a location and click the Add Marker
button; you ll notice that Google Maps displays an icon at the location
selected (see Figure 10).
Figure 10: Adding a marker to the
map.
Besides adding an icon to represent the marker, you can
also display a balloon when the marker is clicked. To do so, add an event
handler to the marker using the GEvent.addListener method (see Figure 11).
function AddMarker()
{
//---set the location to
add the photo---
var centerPoint = new
GPoint(
document.forms[0].txtLongitude.value,
document.forms[0].txtLatitude.value);
//---create a new marker
object---
var marker = new
GMarker(centerPoint);
//---add the click event for the marker---
GEvent.addListener(marker,
"click",
function() {
//---open the marker info tab---
marker.openInfoWindowHtml("<b>Marker 1</b>");
});
//---add the marker---
map.addOverlay(marker);
}
Figure 11: Add an
event handler using the GEvent.addListener method to display a balloon when the
marker is clicked.
When the marker is clicked, it will display the content
specified as the argument for the openInfoWindowHtml method (from the marker
object). The openInfoWindowHtml method takes in a single parameter, which can
be plain text or an HTML string. Figure 12 shows the marker displaying a
balloon showing the text Marker 1 .
Figure 12: Displaying a balloon on a
marker.
When you click elsewhere on the map, the balloon will
disappear. To view the balloon again, click on the marker. You can also
organize into tabs the information displayed in the balloon (see Figure 13); Figure
14 shows the balloon organized into two tabs.
function AddMarker()
{
var infoTabs = [
new GInfoWindowTab("Tab 1",
"Content for tab 1"),
new GInfoWindowTab("Tab 2",
"Content for tab 2")
];
//---set the location to
add the photo---
var centerPoint = new
GPoint(
document.forms[0].txtLongitude.value,
document.forms[0].txtLatitude.value);
//---create a new marker
object---
var marker = new
GMarker(centerPoint);
//---add the click event for the marker---
GEvent.addListener(marker,
"click",
function() {
//---open the marker info tab---
marker.openInfoWindowTabsHtml(infoTabs);
});
//---add the marker---
map.addOverlay(marker);
//---open the marker
info tab---
marker.openInfoWindowTabsHtml(infoTabs);
}
Figure 13: Organize
into tabs the information displayed in the balloon.
Figure 14: Displaying tabs in a
marker.
You can drag the marker to another position after adding
it to the map. To do so, you must specify that the marker is draggable at the
time you create the marker object. You also need to add two event handlers,
dragstart and dragend. The dragstart event is fired when the marker is dragged
(with the mouse button down). The dragend event is fired when the user releases
the mouse button. As shown in Figure 15, when the user starts to drag the
marker, I ll hide the balloon and display another balloon when the user
releases the mouse button. Figure 16 shows the marker before and after
dragging.
function AddMarker()
{
var infoTabs = [
new
GInfoWindowTab("Tab 1", "Content for tab 1"),
new
GInfoWindowTab("Tab 2", "Content for tab 2")
];
//---set the location to
add the photo---
var centerPoint = new
GPoint(
document.forms[0].txtLongitude.value,
document.forms[0].txtLatitude.value);
//---create a new draggable marker object---
var marker = new GMarker(centerPoint,
{draggable: true});
//---add the click event
for the marker---
GEvent.addListener(marker, "click",
function() {
//---open the marker
info tab---
marker.openInfoWindowTabsHtml(infoTabs);
});
//---start dragging---
GEvent.addListener(marker,
"dragstart", function() {
map.closeInfoWindow();
});
//---end dragging---
GEvent.addListener(marker, "dragend",
function() {
marker.openInfoWindowHtml("Marker
moved!");
});
//---add the marker---
map.addOverlay(marker);
//---open the marker
info tab---
marker.openInfoWindowTabsHtml(infoTabs);
}
Figure 15: The dragstart
and dragend event handlers.
Figure 16: Moving a marker.
Because the content for the balloon can take in an HTML
string, you can easily insert images into the balloon by using the <img>
HTML element. The example in Figure 17 inserts into the balloon a picture from
another site; Figure 18 shows how the balloon looks.
function AddMarker()
{
//---HTML for displaying the photo---
var content = '<img width="300"
Height="210"
src="http://www.visitingdc.com/images/
golden-gate-bridge-picture.jpg"
/>';
var infoTabs = [
new GInfoWindowTab("Tab 1",
content),
new
GInfoWindowTab("Tab 2", "Content for tab 2")
];
//---set the location to
add the photo---
var centerPoint = new
GPoint(
document.forms[0].txtLongitude.value,
document.forms[0].txtLatitude.value);
var marker = new
GMarker(centerPoint, {draggable: true});
//---add the click event
for the marker---
GEvent.addListener(marker, "click",
function() {
//---open the marker
info tab---
marker.openInfoWindowTabsHtml(infoTabs);
});
//---start dragging---
GEvent.addListener(marker, "dragstart", function() {
map.closeInfoWindow();
});
//---end dragging---
GEvent.addListener(marker, "dragend", function() {
marker.openInfoWindowHtml("Marker
moved!");
});
//---add the marker---
map.addOverlay(marker);
//---open the marker
info tab---
marker.openInfoWindowTabsHtml(infoTabs);
}
Figure 17: Insert
images into the balloon by using the <img> HTML element.
Figure 18: Displaying an image in a
marker balloon.
Searching for Locations
Another useful feature to add to Google Maps is the
ability to search for locations. To demonstrate how, add the following HTML in
the Source View of Default.aspx:
<ContentTemplate>
<asp:Button ID="btnAddMarker"
runat="server"
Text="Add
Marker" Width="104px"
OnClientClick="AddMarker()" />
<br />
Enter address to search:
<asp:TextBox ID="txtAddress"
runat="server">
</asp:TextBox>
<asp:Button ID="btnSearch"
runat="server" Text="Search"
Width="104px"
OnClientClick="findAddress()" />
</ContentTemplate>
Next, declare the geocoder object as follows:
<script type="text/javascript">
var map = null;
var geocoder = new
GClientGeocoder();
Then, define the findAddress JavaScript function, as shown
in Figure 19.
function findAddress() {
//---get the address to
search for---
var address =
document.forms[0].txtAddress.value;
geocoder.getLatLng(address,
function(point) {
//---if address is
not found---
if (!point) {
alert(address +
" not found");
} else {
//---address
found---
map.setCenter(point, 13);
//---create a new
marker---
var marker = new
GMarker(point);
//---close the
marker if it is clicked---
GEvent.addListener(marker, "click", function() {
if (marker) {
//---close
the balloon---
map.closeInfoWindow();
//---remove
the marker---
map.removeOverlay(marker);
}
});
//---add the
marker---
map.addOverlay(marker);
//---display the
address---
marker.openInfoWindowHtml("Found: " + address);
}
}
);
}
Figure 19: Define
the findAddress JavaScript function.
The findAddress function searches for a specified address
using the getLatLng method from the geocoder object. Because the search may
take some time, you need to define a function so it can process the returning
result later. The found address is returned as a point object, which you will
use to add a marker on the map. In addition, you ll display in the marker
balloon a message indicating the found location. Figure 20 shows the marker
added to the map when I searched for Empire
State Building .
Figure 20: Searching for the address
of the Empire State
Building.
Conclusion
You ve now seen the basics of how to get started with the
Google Maps API. The Google Maps API offers much more than what I can possibly
describe in this space. As you become comfortable with it, check out the
documentation and explore the rest of what the API offers. In Part II, you ll
learn how to geo-tag your photos using Google Maps.
The source code accompanying
this article is available for download.
Wei-Meng Lee (http://weimenglee.blogspot.com) is a
Microsoft MVP and founder of Developer Learning Solutions (http://www.learn2develop.net), a
technology company specializing in hands-on training on the latest Microsoft
technologies. He is an established developer and trainer specializing in .NET
and wireless technologies. Wei-Meng speaks regularly at international
conferences and has authored and co-authored numerous books on .NET, XML, and
wireless technologies. He writes extensively on topics ranging from .NET to Mac
OS X. He is also the author of.NET Compact
Framework Pocket Guide, ASP.NET 2.0: A
Developer s Notebook (both from O Reilly Media, Inc), and Programming Sudoku (Apress).