5 Steps to Google Maps!

Google's map API is perhaps one of the easiest APIs to work with and has led to some really great mashups. What are you waiting for? Jump on the Web 2.0 wagon and get started on creating your own mashup!

The Steps:
  1. Get a Google Map API Key
  2. Set up the page
  3. Get your Lat/Long
  4. Configure the map's JavaScript code
  5. Save & Publish

Before we get started, let's decide what we want to make a map of. Since just about everyone works in a building (or even at home if you're lucky enough!), we will map that. Ok, that's out of the way so let's get to it!

Step 1: Get your Google Map API Key. Before you can begin to use Google Maps API, you must obtain a key. The key is valid for a specific folder on your website. So let's say you own the site http://www.mysite.net. If you want to put a Google Map on the page http://www.mysite.net/about/about.html then you will need to register http://www.mysite.net/about/ as the site on Google's form. Your key will be valid for any page inside the about folder (http://www.mysite.net/about/). You could also register your Google Map key for http://www.mysite.net/ but the key will only be valid for any file in the / folder.

Head over to the Google Maps API Sign up page and get your key!
Make sure you save this key! You'll need it later!

Step 2: Set up the page. Before we try to integrate a map into an existing page, let's do a little testing with a simple page we'll create just for the map.

The Google Maps API only has three required pieces. Two Javascript blocks: One to import the Gmaps API and the other to define the map. The third piece is a html div element that defines the size and width of the map.

Let's create a new HTML page. At base you'll have something like this (Figure 1):

Figure 1:
<html>
<head>
<title>My Google Map Page</title>
</head>
<body>

</body>
</html>

Now we add two of the required elements: The Gmaps API script block and the div element to hold the map. (Figure 2)

Figure 2:
<html>
<head>
<title>My Google Map Page</title>
<script src="http://maps.google.com/maps?file=api&key=[PASTE YOUR API KEY HERE]" type="text/javascript"></script>
</head>
<body>
<div id="map" style="width: 450px; height: 450px;></div>
</body>
</html>

Replace [PASTE YOUR API KEY HERE] with that long string that you got from the Gmaps API Sign up page. You'll also see that in the body tags you should now have a div with id "map". Make sure you assign the div an id and not a class*; giving it an id makes it available to the Gmaps JavaScript code.

*Later I will mention how to use a CSS anchor to assign styles to your map div from a style sheet instead of doing it inline.

Step 3: Get your latitude and longitude.
Google Maps does not offer a geocoding service; that is, a service that converts an address to it's latitude and longitude (Lat & Long) coordinates. In order to use Gmaps, you must provide this data yourself. There are several ways to do this:

Geocoder.us has a free service that you can tap into and get your lat & long. In my use of it, I have noticed some discrepencies between the coordinates you get and what I know the actual location to be. So, for our first try let's use a little Google Maps hack to find the lat & long. Head over to Google Local. Enter the address you want to search in the search box. Ready for the hack?

Click and hold on the map and move it just slightly (a few pixels if you can manage it), then release. Now, in the upper right hand corner, click "Link to this page". Now, look in the address bar. In the URL you should see a part that looks something like this:
&ll=38.781521,-89.947729
Everything that follows &ll= is your Lat & Long (Lat is first, then Long seperated by a comma). See figure 3

Now we have our Key, our HTML page, and our Lat & Long. Next let's configure the JavaScript code that creates the map!

Step 4: Configure the map's JavaScript code
Gmaps works by creating a map element (using JavaScript) that contains all the data about the map and any points that should be marked on the map. The configuration is passed in a CDATA block. In this block you can configure all the parameters of your map like what controls to include (like the zoom slider or satellite button), any points to mark, and how far to zoom in when the map loads.

Figure 4:
<script type="text/javascript">//<![CDATA[
function load(){
var map = new GMap(document.getElementById("map"));
var point = new GPoint(-89.947729,38.781521);
var marker = new GMarker(point);
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.centerAndZoom(point, 3);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml("<table width='215'><tr><td><a target='_blank' href='http://www.lcls.org/'>Lewis & Clark Library System</a></td></tr><tr><td><img src='http://www.lcls.org/images/galleries/tour/01-BuildingFromLot.JPG' border='0' width='195px' height='95' /></td></tr><tr><td>425 Goshen Road<br />Edwardsville,IL 62025<br />618-656-3216</td></tr></table><br /><a target='_blank' href='http://maps.google.com/maps?q=425 Goshen Road%20Edwardsville,%20IL'>Directions</a>");
});
map.addOverlay(marker);
}
//]]>
</script>

