This article examines a custom ASP.NET server control I developed to make using the Google Maps API easier for .NET developers. This article assumes you are somewhat familiar with Google Maps (or are at least somewhat curious). If you're not familiar with Google Maps or its sweet API, check out http://maps.google.com/ and http://www.google.com/apis/maps/documentation/ for the lowdown. You may see references throughout the article to "my control, my GoogleMaps control, my GMap control, and so forth." I did not create the Google Maps API; I merely used C#, XML, and XSL to create a wrapper for ASP.NET.
As I stated above, my main goal for this control was to make it easy to use a Google Map using .NET languages. I also tried very hard not to use any fancy or proprietary "hacks" or workarounds when creating this control.
I need to point out a few quick things before you get to the examples. The Google Maps Documentaion makes some specific recommendations for the DOCTYPE, HTML Namespaces, and STYLES for your Google Map pages. Each of the example pages starts like so:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"//www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="//www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml"
xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type"
content="text/html;
charset=UTF-8"/>
<title>. . .</title>
<style type="text/css">
v\:*
{
behavior:url(#default#VML);
}
</style>
. . .
</head>
Note the "strict" DOCTYPE, the custom xmlns attributes in the HTML tag, and the cryptic-looking stylesheet entry for v\:*. If you don't include these values in your pages, strange things may happen. I noticed them especially when using polylines in Internet Explorer.
Google API Key
You'll need a valid Google API key (get one here) to run the examples. The key included in the downloadable code (see the web.config file) will work as long as your application is located at http://localhost/TestWeb/.
Web.Config Setup
The GMap control is based on the "div" tag. Unfortunately, ASP.NET renders div tag controls as tables in non-IE browsers by default. For the control to render properly in Firefox, you need to add the following entries to your web.config or machine.config file:
<browserCaps>
<case match="^Mozilla/5\.0\s*([^)]*\))\s*(Gecko\/\d+)\s*Firefox\/
(?'version'(?'major'\d+)(?'minor'\.\d+)(?'letters'\w*)).*">
type=Firefox/${version}
version=${version}
majorversion=${major}
minorversion=${minor}
frames=true
tables=true
cookies=true
javascript=true
javaapplets=true
ecmascriptversion=1.5
w3cdomversion=1.0
css1=true
css2=true
xml=true
tagwriter=System.Web.UI.HtmlTextWriter
<filter match="^b" with="${letters}">
beta=true
</filter>
</case>
</browserCaps>
It's a good idea in general to add these values to the machine.config file on your Web server. Why? So things like asp:panel and other "div"-based controls will render properly in Firefox.
The Good Stuff
Included in the downloadable code (see the Downloads at the bottom of this article) is a Web project called TestWeb with nine (9) example pages on how to use my GMap Control in your applications (see all examples here). The download includes the complete source for the control.
Basics.aspx
__Show Me__ This is the simplest use of a GMap. Here, you just create a GMap with a width of 500px and height of 300px. What could be simpler?
<form id="Form1" method="post" runat="server">
<wcp:GMap runat="server" id="gMap" Width="500px" Height="300px" />
</form>
Basics.aspx.cs
To initialize the map, you'll always want to make a call to CenterAndZoom. Otherwise, you may get just a big grey box.
protected GMap gMap;
private void Page_Load(object sender, System.EventArgs e)
{
gMap.CenterAndZoom(new GPoint(-122.141944F, 37.441944F), 4);
}
Houston, we have a GMap!
Controls.aspx.cs
__Show Me__ The .aspx code for the Controls example is identical to the Basics example. Here, you add some basic controls to your map.
protected GMap gMap;
private void Page_Load(object sender, System.EventArgs e)
{
gMap.AddControl( new GSmallMapControl());
gMap.AddControl( new GMapTypeControl());
gMap.CenterAndZoom(new GPoint(-122.141944F, 37.441944F), 4);
}
GMap & GMarker Events
Say you want to tap into some of the events provided by the Google Maps API. You can access any of the GMap events by implementing the proper JavaScript functions in your page. The events are outlined below and demonstrated in the following examples:
Event Handler
Notes
GMap_Click(overlay, point)
"this" will reference the GMap being clicked
GMap_Move()
"this" will reference the GMap being moved
GMap_MoveStart()
"this" will reference the GMap being moved
GMap_MoveEnd()
"this" will reference the GMap that was moved
GMap_Zoom(oldZoomLevel, newZoomLevel)
"this" will reference the GMap being zoomed
GMap_WindowOpen()
GMap_WindowClose()
GMap_AddOverlay(overlay)
"this" will reference the GMap to which the overlay was added
GMap_RemoveOverlay(overlay)
"this" will reference the GMap that lost the overlay
GMap_ClearOverlays()
"this" will reference the GMap being cleared
GMarker_Click()
"this" will reference the GMarker that was clicked
GMarker_InfoWindowOpen()
GMarker_InfoWindowClose()
Downloads
WCPierce.zip - Complete source files
WCPierceWebChm.zip - Compiled HTML Help file for control
Listeners.aspx
__Show Me__
<script type="text/javascript">
function GMap_MoveEnd()
{
var center = this.getCenterLatLng();
var latLngStr = '(' + center.y + ', ' + center.x + ')';
document.getElementById('message').innerHTML = latLngStr;
}
</script>
</head>
<body>
<form id="Form1" method="post" runat="server">
<wcp:GMap runat="server"
id="gMap"
Width="500px"
Height="300px" />
<asp:Label Runat="server" ID="message" />
</form>
</body>
Here, you implement one of the GMap JavaScript event functions, GMap_MoveEnd. This function will run any time the user stops moving the GMap with their mouse. The JavaScript code gets the current Center coordinate of the map (this), formats the values, and displays them in the "message" label.
__Show Me__ This example opens the GMap Info Window and displays "Hello World". Note that this example uses JavaScript to create a new DOM text node. GMap also supports OpenInfoWindowHtml, which accepts a string of HTML to display in the info window.
protected GMap gMap;
private void Page_Load(object sender, System.EventArgs e)
{
GPoint gp = new GPoint(-122.141944F, 37.441944F);
gMap.CenterAndZoom(gp, 4);
gMap.OpenInfoWindow(gp, "document.createTextNode('Hello World')");
}
Overlays.aspx.cs
__Show Me__ What fun is a map without points of interest or line annotations? You can add "overlays" to your GMap programmatically. Currently, the only two overlays provided by the Google Maps API are the GMarker and GPolyline. This example shows the usage of both.
protected GMap gMap;
private void Page_Load(object sender, System.EventArgs e)
{
gMap.AddControl(new GSmallMapControl());
gMap.AddControl(new GMapTypeControl());
GPoint gp = new GPoint(-122.141944F, 37.441944F);
gMap.CenterAndZoom(gp, 5);
GMarker gm = new GMarker(gp, "FirstMarker");
gMap.Overlays.Add(gm);
GPolyline gPoly = new GPolyline();
gPoly.Weight = 5;
gPoly.Opacity = 0.25F;
gPoly.Color = Color.Red;
for( int i=1; i<6; i++ )
{
float x = gp.X + (0.005F*-i);
float y = gp.Y + (0.005F*-i);
gPoly.Points.Add(new GPoint(x, y));
}
gMap.Overlays.Add(gPoly);
}
ClickHandling.aspx
__Show Me__ You also can capture the GMap click event and take any desired actions based on the click, such as adding or removing an overlay:
<script type="text/javascript">
function GMap_Click(overlay, point)
{
if( overlay )
this.removeOverlay(overlay);
else if( point )
this.addOverlay(new GMarker(point));
}
</script>
</head>
<body>
<form id="Form1" method="post" runat="server">
<wcp:GMap runat="server"
id="gMap"
Width="500px"
Height="300px" />
</form>
</body>
MarkerInfoWindow.aspx
__Show Me__ You also can capture the GMarker click event and show an info window over the marker with any HTML you want:
<script type="text/javascript">
function GMarker_Click()
{
var html = "<b>" + this.id + "</b>";
this.openInfoWindowHtml(html);
}
</script>
</head>
<body>
<form id="Form1" method="post" runat="server">
<wcp:GMap runat="server"
id="gMap"
Width="500px"
Height="300px" />
</form>
</body>
MarkerInfoWindow.aspx.cs
Create the GMarkers programmatically with any .NET language. Set each GMarker's ID so it will be displayed client-side when clicked.
protected GMap gMap;
private void Page_Load(object sender, System.EventArgs e)
{
GPoint gp = new GPoint(-122.141944F, 37.441944F);
GMarker gm = new GMarker(gp, "FirstMarker");
gMap.Overlays.Add(gm);
gm = new GMarker(new GPoint(gp.X + 0.005F, gp.Y + 0.005F),
"SecondMarker");
gMap.Overlays.Add(gm);
gMap.CenterAndZoom(gp, 4);
}
Icons.aspx
__Show Me__ The GMap control also supports custom icons. Creating icons requires a little more work unless you have access to the proper images. I'll borrow some of Google's for demonstration purposes.
<script type="text/javascript">
function GMarker_Click()
{
var html = "You clicked me!";
this.openInfoWindowHtml(html);
}
</script>
</head>
<body>
<form id="Form1" method="post" runat="server">
<wcp:GMap runat="server"
id="gMap"
Width="500px"
Height="300px" />
</form>
</body>
Icons.aspx.cs
Again, the theme here is programmatically creating Google API objects and interacting with them using C#/VB .NET.
protected GMap gMap;
private void Page_Load(object sender, System.EventArgs e)
{
GPoint gp = new GPoint(-122.141944F, 37.441944F);
GIcon tiny = new GIcon();
tiny.Id = "tiny";
tiny.Image = new Uri("http://labs.google.com/ridefinder/images/
mm_20_red.png");
tiny.Shadow = new Uri("http://labs.google.com/ridefinder/images/
mm_20_shadow.png");
tiny.IconSize = new GSize(12, 20);
tiny.ShadowSize = new GSize(22, 20);
tiny.IconAnchor = new GPoint(6, 20);
tiny.InfoWindowAnchor = new GPoint(5, 1);
gMap.Icons.Add(tiny);
gMap.AddControl(new GSmallMapControl());
gMap.AddControl(new GMapTypeControl());
gMap.CenterAndZoom(gp, 4);
GMarker gm = new GMarker(gp, "TinyMarker", tiny.Id);
gMap.Overlays.Add(gm);
}
DataListExample.aspx
__Show Me__ This is the final example that I wanted to throw into this article. I wanted to demonstrate just how easily you could create multiple GMap controls. This example creates six (6) maps centered at the same point each with a different zoom level.
<body>
<form id="Form1" method="post" runat="server">
<asp:DataList Runat="server" ID="dlMaps"
RepeatDirection="Horizontal"
RepeatColumns="2"
RepeatLayout="Table">
<ItemTemplate>
<wcp:GMap runat="server"
ID="gMap"
width="400px"
height="240px" />
<asp:Label Runat="server">
Location: (-122.141944, 37.441944) Zoom Level:
<%# Container.DataItem %>
</asp:Label>
</ItemTemplate>
</asp:DataList>
</form>
</body>
DataListExample.aspx.cs
Here, I get a little fancy by creating an ArrayList of zoom values. This ArrayList serves as the DataSource for your DataList. During the DataBinding, you get a reference to each GMap and center it at the given point and zoom out by one step each time.
protected DataList dlMaps;
private const int MAX_ZOOM = 6;
private void Page_Load(object sender, System.EventArgs e)
{
ArrayList al = new ArrayList();
for( int i=1; i<=MAX_ZOOM; i++ )
al.Add(i);
dlMaps.DataSource = al;
dlMaps.DataBind();
}
private void dlMaps_ItemDataBound(object s,
DataListItemEventArgs dliea)
{
GMap map = (GMap)dliea.Item.Controls[0];
int zoom = Convert.ToInt32(dliea.Item.DataItem);
map.CenterAndZoom(new GPoint(-122.141944F, 37.441944F), zoom);
}
Conclusion
I hope you are able to get some good mileage out of the GMap control.
Downloads
WCPierce.zip - Complete source files
WCPierceWebChm.zip - Compiled HTML Help file for control