I’m going to show you how to build a basic ASP.NET WebControl whose goal is to use the Google MapData “feature” (in a few words: a dynamically generated image with basic Google Map features).
You will learn how to derive your own WebControl from an existing one, make some attributes, use the viewstate, etc…
Why this control? (What is Google MapData?)
Some days before, one of my Google searches returned a “Google Map” result entry. First, I guessed that it was an embedded Google Map, but a right click let me know that it was a parameterized image. After copying and playing with the image’s URL in my browser, it quickly appeared that the parameters were easy to use, and the idea to wrap it in a WebControl came to my mind.
Look at this Google Search to see a MapData image.
Right click, and you will see this URL (don't click, I've added some spaces to make this long URL wrap at the end of the line): http://www.google.com//mapdata?Point=b& Point.latitude_e6=45773917& Point.longitude_e6=4806903& Point.iconid=33&Point=e& latitude_e6=45773917& longitude_e6=4806903& zm=2400&w=304&h=156&cc=FR&min_priority=1.
Basically, what is a Google MapData image? Just an image, dynamically generated by Google with the help of some GET parameters!
There is no need to reinvent the wheel, so our WebControl will naturally derive from the
System.Web.UI.Image framework’s WebControl (MSDN).
More about MapData parameters
A MapData image accepts the following parameters (I didn’t find any API documentation, other parameters may exist):
cc: ISO 3166 country code (string value, “fr” for me)
w: image’s width (integer value)
h: image’s height (integer value)
zl: image’s zoom level (integer value from 1 up to 9 (mini / maxi))
- a collection of points, each of them having the following parameters :
Point: begin of the point (“b” value)
Point.latitude_e6: point’s latitude (double without decimal point, 8 characters)
Point.longitude_e6: point’s longitude (double without decimal point, 7 characters)
Point.iconid: icon identifier of point’s icon (integer value)
Point: end of the point (“e” value)
Before starting the control itself, we need to think about the whole structure.
Since our goal is to show a map image with some points, it’s a good idea to make a
Point class encapsulating the needed properties. Since a point is composed of a coordinate and graphical properties, it's a better idea to make a
Coordinate base class (latitude, longitude) and make our
Point class (icon identifier) derive from it. Then, the
Point class will be used by the WebControl.
Note that I have used some enumerations in order to clarify the source. They are definitely great for the class “users”, but the code to manage them is (in my opinion) verbose and doesn’t come naturally.
Starting the WebControl itself
It’s now time to start coding the WebControl itself, deriving from
System.Web.UI.Image. Let us name it
MapDataImage. The width and height properties are already defined in the base class, so we “only” have to encapsulate the map properties (the zoom level and points collection).
The main work of the
MapDataImage class is to use its attributes in order to build and set up the
ImageUrl property (of the base class) with the right URL. Note that I used the
new keyword modifier in order to redefine the
ImageUrl to avoid any modification from the outside.
The URL is built and set in the pre-render phase (by overriding the
OnPreRender method) which is executed before rendering the WebControl.
MapDataImage builds the URL with its own attributes and by looping through the points collections (the
Point class and the
Coordinate class provide methods to generate their respective query string parts).
Managing the ViewState
The ViewState, when enabled, allows to store the state of a
Control (base class of WebControl) and to restore it after a postback.
In our case, we need to store some strategic attributes such as the zoom level, the image format, and obviously the points (note that the width and height are already managed by the base class).
Saving the ViewState is done by overriding the
SaveViewState method, and its loading is done by overriding the
Basically, we store and retrieve a value in / from the ViewState with a code like:
ViewState["ZoomLevel"] = Zoom;
Zoom = (uint)ViewState["ZoomLevel"];
The storing of the points (a generic list) is a little trickier since the generic
List<> class isn’t serializable. A quick workaround to achieve this is to convert the list to an array when storing it in the ViewState, and convert it back when retrieving it:
ViewState["Points"] = Points.ToArray();
All right? Not yet! The compiler is now complaining about the
Point class which is not serializable… No problem, add the
[Serializable] attribute before the
Coordinate classes. Note that for more complex classes, you can mark the variable as non-serializable by adding the
NonSerialized attribute before them.
Using the control
Note: since to explain how to consume a WebControl is not the goal of this article, I will quickly cover this part. I recommend you to download the sample project in order to see how the WebControl is basically used.
So, to test our WebControl, we first need to register it in our test page, with a line like this one (note that you can register it in the web.config in order to avoid registering it in each page of your project):
<%@ Register TagPrefix="igm" Assembly="TestMapData" Namespace="Initia.Google.MapData" %>
Then, you instantiate your WebControl like any other WebControl (you may set some attributes here, since we bind them to the designer in the code):
<igm:MapDataImage ID="gmdTest" runat="server"></igm:MapDataImage>
In our page, it’s time to use the
Page_Load handler in order to initialize our WebControl with common data such width and height (don’t forget to set them in the
Then, you can use some basic WebControls (like dropdown lists or textboxes) in order to change the attributes or to add / modify / delete points.
Points of Interest / Conclusion
We have covered the basics of a WebControl based on an image, and I hope that it helps you. I made this WebControl for my own interests, and I am very pleased to share my experiences with you by writing this first article on CodeProject.
Feel free to use and enhance this control the way you want, but keep in mind that I really don’t know if Google will allow third party websites to use their MapData “feature” (very few documentation available on this).
This is my first article, and English isn’t my native language; thank you for your “kindness” and your advices about the source code and the article itself.
- 2008 / 04 / 10: First version.