Let's go through figure 4 so we know what is going on. In the first line we are simply declaring a JavaScript block and beginning the CDATA block. The function load(){ line creates a JavaScript function called "load" that we will be adding as the onloadaction of the body element of our page.

var map = new GMap(document.getElementById("map")); creates a new Google Map instance and assigns our div element named "map" to the Gmap control.

var point = new GPoint(-89.947729,38.781521); creates a new "point". In Gmap speak a point is a set of coordinates that define a location on the map. Points are the focus of a map. Without them, you'd just be looking at the map.

var marker = new GMarker(point); creates a new marker. Markers are what make maps fun! This line will add the red marker icon to represent your point on the map.

the map.addControl lines define the types of controls to display on the map. The GLargeMapControl is the standard Gmap control with the zoom levels and pan arrows. The GmapTypeControl displays the Satellite, Hybrid, and Map buttons that let you switch map modes.

map.centerAndZoom(point, 3); centers the map on our defined point and zooms into level 3.

GEvent.addListener(marker, "click", function() { Now it's time for what makes these maps really useful: the ability to click markers and get information! GEvent.addListener assigns functions to the map controls. This is what allows us to assign a click action to a marker so that when you click the marker, you get the information window that pops up.

marker.openInfoWindowHtml. This is where the action happens. This function takes HTML as its value and displays that HTML the information balloon when you click on a marker. When you add your own HTML into this, make sure you use the single quote (') to surround attribute values (ex. <table border='1'>). If you use a double-quote (") you will get JavaScript errors. (Yes, you could escape the quotes with a backslash (ex <table border=\"1\">), but that is more work than using a single quote).

Now that we understand how it works, let's put it all together! (See Figure 5)

Figure 5:
File: singlelocation.html
<html>
<head>
<title>My Google Map Page</title>
<script src="http://maps.google.com/maps?file=api&key=[PASTE YOUR API KEY HERE]" type="text/javascript"></script>
</head>
<body onload="load();">
<div id="map" style="width: 450px; height: 450px;></div>
<script type="text/javascript">//<![CDATA[
function load(){
var map = new GMap(document.getElementById("map"));
var point = new GPoint(-89.947729,38.781521);
var marker = new GMarker(point);
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.centerAndZoom(point, 3);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml("<table width='215'><tr><td><a target='_blank' href='http://www.lcls.org/'>Lewis & Clark Library System</a></td></tr><tr><td><img src='http://www.lcls.org/images/galleries/tour/01-BuildingFromLot.JPG' border='0' width='195px' height='95' /></td></tr><tr><td>425 Goshen Road<br />Edwardsville,IL 62025<br />618-656-3216</td></tr></table><br /><a target='_blank' href='http://maps.google.com/maps?q=425 Goshen Road%20Edwardsville,%20IL'>Directions</a>");
});
map.addOverlay(marker);
}
//]]>
</script>
</body>
</html>

Step 5!: Save and publish.

Using the code in figure 5, copy that into your HTML file. Paste your your Gmaps API Key into the line [PASTE YOUR API KEY HERE], replace the Latitude and Longitude in this line: GPoint(-89.947729,38.781521), and replace the InfoWindowHTML in this line: marker.openInfoWindowHtml( with something else. How about:
marker.openInfoWindowHtml("Hello world!")
Once you have everything configured, save your file and then upload it to your website. Make sure you put it in the folder you registered with the Gmaps API. Otherwise you'll get an error message.

Once you've done all that, go test it. To see my sample using the code from Figure 5, click here!

The Next Level: Multiple Locations

Still with me? Great! You have just made your first Google Maps page. Now let's move up to putting multiple locations on the map.

There are a few ways to go about this. At the time I submitted my proposal, Google had a nice feature that used an XSLT Style Sheet to display information in the information balloons. About a week later they announced they were dropping support for that feature in future versions of the API. I went back and reworked some of the maps I use on the Lewis & Clark Library System website. It turned out to be less of a hassle than I initially thought.

The Gmaps API has a very nice method that takes XML formatted data and creates points for a map. This is done using an AJAX call that requests an XML file and loads the data. Google has written their own XMLHttp "wrapper" that makes fetching the data really easy.

Let's start with the data format Google Maps uses (figure 6). According to the Gmap API reference (Using XML & Async RPC), the format they expect is:

Figure 6:
// Download the data in data.xml and load it on the map. The format we
// expect is:
// <markers>
// <marker lat="37.441" lng="-122.141"/>
// <marker lat="37.322" lng="-121.213"/>
// </markers>

Taking a spin on that, we can create a similarly formatted document, but add in our own data for each point we want to map. We're also going to add a "marker" node. This holds the location and defines the type of marker we'll use to mark each point. The standard marker is the red marker. We could create our own custom marker, and use the marker node to define the URL for the custom marker.

On to figure 7, where we see a spin on Gmaps required format.

Figure 7:
File: data.xml
<?xml version="1.0" encoding="utf-8"?>
<members>
  <member>
    <point lng="-89.88194" lat="39.285685"/>
    <icon image="marker.png" class="local"/>
    <info>
      <bid>bha</bid>
      <libraryname>Carlinville Public Library</libraryname>
      <html>
        <table width='215'><tr><td><a target='_blank' href='http://www.carlinvillelibrary.org/'>Carlinville Public Library</a></td></tr><tr><td><img src='http://www.carlinvillelibrary.org/images/exterior_header.jpg' border='0' width='195px' height='95' /></td></tr><tr><td>510 N. Broad Street<br />Carlinville,IL 62626<br />217-854-3505</td></tr></table><br /><a target='_blank' href='http://maps.google.com/maps?q=510 N. Broad Street%20Carlinville,%20IL'>Directions</a>
      </html>
    </info>
  </member>
  <member>
    <point lng="-89.954252" lat="38.811356"/>
    <icon image="marker.png" class="local"/>
    <info>
      <bid>bea</bid>
      <libraryname>Edwardsville Public Library</libraryname>
      <html>
        <table width='215'><tr><td><a target='_blank' href='http://www.edwardsvillelibrary.org/'>Edwardsville Public Library</a></td></tr><tr><td><img src='http://www.lcls.org/images/members/ede.jpg' border='0' width='195px' height='95' /></td></tr><tr><td>112 South Kansas Street<br />Edwardsville,IL 62025<br />618-692-7556</td></tr></table><br /><a target='_blank' href='http://maps.google.com/maps?q=112 South Kansas Street%20Edwardsville,%20IL'>Directions</a>
      </html>
    </info>
  </member>
</members>

What I've done above in Figure 7 is taken a little spin on the Google Maps format. I have taken data from some of our member libraries and created my own little format to use with Google Maps API. I still have their required marker node (though I call my node "point") which has the lat & lng attribute. What I have added is another node called "info". The "info" node will hold data about each member library. Inside the info node I have an Id, the Library name, and another node called HTML which holds the info window HTML that is displayed when you click the marker.

The code to use an XML file to create map points is a little more complex than what we covered already. So let's look at Figure 8 to see what things will look like. Then we'll disect each line and learn how it all comes together.

Figure 8:
File: multiplelocations.html
<html>
<head>
<title>My Google Map Page - Now with Multiple Locations!</title>
<script src="http://maps.google.com/maps?file=api&key=[PASTE YOUR API KEY HERE]" type="text/javascript"></script>
</head>
<body>
<div id="map" style="width: 450px; height: 450px;></div>
<script type="text/javascript">//<![CDATA[
var map;
function load(){
map = new GMap(document.getElementById("map"));
var point = new GPoint(-89.948426,38.781529);
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.centerAndZoom(point, 9);
var baseIcon = new GIcon();
baseIcon.shadow = "shadow50.png";
baseIcon.iconSize = new GSize(20, 34);
baseIcon.shadowSize = new GSize(37, 34);
baseIcon.iconAnchor = new GPoint(9, 34);
baseIcon.infoWindowAnchor = new GPoint(9, 2);
baseIcon.infoShadowAnchor = new GPoint(18, 25);
function createMarker(point, iconname, info) {
var icon = new GIcon(baseIcon);
icon.image = iconname.getAttribute("image");
var marker = new GMarker(point, icon);
GEvent.addListener(marker, "click", function() {marker.openInfoWindowHtml(info.childNodes[2].firstChild.data);});
return marker;
}
var request = GXmlHttp.create();
request.open("GET", "data.xml", true)
request.onreadystatechange = function() {
if (request.readyState == 4) {
var xmlDoc = request.responseXML;
var points = xmlDoc.documentElement.getElementsByTagName("point");
var icons = xmlDoc.documentElement.getElementsByTagName("icon");
var info = xmlDoc.documentElement.getElementsByTagName("info");
for (var i = 0; i < points.length; i++) {
var point = new GPoint(parseFloat(points[i].getAttribute("lng")),parseFloat(points[i].getAttribute("lat")));
var marker = createMarker(point, icons[i], info[i]);
map.addOverlay(marker);
}
}
}
request.send(null);
}
//]]>
</script>
</body>
</html>

The first lines really start out the same as before. The new code begins with the line: var baseIcon = new GIcon();. The GIcon class lets you define icons. According to Google's documentation:

In many cases, your icons may have different foregrounds, but the same shape and shadow. The easiest way to achieve this behavior is to use the copy constructor for the GIcon class, which copies all the properties over to a new icon which you can then customize. The following example demonstrates this icon-copying technique.
source: http://www.google.com/apis/maps/documentation/#Using_Icon_Classes

Using this method we could actually create new icons (their sample shows markers labeled "A", "B", "C", etc.), but use the same shawdow and other properties. We're not actually going to use a different icon, but I'm including this just so you know what it's for.

function createMarker(point, iconname, info) This is the function that will be called for each point in the data.xml file. This is where all the action happens. The createMarker function will take the parameters for each point and create a marker which will then be added to the map. Inside this function we can (and will) do a variety of things with the markers.

var icon = new GIcon(baseIcon); creates a new icon based off the baseIcon we created a few lines earlier. The new icon then has its image property set based on the <icon image="marker.png" class="local"/> in our data.xml (see figure 7) file. Using this knowledge, you could actually assign a different icon for each point in your data.xml file.

GEvent.addListener(marker, "click", function() {marker.openInfoWindowHtml(info.childNodes[2].firstChild.data);}); What a mouthful! What this does is add a click function to each marker. This is where you define what happens when a marker is clicked by the user. If you read it word by word you'll notice that we're telling it to execute the marker.openInfoWindowHtml function and in the parenthesis we're defining where the HTML is. In this case the HTML is coming from our data.xml file in the "html" element.

If you're spidey sense is tingling, then you may have realized that you could assign a variety of event listeners to a marker. That is to say, you have more options than just opening the little popup window.

*Note: The info.childNodes[2].firstChild.data line reads the value of the HTML node in my XML document. If you change the structure of the XML document, then you'll need to work with this line to get it to read your structure. This can be kind of tricky if you've never worked with the JavaScript XML Parser.

return marker; This does what it sounds like. It returns a GMaps marker to the calling function (which we'll get to in a minute).

The next three lines (starting with var request = GXmlHttp.create();) create the XML Http request that will fetch our data.xml file. The XML Http request is at the heart of the "AJAX" programming method. Google has created a nice wrapper for the XML Http request that returns a browser neutral request. (quick note here: Gmaps has a browser compatibility list)

request.open("GET", "data.xml", true) This line defines the how & where to get the data. This line assumes that data.xml is in the same folder on your website as the multiplelocations.html file (or whatever file you want GMaps to access data.xml from). You could pull the data in a number of ways using this call, so here are some examples:
request.open("GET", "/mysite/data.xml", true)
request.open("GET", "http://www.mysite.org/data.xml", true)
request.open("GET", "../data.xml", true)

I think you get the idea. The XML Http request gets the data and offers it to you in two ways. One is using the responseXML property of the request the other is using the responseText property of the request. Since we're working with XML, we'll use the responseXML property.

request.onreadystatechange = function() This builds the function that will execute when the request is completed and the data is retrieved. Without this, you would just download data with nothing defining what to do with the data.

if (request.readyState == 4) Checks the request to see if its ready. If the readyState is = 4 then it will execute the next lines

var xmlDoc = request.responseXML; This puts our xml in a variable we can work with.

var points = xmlDoc.documentElement.getElementsByTagName("point"); Gets all of the point elements from data.xml and puts them into a variable

var icons = xmlDoc.documentElement.getElementsByTagName("icon"); Gets all of the icon elements from data.xml and puts them into a variabl

var info = xmlDoc.documentElement.getElementsByTagName("info"); Gets all of the info elements from data.xml and puts them into a variabl

for (var i = 0; i < points.length; i++) Begins a for loop to go through each point element

var point = new GPoint(parseFloat(points[i].getAttribute("lng")),parseFloat(points[i].getAttribute("lat"))); For each point found, this creates a new GPoint object that will be used to create the marker.

var marker = createMarker(point, icons[i], info[i]); Calls the createMarker function with the point, the icon info, and the info from our XML that will be used in the infoWindow.

map.addOverlay(marker); Adds the marker to the map.

request.send(null); Sends the request to get the XML data. This is the last step and is what actually goes out to fetch the XML data from our data.xml file. The request is called with (null) because we are not sending any data, just retrieving it.

Now, put everything from figure 8 into a new html file, and put it in the same folder as your data.xml file and give it a shot. Your results should look something like this. Also, see my data.xml file.

To "mapinity" and beyond

There are many things you can do with your maps to take them to the next level. This tutorial should have given you a good base to build from and also knowledge of how Gmaps API works. Knowing how the API works will help you as you try to come up with your own "hacks" and of course when things break!

References

Google's Official Documentation
Google Maps API Basic Tutorials
XML.com: Hacking Maps with the Google Maps API

Resources

Google Map's API official blog
Google Groups: Google-Maps-API