Building a Store Locator ASP.NET Application Using Google Maps API (Part 2)By Scott Mitchell
Last week's article, Building a Store Locator ASP.NET Application Using Google Maps API (Part 1), was the first in a multi-part article series exploring how to add store locator-type functionality to your ASP.NET website using the free Google Maps API. Part 1 started with an examination of the database used to power the store locator, which contains a single table named
Storeswith columns capturing the store number, its address and its latitude and longitude coordinates. Next, we looked at using Google Maps API's geocoding service to translate a user-entered address, such as San Diego, CA or 92101 into its latitude and longitude coordinates. Knowing the coordinates of the address entered by the user, we then looked at writing a SQL query to return those stores within (roughly) 15 miles of the user-entered address. These nearby stores were then displayed in a grid, listing the store number, the distance from the address entered to each store, and the store's address.
Displaying a Map in a Web Page Using Google Maps API
<script>element like so:
<script> element needs to appear on every page that uses the Google Maps API. You can add it on a page-by-page basis or in the master page. Once the
invaluable resource when getting started with Google Maps API.
To display a map in a web page you need to create the map canvas, which is the area on the web page where the map will be "painted." The map canvas is simply an HTML
element in the page, and is typically implemented by adding a
<div> element to the page's markup like so:
id attribute identifies the
attribute specifies the dimensions of the map - in this case the map will be 500 pixels wide by 400 pixels high. You could also use relative measurements (like a width of 100%) and
include additional style settings, like a border.
With the Google Maps API referenced via a
map on the map canvas. To display a map we use the
Map class and need to pass in three bits of information:
- The latitude and longitude coordinates of where to center the map,
- The zoom level, and
- The map type
LatLngobject. The zoom is an integer value that ranges from zero on up. A zoom level of zero shows the entire world. All points on the map can zoom up to 19, while certain parts of the globe can have zoom levels of 20 and beyond. The map type indicates whether the map shows just roads, shows satellite data, shows a hybrid of road and satellite data, or shows terrain.
First, note the map canvas (
my_map), which defines a canvas of 400x300 pixels. There's also some other HTML markup on the page - an
heading and some text that explains what the visitor is viewing.
<head> section there are two
<script> tags. The first one pulls in the Google Maps API while the second one defines a function
init_map function accepts four input parameters:
idvalue of the map canvas element (
my_map, in this instance),
lat- the latitude coordinate of where the map should be centered,
lng- the longitude coordinate of where the map should be centered,
zoomLevel- the zoom level
init_mapfunction starts by creating a
LatLngobject modeling the
lngvalues passed into the function. Next, an
optionsobject is defined as having three properties -
mapTypeId- and these properties are set to the passed-in zoom level (
LatLngobject based on the passed-in
myLatLng), and the
HYBRID, which indicates that the a hybrid map should be displayed (one that shows both road and satellite information).
Next, the map canvas is retrieved from the HTML DOM via the
getElementById function. Finally, a new
Map object is created by passing in the map canvas and the
map's options. That's all there is to it! When viewing the page through a browser you will see a 400x300 pixel hybrid map centered in the heart of Mexico City, Mexico.
Like with any other Google map, the visitor can zoom in and zoom out and scroll the map by clicking and dragging her mouse on the map surface.
The final piece of the puzzle is the
<script> block at the end of the HTML document. Here we call the
init_map function passing in the
of the map canvas (
my_map), the latitude and longitude of the map center (19.4270499 and -99.1275711), and the zoom level (14).
The screen shot below shows this sample page when initially viewed through a browser.
Adding Markers to the Map
Markerclass that can be placed at a specific latitude and longitude. To add a marker to a map first create the
Mapobject (like we did in the sample above) and then use the following pattern:
Marker Title is the title of the marker and appears as a tooltip when the user hovers over the marker;
lng indicate the latitude and
longitude coordinates of where the marker should be placed.
To demonstrate using markers, let's create another Mexico City map that includes markers showing museums of interest. I found a bunch of Mexico City museums listed online
at http://www.mexicocity.com.mx/museum.html, which included the name of the museum and its address. I then used the
Google geocoding service discussed last week to translate those addresses to latitude and longitude coordinates. I then combined this into an array of
Next, I added the following code to the
init_map function, which we created in the previous example. (I also changed the map's
MapTypeId value from
The above code adds the four markers defined in the
markers array to the map. However, if you view the page through a browser you'll see that not all markers
are initially displayed. The map is centered in the heart of Mexico City at a zoom level that only captures two of the four markers (see the screen shot below). If you zoom
out you'll soon see the other two markers, which are in the southwest part of the city.
The Google Maps API includes a
LatLngBounds object that can be used to define a boundary that includes all of the markers added to the map; moreover, this boundary
can be used to center and zoom the map so that the initial map includes all of the markers. To use this object, we need to update the
init_map function to
LatLngBounds object, to extend it with each new marker, and then to set the map's center and zoom level based on the bounds. The following code
is all that is needed to achieve this:
With the above code in place, the initial map view is appropriately centered and zoomed, as the following screen shot illustrates.
Tying It All Together - Displaying a Map and Markers for the Store Locator
Now that we know how to display a map and add markers to it, we're ready to update our store locator results page to show a map based on the address entered by the user and to add markers on the map for any nearby stores. Recall that the search results are displayed in the
ShowStoreLocations.aspxpage and that this page uses Google's geocoding service to translate the user-entered address into latitude and longitude coordinates. In Part 1 we used these coordinates to determine which store locations were nearby and to compute the distance from the user-entered address to each nearby store location. We'll use these same coordinates as the initial center for our map.
Before we get there, though, let's first take a look at the HTML we need to add to the
ShowStoreLocations.aspx page to display the map. There are three
<script>tag that references the Google Maps API
<script>tag referencing the script file
GoogleHelpers.js. This is a script file in the
Scriptsfolder that contains the
GoogleHelpers.jsis virtually identical to the one we examined in the Adding Markers to the Map section. The only difference is that instead of having a
markersarray defined external to the function the
markersarray is passed into the function as an input parameter.
- A map canvas implemented as a
map_canvas. The map canvas appears above the grid of nearby store locations.
titleproperty displays the store number of the nearby store whereas the
positionproperty is a
LatLngobject modeling the latitude and longitude values of the store. These objects are combined into an array and then passed into the
The following C# code shows the above workflow. The demo available for download at the end of this article include code in both C# and VB, so if you want to see the VB equivalent
be sure to download the demo. A couple of comments about the code: first, recall that the nearby store locations are pulled from the database using a SqlDataSource control
dsSearchResults) that is bound to a ListView control on the page. In order to get the list of nearby stores for the purpose of adding the markers I call the
Select method, which returns a
DataView object. Next, each row in the DataView is enumerated and for each row the appropriate
Because I am using
} - need
to be escaped by using a pair of them, which is why you see the
}} at the start and end of the object declaration. At the end of the loop
position objects. This string that represents the array,
is passed into the
init_map function as its fifth input parameter in the
RegisterStartupScript method. The
Working with Client-Side Script.
(If you have trouble grasping the below code I suggest downloading the code and running the demo. When viewing the store locations for a particular search, do a View/Source
init_map and you'll see the array of markers passed into the function.)
With the above code in place we have a much nicer search results page for our store locator. As the following screen shot shows, the search page not only lists the nearby stores but also shows a map with markers for each store, and hovering over a marker displays the store number in a tooltip.
While the store locator has been enhanced to include a map with markers for each store location, it still leaves a bit to be desired. For instance, each of the markers on the map looks the same. Hovering your mouse over a marker shows a tooltip, but it would be nice to be able to click the marker and see details about the store, such as its address, its hours of operation, and a phone number. Finally, there's no quick way for a user unfamiliar with the area to know which marker corresponds to which result in the grid below. Ideally, each result in the grid would be numbered and the corresponding marker in the map would be numbered to match. We'll update the map to include these enhancements in Part 3.