Introduction
This article marks a couple of milestones.. Firstly, it marks my first attempt at a C# project! (Please be kind to me!), and secondly, it offers the outside world the ability to view Google Maps in a web application without using a key (sssh!)
Background
I am no means endorsing hacking here with this. This control merely makes use of knowledge that is available to anyone that goes onto Google Maps and clicks "View Source" :-)
So, how did I discover this? Well, if you go to Google Maps and click "View Source", you will notice that Google has introduced a friendly catch for people that do not have JavaScript enabled in their browsers. Simply "View Source" and search the source for the first occurrence of the <noscript>
tag. You will get something like this:
<noscript><meta http-equiv=refresh content="0;
URL=http://maps.google.com/?output=html" /></noscript>
This little snippet redirects the browser to a "Non JavaScript" version of Google Maps - And this is the key to the component working!
How Does it Work?
Well, this control merely offers a static view of a map based on an entered Latitude, Longitude, and Zoom Level (which I believe is in feet). No JavaScript, no DHTML. Just a nice simple image tag.
This URL defined in the code will generate a map image:
private const string mapurl = "http://maps.google.com/mapdata" +
"?latitude_e6={0}&longitude_e6={1}&zm={2}&w={3}" +
"&h={4}&cc=&min_priority=2";
As you can see, we are only interested in the Latitude, Longitude, Zoom Level, Width, and Height of our desired map image. These are stored in the properties of the control.
public Unit Height
{
get
{
object value = ViewState["Height"];
if (value == null) { return new Unit(400, UnitType.Pixel); }
return (Unit)value;
}
set { ViewState["Height"] = value; }
}
public Unit Width
{
get
{
object value = ViewState["Width"];
if (value == null) { return new Unit(600, UnitType.Pixel); }
return (Unit)value;
}
set { ViewState["Width"] = value; }
}
public System.Int64 Latitude
{
get
{
object value = ViewState["Latitude"];
if (value == null) { return 0; }
return (System.Int64)value;
}
set { ViewState["Latitude"] = value; }
}
public bool ShowControlPanel
{
get
{
object value = ViewState["ShowControlPanel"];
if (value == null) { return true; }
return (bool)value;
}
set { ViewState["ShowControlPanel"] = value; }
}
public System.Int64 Longitude
{
get
{
object value = ViewState["Longitude"];
if (value == null) { return 0; }
return (System.Int64)value;
}
set { ViewState["Longitude"] = value; }
}
public int Zoom
{
get
{
object value = ViewState["Zoom"];
if (value == null) { return 9600; }
return (int)value;
}
set { ViewState["Zoom"] = value; }
}
public MapZoomLevel ZoomLevel
{
get
{
switch (this.Zoom)
{
case 1200: return MapZoomLevel.Level0;
case 2400: return MapZoomLevel.Level1;
case 4800: return MapZoomLevel.Level2;
case 9600: return MapZoomLevel.Level3;
case 19200: return MapZoomLevel.Level4;
case 38400: return MapZoomLevel.Level5;
case 76800: return MapZoomLevel.Level6;
case 180000: return MapZoomLevel.Level7;
case 600000: return MapZoomLevel.Level8;
case 1800000: return MapZoomLevel.Level9;
}
return MapZoomLevel.Custom;
}
set
{
int zoom1 = GetZoomLevel(value);
this.Zoom = zoom1;
}
}
public string ToolTipText
{
get
{
object value = ViewState["ToolTipText"];
if (value == null) { return ""; }
return (string)value;
}
set
{
ViewState["ToolTipText"] = value;
}
}
This example URL below generates a map image for Wallingford in Oxfordshire, UK..
http://maps.google.com/mapdata?latitude_e6=51600117&longitude_e6=
4293842485&zm=9600&w=600&h=400&cc=&min_priority=2
All our control does is format the URL and generate an IMG
tag based on the properties passed by the developer, as shown below:
protected override void Render(HtmlTextWriter writer)
{
writer.AddAttribute("border", "0");
writer.AddAttribute("cellpadding", "0");
writer.AddAttribute("cellspacing", "0");
writer.RenderBeginTag("table");
writer.RenderBeginTag("tr");
writer.RenderBeginTag("td");
writer.AddAttribute("id", this.ClientID);
writer.AddAttribute("width", this.Width.ToString());
writer.AddAttribute("height", this.Height.ToString());
writer.AddAttribute("alt", this.ToolTipText);
writer.AddAttribute("src", string.Format(mapurl, this.Latitude,
this.Longitude, this.Zoom,
this.Width.Value, this.Height.Value));
writer.RenderBeginTag("img");
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
if (this.ShowControlPanel)
{
writer.AddStyleAttribute("background-color","#eeeeee");
writer.RenderBeginTag("tr");
writer.RenderBeginTag("td");
writer.Write("Zoom:");
for (var i = 0; i < 10; i++)
{
if (i == (int)ZoomLevel)
{
writer.AddStyleAttribute("background-color", "#0A246A");
writer.AddStyleAttribute("color", "white");
}
else
{
writer.AddStyleAttribute("color", "black");
}
writer.AddStyleAttribute("font-size", "14px");
writer.AddAttribute("href",
Page.ClientScript.GetPostBackClientHyperlink(this,
"Zoom$" + i.ToString()));
writer.AddAttribute ("title",
GetZoomLevel((MapZoomLevel)i).ToString() + " Feet.");
writer.RenderBeginTag("a");
writer.Write(" " + i.ToString() + " ");
writer.RenderEndTag();
writer.Write(" ");
}
writer.RenderEndTag();
writer.RenderEndTag();
}
writer.RenderEndTag();
}
Nothing like keeping it simple!
So, to generate the above map image using our control, all we would need to do is use the following code snippet on our page:
<ctl:GoogleMap id="map1" runat="Server" Latitude="51600117"
Longitude="4293842485" Zoom="9600" Width="600px" height="400px" />
Cool!
I know this generates a simple map image, but there is so much potential to enhance this control. We could look at adding dynamic navigation using the mouse, simply by adjusting the longitude and latitude, dynamic zooming in and out using the mouse too. Of course, these enhancements can be made easier by using AJAX technologies. If you have access to a Postcode file (there is a free one in the UK that maps Postcode areas to Lat/Long coordinates), you could look at plotting them on this map.. Perhaps in a future article, when I have some time, I will add some of these enhancements to the component.
I havn't gone into a huge amount of detail on the code. Please bear with any errors in the code as it is my first C# project! And, feel free to download, use, and enhance the component as you require.
Enjoy!!