Absolute beginners guide to Google Maps JavaScript v3

Since I first published my HowTo and the subsequent follow up for novices to get a Google Map on a web page it’s been the most popular post on my site by quite a margin.  Sadly it’s been resting on its laurels, and is now quite out of date and indeed broken.  So spurred on by my recent server replacement and attempt to revitalise this blog I present the new, improved, and generally working… Beginners Guide To Google Maps JavaScript v3.

The premise is simple; you’ve got a requirement to put a map on your site.  You don’t have the first clue how to do it.  You follow these instructions and you get you map.  Hopefully you’ll pick up enough to tweak the map to your requirements, if not – please ask in the comments and I’ll try and help you.  I’m assuming that you’ve got a bit of HTML experience, and that you’ve got a JavaScript debugger available to you (either Firebug for Firefox or Developer Tools built in to Chrome).

I’ve based a lot of this on the official Google tutorial here:  https://developers.google.com/maps/documentation/javascript/tutorial.  (I’m pretty sure they borrowed that from me in the first place, so it’s only fair ;) ).

Part 1.  Getting the map on the page

Get yourself an API key for Google Maps from here:  https://developers.google.com/maps/documentation/javascript/tutorial#api_key

Let’s start from the end and work back to the beginning.  Save this as an HTML document, change the API key, open it in your browser and you’ll have a map.  I’ve saved you a bit of time by already centring it on Barrow-in-Furness bus depot.

[js]
<!DOCTYPE html>
<html>
<head>
<title>My first Google Map</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map-canvas { height: 100% }
</style>
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXXXX&sensor=false">
</script>
<script type="text/javascript">
function initialize() {
var myLatLng = new google.maps.LatLng(54.124634, -3.237029)
var mapOptions = {
center: myLatLng,
zoom: 17,
mapTypeId: google.maps.MapTypeId.SATELLITE
};

var map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);

var myMarker = new google.maps.Marker({
position: myLatLng,
map: map,
title: "A place on Earth",
draggable: true,
})
}

google.maps.event.addDomListener(window, ‘load’, initialize);
</script>
</head>
<body>
<div id="map-canvas"/>
</body>
</html>
[/js]

Copy and paste that in to a text editor, replace XXXXXXXXXXXXXXXX with your own API key, save it somewhere and the load it up in your browser.  You should see a satellite style map with a marker in the middle. You’re done.  Simple eh?  Read on learn a bit about how it works, and what you can do to change the appearance.

Part 1.1 Understanding the basic HTML

In order to try and guarantee a consistent layout across browsers you need to make sure that your page is rendered in ‘Standards Compliant’ mode as opposed to ‘Quirks’ mode. To do this you need to specify a DOCTYPE at the top of your HTML file.  We’re using a very simple “html” DOCTYPE which tells the browser that we’re HTML5.  In HTML4.x there were a plethora of variations – thankfully we don’t need to care about them anymore.  HTML5 is the way to go, and so the only DOCTYPE we care about is “html”.

We set the title of the page, and then we set some initial viewport settings to help mobile browsers render the page correctly.  This is widely regarded as a good thing, and you can learn more about it from here: http://webdesign.tutsplus.com/tutorials/htmlcss-tutorials/quick-tip-dont-forget-the-viewport-meta-tag/

Skipping over the style and scripts for a moment, we create the main body of the page with a single div element in it.  We give it the id “map-canvas”, and then we close off the bottom of the body and mark the end of the HTML.  You won’t be surprised to read that the div we’ve just created will be where the map will soon appear.

Part 1.2 All about style

In standard HTML5 (remember the DOCTYPE from above) there are a few specifics you need to know about CSS.  If an element specifies a size as a percentage, then that percentage is calculated from the parent objects size.  Imagine you have a nested DIV, called DIV2.  It lives inside DIV1.  Where DIV1 has a fixed size of 500px by 500px, then DIV2 knows that 100% high equals 500px, but what if DIV1 didn’t have a size specified?  In that case, in standards mode, DIV2 would decide that 100% high equals zero px – because it doesn’t know any better.  This has caught people out a few times.  In order to make sure that all our DIVs can inherit a size correctly we set the height of the entire HTML page and the BODY to be 100%.  This is calculated by the browser when the page loads, and then can flow down to the elements within the page correctly.

Once we have the parent elements size set correctly (the page, and the body) we can style our map DIV to be 100% high safe in the knowledge that it has enough information to render and the correct size and not 0 px high.

Part 1.3 The Meat Section

Now we’re going to look at the actual JavaScript and understand what it’s doing and in which order.

First of all, we have the scripts in the HEAD tag.  The browser will load the head part of the HTML first and your scripts will be loaded before the page is fully rendered.  Any functionality that you make available in your scripts should be available to the rest of the page when it comes to need it.  This is generally the right way to do it.

The first SCRIPT tag takes care of loading the Google Maps code.  We tell the browser that the content of the script is text/javascript and then where to find it.  There are a couple of parameters we pass  in to the script through the URL.  The first one is “key” – this is your simple API key for access Google Maps (see above for details of where to get this key).  The second parameter is “sensor”.  This is required and must be “false” if you’re not using a GPS (or similar) to work out where you are.  In our case, we’re just picking a point on and saying “centre the map here” – so we use false.  If were using a GPS to centre the map on our current location, then this would be “true”.

This script gets loaded by the browser and now we can start to make use of the Google Maps JavaScript APIs in the rest of our page.

The second script is a bit more complex, but should be easy to understand:

We create a new function called “initialize”.
Inside that function we create an object called myLatLng.  We use the Google provided API google.maps.LatLng() to create an object which can be understood by the rest of the Google Maps API and pass in the co-ordinates of Barrow-in-Furness bus depot.  We use “var” to limit that object’s “scope” to within the “initialize” function – that is to say, we won’t be able to get access to that particular myLatLng from other functions on the page.
Next we create another thing called mapOptions.  The format of this is as per the spec here: https://developers.google.com/maps/documentation/javascript/reference?hl=en#MapOptions

There are loads of options, most of which we don’t need to worry about, so we’re just setting a few key options:  where the map is centered, how much it is zoomed in, and the type of map we see.  The map types are provided by Google as a set of constants, which are identifiable by being all in upper case.  In our case we’re using SATELLITE, but we could also use HYBRID, ROADMAP or TERRAIN.

Once we’ve set up the various mapOptions we create a new var called “map” which is an instance of a Map object as provided by the Google APIs.  We pass in to it the id of the HTML object where we want the map to appear, as we created in section 1.2, and we pass in the options var which we just created.  This is enough information for the Google APIs to set up the map as we want it and put it on the page.

The last thing we do in our example is add a marker.  A marker is the indicator which you use to highlight a point on the map.  Google provide a lot of icons and colours for us to use, but the default is the red tear-drop one, so we’ll stick with that for now.

To create a marker we create a new instance of google.Maps.Marker and set up some of the options as we did for the map itself.  We tell it the position for the marker to appear.  We use the “myLatLng” object we created earlier.  You might notice that we are using the myLatLng object twice in our example.  Once as the centre point for the map, and once for the position of the marker.  You can probably deduce from this that the marker will appear in the centre of the map.  We also tell the marker which map it should be added to.  We only have one map on our page, but if we had many this is how you’d add a marker to the correct map.  We give it a title, which is simply a string and we make it draggable by setting the draggable option to “true”.  You can read more about the marker options here: https://developers.google.com/maps/documentation/javascript/reference?hl=en#MarkerOptions

That’s very nearly it for our first simple map.  The last thing to do is use a DOM listener to trigger the above JavaScript when the page loads, and so make our map and marker appear.

google.maps.event.addDomListener is provided via the Google APIs and we pass in three pieces of information.  window is the object provided by the browser.  The ‘load’ event is actually is separate from the “onload” event you might have read about.  The load event signifies that the page is fully rendered and any JavaScript which wants to manipulate the DOM can begin work, and that’s what we want to do.  We want to swap the empty div with the id of “map” with the actual map.  So once the page is indeed loaded the command will execute the “initialize” function and all the magic will happen.

And that’s it.  We’re done.  We’ve got a map on the page centred at our chosen location, and there is a little marker to show a specific part of the map.

If you compare this to the original Beginners Guide I think you’ll say that this new version of the API is even easier to use.  I will try and find time of the next few months to jot down a few notes on doing more interesting things with the map but I hope that this will get you started.

Google announce Maps API version 3

In a post on the Google Geo Developers Blog, Mickey Kataria, Product Manager of something – Google Maps I’m guessing, announced Google Maps API version 3.  It will move away from the G…. name space and to the google…… name space.  

What does this mean for you?  Not a lot probably.  I expect that version 3 will still be a long time coming and that version 2 will be around for a while.  Still, it might be worth starting to move your code over to the google name space and the Google loader.

There are a raft of new features, most interesting to me is the improved support for mobile browsers.

Anyway, check out the post here:  http://googlegeodevelopers.blogspot.com/2009/05/announcing-google-maps-api-v3.html

and the new version 3 API reference:  http://code.google.com/apis/maps/documentation/v3/reference.html

Absolute beginners guide to Google Maps Javascript Part 2

Stop!  This page is out of date.  Read this one first.

Part 2. Doing a bit more with the Google Maps API

This guide follows on from this one: http://www.whizzy.org/2009/05/absolute-begineers-guide-to-google-maps-javascript/
You’ll need to install Firefox and the Firebug add-on: https://addons.mozilla.org/en-US/firefox/addon/1843

If you’ve run through the previous guide you should have a little 27 line piece of HTML and JavaScript which gets you a basic draggable map on to your page with a marker in the centre.  It’s not much, but it was easy to do and most of all it didn’t take us very long.  Now we’re going to make the process of adding more markers to the map a bit easier, give each marker an infoWindow to display some text and see how to read some information back out of the marker object and finally we’ll give our marker a different icon to the standard red one.

  1. Create a function to add Markers
  2. Giving markers an infoWindow
  3. Reading information back out of the marker
  4. Changing the marker icon

Part 2.1 Creating a function to add Markers

Why do you need a function to add markers when you could just copy & paste the line we used in part 1. Imagine you have 50 markers added to your map, they would all have different co-ordinates but they might also have some common features such as “type” which might be ‘Bus Stop’. What would happen if you wanted to make a change to that title for all your makers, like adding a prefix of ‘Marker:’? If you used the copy & paste method to create the 50 markers you would have to go through each of the 50 lines and make the change, but if you used a function to create the markers and moved the common attributes to that function you would only need to make the change in one place – inside the function. By doing this we are using the DRY principal – Don’t Repeat Yourself. It will allow us to specify all common attributes only once and so therefore make changing those common attributes very quick. Our new function is called addMarker and when added to our code from part 1, the <script> section looks like this:

<script type="text/javascript">
  google.load("maps","2", {"other_params":"sensor=false"});
  function init() {
    map = new google.maps.Map2(document.getElementById("map"));
    var myLatLng = new google.maps.LatLng(54.124634, -3.237029);
    map.setCenter(myLatLng,17);
    map.addControl(new google.maps.LargeMapControl());
    map.addControl(new google.maps.MapTypeControl());
    map.setMapType(G_SATELLITE_MAP);
    newMarker1 = addMarker(54.124634, -3.237029,'Barrow-in-Furness Bus Depot');
    newMarker2 = addMarker(54.124500, -3.237129,'Monster defence system');
  };
  function addMarker(lat,lng,marker_title) {
    var myLatLng = new google.maps.LatLng(lat,lng);
    marker_title = 'Marker:  '+marker_title;
    var myMarkerOptions = {"draggable":true, "title":marker_title};
    var myMarker = new google.maps.Marker(myLatLng, myMarkerOptions);
    map.addOverlay(myMarker);
    return myMarker;
  };
  google.setOnLoadCallback(init);
</script>

You can see the new addMarker function inserted between the closing curly bracket of init() and the line google.setOnLoadCallback(init);.  The function accepts three things as shown by the comma separated values inside the brackets – lat,lng and title.  These are variables which become accessible inside the function and will be set to the values passed in when the function is called, in the same order as they are passed in.  For example, if I called the addMarker function like this:

addMarker('blue',42,'soup');

then lat would become a string ‘blue’,  lng would become the number 42 and title would be a string ‘soup’.  Obviously those values aren’t going to be valid for our real function as ‘blue’ is not a measurement of latitude – but you get the idea.   We actually call the function from inside the init() function,  like this:

newMarker1 = addMarker(54.124634, -3.237029,'Barrow-in-Furness Bus Depot');
newMarker2 = addMarker(54.124500, -3.237129,'Monster defence system');

You can see we actually pass in a real latitude, longitude and title string.
Back inside the new function, the first thing we do is construct a new instance of a google.maps.LatLng class by passing it the lat and lng variables that were used when the function was called.   We assign this to a local variable called myLatLng.  Notice we use var myLatLng – this makes myLatLng local to our function, it’s not a global variable.   Next we prepend ‘Marker: ‘ to the marker_title variable and then we declare another function-local variable (note the var) which is our dictionary of keywords and values mated together with a colon and separated from each other with a comma.  This also demonstrates why using a function is a better way of doing things.   On the whole marker options are likely to the same for every marker you have on your map,  so rather than specifying the same set of options for each marker we only do it once, inside the function.  If we want to change the options we just have to change one line rather than one line per marker.  If you wanted to add more options you would just add them to the end of the dictionary.  For example, let’s say you wanted to make your markers not bounce up and down when you let go after dragging.   From the API reference we can see that the option is “bouncy” and to turn it off we set it to false, so we just add that to the end:

var myMarkerOptions = {"draggable":"true", "title":marker_title, "bouncy":false};

You’ll notice that we don’t need to make “bouncy” true in order to get bouncy markers, from the API reference we can see that draggable makers are bouncy by default.

The next line creates a new instance of a google.maps.Marker class called myMarker and we use the variables we have defined above as constructors – myLatLng, which is an instance of a google.maps.LatLng and myMarkerOptions which is a dictionary of keywords and values.  myMarker is now a fully formed marker that can be added to the map with map.addOverlay(myMarker) where map is our instance of google.maps.Map2 – the main Google Maps class.
The last bit of our function is where things get a bit conceptual:

return myMarker;

When we instantiate the new marker we store a reference to it in the variable myMarker.  myMarker is not actually the object, but rather a set of directions telling us where that marker is in memory.  We can pass that reference around to tell functions which marker we are talking about when we perform actions on it,  such as adding it to the map with addOverlay.   We call addOverlay and tell it where to find the marker we have just created.  A problem arises when we call the addMarker function for a second time, as the variable myMarker stops being directions to the first marker and starts being directions to the new marker.  We have lost our directions to the first marker.  It still exists in memory, and the map knows where it is, but we don’t.  This is why we return the reference, or directions, at the end of our function – so we can keep a record of it outside of the addMarker function.  When we call the function first time around:

newMarker1 = addMarker(54.124634, -3.237029,'Barrow-in-Furness Bus Depot');

the ‘return myMarker;’ passes the reference to the marker back out of the function and the ‘newMarker1 =’ accepts that returned reference and becomes a reference to the marker itself.  Then, then next time we call the function:

newMarker2 = addMarker(54.124500, -3.237129,'Monster defence system');

newMarker2 becomes a reference to the second marker.

So there you have it.  A simple little function that makes it a bit easier to add new markers.  If you want a nice way of storing all these references and then being able to do things like loop through them – look up JavaScript arrays – but we’ll cover this in a later tutorial.  Now we’ve got our function we can start adding more features to it.

Part 2.2 Adding Info Windows to your markers.

An Info Window is a pop-up area inside that map that you can use to provide more information about markers.  It usually appears when you click on a marker.   There are many different types of infoWindow available with the Google Maps API, but for now we will be using an HTML infoWindow because it’s very easy to set up.  If we are going to display an infoWindow we are going to need some information to display in it, so the first thing is to extend our function to accept a fourth incoming variable which can be used to pass in the contents of the infoWindow.

function addMarker(lat,lng,title,descr) {

This gives us a new variable inside the function called ‘descr’ which we will use as the contents of the infoWindow.  As we are using an HTML infoWindow we could pass an HTML string in to our function when we call it, something like this:

newMarker1 = addMarker(54.124634, -3.237029,'Barrow-in-Furness Bus Depot','<b>Barrow-in-Furness Bus Depot</b><br />Under threat from monsters');

… or we could just pass in some plain text and HTMLifiy it inside the function, which is a much better idea as we can affect a global change much more easily inside the function.  So we will just use a plain string:

newMarker1 = addMarker(54.124634, -3.237029,'Barrow-in-Furness Bus Depot', 'under threat from monsters');

which means we need to add the HTML inside the function.  We will do this by associating a new variable to the marker object:

var myMarker = new google.maps.Marker(myLatLng, myMarkerOptions);
myMarker.infoHtml = '<b>'+title+'</b><br />'+descr

the ‘var myMarker…’ line is the same as it was above, I’ve included it here to show you where the new line appears, that is underneath the line where we instantiate myMarker.  So, after we have created our myMarker we associate a new variable with it, called infoHTML.  This is a very powerful function of JavaScript and we should explain exactly what’s happened here.  We have created a new attribute or property within the myMarker object and assigned it a value.  This property, or association, now lives with the myMarker object.  We can add lots of extra information to myMarker very easily and use our reference to get access to them in this way.   So anywhere that this marker goes, infoHtml will go with it.   You can see that our HTML is made of the title in bold, a newline and the descr tagged on the end.

Now we have the HTML ready for the infoWindow we need to trigger the opening of that window.  As you would expect this is triggered when you click on a marker.  The Google Maps API makes it easy for us to hook in to this “click” event and to trigger our own code:

google.maps.Event.addListener(myMarker, "click", function() {
myMarker.openInfoWindowHtml(myMarker.infoHtml, {maxWidth: 300});
});

The Map2 class has a number of events that we can listen out for.  We register our interest in a particular event by using the addListener method of Event.  We are saying that when a “click” event is generated from source myMarker (where myMarker is a reference to the marker we are adding during this call of the function) then execute this function, and then the function to be run.  That function, which is included inline, simply calls the openInfoWindowHtml method of myMarker with the infoHtml string we associated with the marker, and then the optional maxWidth keyword.

And that’s all there is to it.  Now you have a function to create markers with infoWindows.  The whole thing looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="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"/>
    <script type="text/javascript" src="http://www.google.com/jsapi?key=xxx"></script>
    <script type="text/javascript">
    google.load("maps","2", {"other_params":"sensor=false"});
      function init() {
        map = new google.maps.Map2(document.getElementById("map"));
        var myLatLng = new google.maps.LatLng(54.124634, -3.237029);
        map.setCenter(myLatLng,17);
        map.addControl(new google.maps.LargeMapControl());
        map.addControl(new google.maps.MapTypeControl());
        map.setMapType(G_SATELLITE_MAP);
        newMarker1 = addMarker(54.124634, -3.237029,'Barrow-in-Furness Bus Depot', 'Very tasty to monsters');
        newMarker2 = addMarker(54.124500, -3.237129,'Monster defence system', 'Chewits to deflect hungry monsters');
        };
      function addMarker(lat,lng,title,descr) {
        var myLatLng = new google.maps.LatLng(lat,lng);
        title = 'Marker:  '+title;
        var myMarkerOptions = {"draggable":true, "title":title, "bouncy":false};
        var myMarker = new google.maps.Marker(myLatLng, myMarkerOptions);
        myMarker.infoHtml = '<b>'+title+'</b><br />'+descr
        map.addOverlay(myMarker);
        google.maps.Event.addListener(myMarker, "click", function() {
          myMarker.openInfoWindowHtml(myMarker.infoHtml, {maxWidth: 300});
          });
        return myMarker;
        };
      google.setOnLoadCallback(init);
    </script>
    <title>My first Google Map</title>
  </head>
  <body onunload="google.maps.Unload()">
    <div id="map" style="width: 800px; height: 800px; margin: auto; background-color: red">
      This is where the map will soon appear.
    </div>
  </body>
</html>

Part 2.3 Reading information back out of the marker.

Since our markers are draggable it would be useful to know where they have been moved to. We need somewhere to display that information and a means of reading the co-ordinates from the marker. Of course, this is made easy with the Google Maps API! First of all we’ll add a couple of text input areas to the HTML to use as somewhere to display the co-ordinates after a marker has been moved:

<div id="output">
  <label for="lat">Latitude:</label><input id="lat" type="text" value="Unknown" >
  <label for="lng">Longitude:</label><input id="lng" type="text" value="Unknown" >
</div>

Using text input boxes makes it easy to copy & paste the results.
Then we need a new function to read the information out of the marker. As before, the API provides a nice easy way for us to hook in, an event is generated when a marker has been dragged and then stops being dragged, called dragend (http://code.google.com/apis/maps/documentation/reference.html#GMarker.dragend). We add a listener to this event:

google.maps.Event.addListener(myMarker, "dragend", function() {
  var lat_box = document.getElementById("lat");
  var lng_box = document.getElementById("lng");
  var coords = this.getLatLng();
  lat_box.value = coords.lat();
  lng_box.value = coords.lng();
});

The structure of this section of our function is very similar to the infoWindow bit. We are adding a listener to the marker object that gets triggered when the dragend event is fired. This listener becomes part of the marker object referred to by myMarker. It works like this: the dragend event is fired when you release the mouse button having moved the marker, which in turns executes in inline function. We use “document.getElementById” and pass in the ID of the element to get a reference to elements in the DOM where we are going to write our output. Then we read the co-ordinates from the marker object and put them in the variable “coords”. To do this we refer to “this”. “this” is a special keyword in JavaScript, it refers to the owner of the function. So in our function, which is inline with the addListener method, the owner is set the marker itself, and the marker has a method getLatLng which returns a google.maps.LatLng, which in turn has a lat method and lng method.
We combine all these things to set the contents of the two text boxes to be the latitude and longitude of the marker that was dragged.

Part 2.4 Using your own icon

By default the Google Maps API provides you with nice red marker icon, which is fine for most maps.  On my Potton Online website I needed to be able to show lots of different types of marker on one map (see http://www.pottononline.net/map/).  The most user-friendly way of doing this was to make each type of marker have it’s own icon.  You won’t be surprised to hear that one of the options available when creating a new instance of a marker is “icon”.  This “icon” option needs to be a google.maps.Icon class, which has a number of properties that define the icon to be used. Unfortunetly it’s not just a case of saying “Use this image to be the icon”, but it’s not a lot more complicated.   We will create a function to create these google.maps.Icon instances and we will modify the addMarker function to accept these Icons so that the google.maps.Marker construction can use it.
The new function to spit out google.maps.Icon instances looks like this:

function createIcon(iconUrl, shadowUrl) {
  var myIcon = new google.maps.Icon();
  myIcon.image = iconUrl;
  myIcon.shadow = shadowUrl;
  myIcon.size = new google.maps.Size(32,32);
  myIcon.shadowsize = new google.maps.Size(59,32);
  myIcon.iconAnchor = new google.maps.Point(16,32);
  myIcon.infoWindowAnchor = new google.maps.Point(16,0);
  return myIcon;
};

I hope that you’ll be able to look at this function and have a rough idea how it works.   But let’s run through it anyway.  The function accepts two inputs;  iconUrl and shadowUrl.  The icons on a map can have a shadow to give the impression that are standing up vertically from the map.   This shadow is just an image with some clever stretching performed on it.  The first thing we do is create a new empty instance of google.maps.Icon.  We see from the API reference there are no required constructors,  so we won’t use any.  A google.maps.Icon has a number of properties, some of which are required, some of which aren’t.   It isn’t immediately apparent to me which is which, so through trial and error I came up with this list.  For now, just belive me.  The first property is image.  Fairly obviously this is required, and it’s a URL to a location where the image can be found.   The same goes for shadow.   size and shadowsize describe the size in pixels of the image and its associated shadow.  These are of the type google.maps.Size which is just an x,y pair of numbers.  We’re including them inline to save on typing.  The iconAnchor and infoWindowAnchor are similar to the size properties.   These describe a point on the icon where the it is anchored to the window and the infoWindow.   These are also a special type, this time called Point.  The last line returns the bundle of properties called myIcon back to the place where the function was called from.  To call this function we use a line like this:

var icon = createIcon('http://maps.google.com/mapfiles/ms/micons/bus.png', 'http://maps.google.com/mapfiles/ms/micons/bus.shadow.png');

So “icon” now becomes an instance of google.maps.Icon and can be used when we instantiate our marker.  This is done by passing the variable “icon” in to the addMarker function.  When we call addMarker now, the line would look like this:

newMarker1 = addMarker(54.124634, -3.237029,'Barrow-in-Furness Bus Depot', 'Very tasty to monsters', icon);

You can see we’ve just tagged “icon” on the end of the data we are passing in to addMarker.   Of course, this means that we need to modify the addMarker function to accept this extra information.   So the whole addMarker function now looks like this:

function addMarker(lat,lng,title,descr,icon) {
  var myLatLng = new google.maps.LatLng(lat,lng);
  title = 'Marker:  '+title;
  var myMarkerOptions = {"draggable":true, "title":title, "bouncy":false, "icon":icon};
  var myMarker = new google.maps.Marker(myLatLng, myMarkerOptions);
  myMarker.infoHtml = '<b>'+title+'</b><br />'+descr
  map.addOverlay(myMarker);
  google.maps.Event.addListener(myMarker, "click", function() {
    myMarker.openInfoWindowHtml(myMarker.infoHtml, {maxWidth: 300});
    });
  google.maps.Event.addListener(myMarker, "dragend", function() {
    var lat_box = document.getElementById("lat");
    var lng_box = document.getElementById("lng");
    var coords = this.getLatLng();
    lat_box.value = coords.lat();
    lng_box.value = coords.lng();
    });
return myMarker;
};

The changes are on the first line, where we add ‘icon’ to the list of function inputs and we add another keyword to the myMarkerOptions line “icon” and the value icon which is the google.maps.Icon class we passed in when we called the function.  And that’s it!  Now your marker has an icon, which has it’s source as a URL to an image on the internet.

If we combine all these steps from Part 1 and Part 2 our entire HTML file now looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="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"/>
    <script type="text/javascript" src="http://www.google.com/jsapi?key=xxx"></script>
    <script type="text/javascript">
      google.load("maps","2", {"other_params":"sensor=false"});
      function init() {
        map = new google.maps.Map2(document.getElementById("map"));
        var myLatLng = new google.maps.LatLng(54.124634, -3.237029);
        map.setCenter(myLatLng,17);
        map.addControl(new google.maps.LargeMapControl());
        map.addControl(new google.maps.MapTypeControl());
        map.setMapType(G_SATELLITE_MAP);
        var icon = createIcon('http://maps.google.com/mapfiles/ms/micons/bus.png', 'http://maps.google.com/mapfiles/ms/micons/bus.shadow.png');
        newMarker1 = addMarker(54.124634, -3.237029,'Barrow-in-Furness Bus Depot', 'Very tasty to monsters', icon);
        var icon = createIcon('http://maps.google.com/mapfiles/ms/micons/snack_bar.png','http://maps.google.com/mapfiles/ms/micons/snack_bar.shadow.png');
        newMarker2 = addMarker(54.124500, -3.237129,'Monster defence system', 'Chewits to deflect hungry monsters', icon);
        };
      function addMarker(lat,lng,title,descr,icon) {
        var myLatLng = new google.maps.LatLng(lat,lng);
        title = 'Marker:  '+title;
        var myMarkerOptions = {"draggable":true, "title":title, "bouncy":false, "icon":icon};
        var myMarker = new google.maps.Marker(myLatLng, myMarkerOptions);
        myMarker.infoHtml = '<b>'+title+'</b><br />'+descr
        map.addOverlay(myMarker);
        google.maps.Event.addListener(myMarker, "click", function() {
          myMarker.openInfoWindowHtml(myMarker.infoHtml, {maxWidth: 300});
          });
        google.maps.Event.addListener(myMarker, "dragend", function() {
          var lat_box = document.getElementById("lat");
          var lng_box = document.getElementById("lng");
          var coords = this.getLatLng();
          lat_box.value = coords.lat();
          lng_box.value = coords.lng();
          });
        return myMarker;
        };
      function createIcon(iconUrl, shadowUrl) {
        var myIcon = new google.maps.Icon();
        myIcon.image = iconUrl;
        myIcon.shadow = shadowUrl;
        myIcon.size = new google.maps.Size(32,32);
        myIcon.shadowsize = new google.maps.Size(59,32);
        myIcon.iconAnchor = new google.maps.Point(16,32);
        myIcon.infoWindowAnchor = new google.maps.Point(16,0);
        return myIcon;
        };
      google.setOnLoadCallback(init);
    </script>
    <title>My first Google Map</title>
  </head>
  <body onunload="google.maps.Unload()">
    <div id="map" style="width: 800px; height: 800px; margin: auto; background-color: red">
      This is where the map will soon appear.
    </div>
    <div id="output">
      <label for="lat">Latitude:</label><input id="lat" type="text" value="Unknown" >
      <label for="lng">Longitude:</label><input id="lng" type="text" value="Unknown" >
    </div>
  </body>
</html>

At first glance that might look quite scary, but it’s really not that bad.  You should be able to read through the script section and understand how it works.

Additional

Hopefully you have installed the Firefox add-in called Firebug. If you have you can play around with the Google Maps API from the Javascript console built in to Firebug. Click on the little bug icon in the bottom left of the browser window and make sure the the console is enabled. Then you will see the console input area as shown by “>>>” at the bottom of the screen. In to this section type:

newMarker1.hide();

and then

newMarker1.show();

Now you got something else to play with. You could use this to show only markers of a particular type. We’ll cover this next time.

Absolute beginners guide to Google Maps Javascript

STOP!  This page is quite out of date!  Click here to read an up-to-date version.

So – you’ve got an idea for site that makes use of the Google Maps API but you lack any knowledge of Javascript whatsoever – where do you start?  Up until about 6 months ago I didn’t know, so I went about learning how and now I’m going to write it up in to a tutorial so you can find out too.  This guide is aimed at beginners of Javascript and DOM scripting, some knowledge of HTML is assumed.  We will assume that you are running the HTML from your local computer to start with, before uploading it to a server.  I would recommend that if you use Firefox, that you install the Firebug addon:  https://addons.mozilla.org/en-US/firefox/addon/1843  Chromium comes with the same functionality built in, just hit f12.

Part 1.  Getting that draggable map on to your web page.

The Google maps API really does a lot to make it easy to get the map to appear on your page, but you need to lay a few of the foundations first.  The steps involved in getting the map on to your page are:

  1. Getting a Google Maps API key
  2. Creating a correctly formatted HTML page
  3. Loading the necessary JavaScript libraries
  4. Writing your own JavaScript code to get the map to actually appear
  5. A bit more code to make the map into something useful

All of the above should be achievable in about 60 minutes.

Part 1.1  Getting a Google Maps API key

Nice and easy.  Go to:

https://developers.google.com/maps/documentation/javascript/tutorial#api_key (opens in a new window)

and follow the instructions.

While you don’t actually need an API key, it will help you to track usage and if your map page hits the big time you’ll already be set up.

Got your API key?  Good, let’s carry on.

Part 1.2  Writing the basic HTML

The best thing about standard HTML is that there is so much variety.  In order to try and guarantee a consistent layout across browsers you need to make sure that your page  is rendered in ‘Standards Compliant’ mode as opposed to ‘Quirks’ mode.  To do this you need to specify a DOCTYPE at the top of your HTML file.  Google recommends that you use this XHTML DOCTYPE:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

so your HTML file should have that line right at the top.  Hand in hand with this goes an ‘xmlns’ attribute on the <html> element in the page, like this:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">

We are using this particular line because we might want to make use of the PolyLine features of Google Maps in the future.  More on this in a later guide, for now just believe me.

It’s also important to specify the correct character encoding.  Google Maps by default uses UTF-8 and you should do the same unless you have a reason not to.  This is the example given by Google:

<meta http-equiv="content-type" content="text/html; charset=utf-8"/>

but this goes inside the HTML head area.

If we put all these together in to a very basic HTML file it would look something like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="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>My first Google Map</title>
  </head>
  <body>
    <div id="map" style="width: 800px; height: 800px; margin: auto; background-color: red">
      This is where the map will soon appear.
    </div>
  </body>
</html>

Copy and paste this in to a text editor and then save that file as something like ‘maps.html’ and open it in your browser. You won’t be amazed to see an 800 x 800 pixel red box in the middle of the screen. But the really important thing is that this is valid XHTML meaning the browser will render it in ‘standards compliant’ mode.

So far so good. You’ve got a Google Maps API key and now you’ve got an area on the page in which the maps can be displayed, now you just need get that map on to the page.

Part 1.3  Loading the Javascript libraries

Google to the rescue. They host a set of AJAX APIs that we can use to do some really clever tricks, but first we need to use the loader to get access to them. This is simply a case of loading the Google AJAX API Loader with this line inside the <head> section of the HTML page:

<head>
  ...
    <script type="text/javascript" src="http://www.google.com/jsapi?key=XXXXXXXXXXXX"></script>
  ...
</head>

where ‘XXXXXXXXX’ should be your API key.
This loads the Google loader, which we can then use to load the Google Maps API (and in the future any other Google hosted APIs such as jQuery which we’ll get to another day). Again, this code is located in the <head> section of the HTML, below the line that loads the Google loader. So, now our <head> section looks like this:

<head>
  ...
    <script type="text/javascript" src="http://www.google.com/jsapi?key=XXXXXXXXXXXX"></script>
    <script type="text/javascript">
      google.load("maps","2", {"other_params":"sensor=false"});
    </script>
  ...
</head>

What’s just happened here, is that you’ve just written a line of Javascript!  It’s not a very long or complicated line but it opens up a world of Javascript wonder to us.  There are six things we should mention about that one little line:

  1. Javascript inside an HTML file must be surrounded by <script> tags.  To make sure it’s a valid tag the opening one must say what sort of thing is inside.  In our case ‘text/javascript’
  2. The ‘google.’ bit becomes available after we loaded jsapi from www.google.com at the start of this section.  This is referred to as the google namespace.
  3. The google namespace has many methods.  One of these methods is ‘load’ which is separated from the ‘google’ bit with a ‘.’ and accepts a few arguments.
  4. The arguments are passed inside the brackets.  In our case we are passing the arguments ‘maps’ and ‘2’.  ‘maps’ is the API we want to load, and ‘2’ is the version.  Version 2 is a bit of a generic version number and actual version number that represents ‘2’ changes frequently.  For example, at the moment 2 represents version 2.97
  5. We also have to tell Google that we’re not using a sensor (e.g. GPS) to determine user location.  I don’t know why this should matter, but Google say you must tell them, so tell them we will.  This is a sort of dictionary where we link keywords with values.  In this case the keyword is ‘other_params’ and the value is ‘sensor=false’.
  6. The line ends with a semicolon.  You may see Javascript written where semicolons don’t appear at the end of a line.  Some browsers are smart enough to realise that a new line represents the end of a line of code, others are not.  So for now just always stick a semicolon on the end of a line, except where you are closing a curly bracket and then immediately closing a normal bracket.

Add these two script elements to your HTML file in the <head> section, below the meta tag and above the title, and reload the page.  If you’ve done it correctly you won’t notice any difference and Firebug should show no errors.

Part 1.4  Making the map appear

Now we’re going to write the code to make the basic map appear on your page, in 5 extra lines.

...
<script type="text/javascript">
  google.load("maps","2", {"other_params":"sensor=false"});
  function init() {
    map = new google.maps.Map2(document.getElementById("map"));
    map.setCenter(new google.maps.LatLng(54.124634, -3.237029),17);
  };
  google.setOnLoadCallback(init);
</script>
...

These extra lines of code go between the same <script> tags as the line we used to load the the Google Maps API and must come after the google.load line otherwise the google.maps namespace won’t exist.  First we create a new function called init.  As you’d expect – the function won’t do anything until it’s called, we’re just creating it so we can use it in a minute.  The function doesn’t take any arguments, hence the empty set of brackets.  The actual code inside the function lives between two curly brackets { } and of course each line ends with a semicolon.

First we declare a variable called map.  Notice that we don’t say ‘var map = new google.maps.Map2….’.  If we did use var then our ‘map’ would only be accessible from within the function that declared it (init in our case).  Since we are going to access the map from many other functions we’ll create ‘map’ as a global variable by not using var.

The variable ‘map’ becomes a new instance of the class ‘Map2’ from within the google.maps namespace.  The Map2 class takes a ‘constructor’ which specifies the node within the document that will be used to display the map.  In our case, as is most common, that node is a div element.  We pass the getElementById function the Id of our div and it returns a reference that we can then pass to Map2 as the required constructor.

Or, put differently, ‘map’ becomes a new copy of a thing called Map2 which Google have provided for us.  The new copy needs to know where to put the map, so we tell it which div we want to use.

Now our variable ‘map’ has been constructed it is an object of class Map2 and as such it posses certain predefined ‘methods’ and ‘events’.  A methods is a way of doing things, and events happen.  These are already in place and all we have to do is either tell them what to do, or listen to what they have to say.

The first method we make use of is setCenter (note the spelling Euro people).  Unsurprisingly the setCenter method sets the centre point for the map.  It takes as an argument a special Google LatLng object.  How do I know this you ask?  Everything you need to know about the Google Maps API can be found here  (centred on the setCenter method):  http://code.google.com/apis/maps/documentation/reference.html#GMap2.setCenter

(You need to be aware that the API refers to the original G namespace, not the google.maps namespace. So in the API wherever you see a capital G in front of something, you can probably assume you should drop the G and replace it with ‘google.maps.’  You can argue that we should stick to using the G namespace since that’s what the docs are written in, but the conversion is really easy, and I expect that all new API docs will use the full google namespace.  UPDATE:  Google have announced that indeed everything will be moving to the google namespace in the future.  http://googlegeodevelopers.blogspot.com/2009/05/announcing-google-maps-api-v3.html)

From the API reference you can see the method also accepts an optional (note the ‘?’ in the API reference) zoom and type.  Since it is optional will ignore the type for now, and only pass a LatLng object and a zoom level.  It’s easy to create our LatLng object, we just instanciate (create) a new google.maps.LatLng class with the latitude and longitude passed to it as numbers.  You can see we do all of this inline, we could equally have declared a new variable, this time with the var prefix, like this:

var myLatLng = new google.maps.LatLng(54.124634, -3.237029);

and then passed that to setCenter instead:

map.setCenter(myLatLng,17);

As you’ve probably already worked out the ’17’ is the optional zoom value.

Notice we close the function with another close-curly-brackets and a semicolon on a new line with the same indention as the line where we started the function, and the contents of the function indented from there.

The last of our Javascript lines causes our init function to get called and make the map appear.  When you are working with elements in the page, for example a div with and Id of ‘map’, using Javascript you are interacting with the DOM, Document Object Model.  This is the browsers internal table of what makes up the web page you are looking at and it gets created as the HTML source loads.  If you’re at the end of a particularly slow internet connection, say a mobile phone, and the page you are loading is quite large it could take a minute or two before all the HTML is loaded.  Before all the HTML is loaded the browser can’t finish building the DOM.  If you tried to reference an element in on the page  before it had loaded you would get an error something along the lines of “the element your are referring is undefined”.  To combat this the browser can tell you when the DOM is ready for you to use and to make things even easier the Google loader provides a nice easy way for you to call your functions when the DOM is ready.

From the google namespace we have a method called setOnLoadCallback which takes a function as an argument.  So we pass it our function called init, and sit back and relax as the browser loads the source, gets the DOM ready, signals that the DOM is ready, the onLoadCallback method gets triggered and in turn calls our init() function which replaces the div called map with a draggable Google Map.  So add the above few lines in to your HTML and reload your browser.  If you’ve done it right you should see a map!

In 21 lines of text we’ve created a Google map in the middle of our page.  It’s pretty basic, in that we can only drag it about and double click to zoom in or double right click to zoom out, but consider how little we had to do to make it work.

Part 1.5  Doing a bit more with the map

We’ve got a map, but it’s missing a few key parts like the zoom slider and the buttons to switch between the different map types and a marker indicating a point on the map.

Remember how we could have created a variable to hold our google.maps.LatLng object, but that we didn’t need to?  Well, now we’re going to need to reference that LatLng in a couple of places, so it makes sense to keep it in a variable, just to save a bit of typing.  To do this we’re going to rewrite the init() function.  The new function looks like this:

function init() {
  map = new google.maps.Map2(document.getElementById("map"));
  var myLatLng = new google.maps.LatLng(54.124634, -3.237029);
  map.setCenter(myLatLng,17);
  var myMarker = new google.maps.Marker(myLatLng, {"draggable":"true","title":"A place on earth"});
  map.addControl(new google.maps.LargeMapControl());
  map.addControl(new google.maps.MapTypeControl());
  map.setMapType(G_SATELLITE_MAP);
  map.addOverlay(myMarker);
};

The way we create the map object stays the same, we create a new instance of class google.maps.Map2 and tell it which div we want to use to display the map.  The next line declares our new myLatLng variable which will be local to the init function because we use ‘var myLatLng….’ and then we set the centre of the map using our myLatLng variable and set the zoom level to 17.

Next we declare another new variable called myMarker.  This is a new instance of class google.maps.Marker, and to instantiate it we need to pass it a location in google.maps.LatLng format as per the map centre and some additional options.  Since we have used the same LatLng object for the Marker as we did for the setCenter the Marker will appear in the middle of the map.  Again, all of this information is found in the API reference:

http://code.google.com/apis/maps/documentation/reference.html#GMarker

where we can see that the options are listed under GMarkerOptions.  These options are passed to Marker in the dictionary style format we have seen before, that is – enclosed in curly brackets we have pairs of keywords and values.  The keywords and values are separated by a colon, and each pair is separated from the next with a comma.  In our example we are only passing two options:

{"draggable":"true","title":"A place on earth"}

If we wanted to add another option, say “bouncy” we’d just add it to the end:

{"draggable":True","title":"A place on earth","bouncy":"true"}

If you read the API reference you’ll see that we don’t need to pass “bouncy”:”true” though, as any marker that is “draggable” is also “bouncy” by default, but if you wanted to turn off “bouncy” you could say that “bouncy”:”false”.

We’ve now created our Marker object, but we haven’t added it to the map yet.  First of all though we add the zoom slider with directional buttons and the buttons to allow us to switch between the various map types (see the API reference under ‘GMapType’ – ‘Constants’ for the various types available).  To add these controls to our map we use the addControl() method of a google.maps.Map2 class, in our case the variable ‘map’.  From the API we see that the addControl method has a constructor which requires a GControl object and an optional position.  If we then look up the GControl object in the API reference we see that it too requires constructing (that is, it is not a constant – it must be summoned from somewhere before we use it).  The API shows that the GControl class constructors don’t require any further information in order to be created – as shown by the empty set of brackets, so to instantiate (summon) a GControl object we just create a ‘new’ one:

new google.maps.LargeMapControl()

will do that for us.  Remember if something in the API starts with an uppercase G we replace that G for ‘google.maps.’ (note the trailing dot).  Since the addControl method requires this new instance of a GControl class as a constructor we just pass it straight in:

map.addControl(new google.maps.LargeControl());

We could equally say:

var myLargeControl = new google.maps.LargeControl();
map.addControl(myLargeControl);

but MyLargeControl just sounds too rude.

We repeat this process to add the controls to switch between map types:

map.addControl(new google.maps.mapTypeControl());

Next we change the default map type to the satellite view instead of the default map which only shows roads.  We use the setMapType method of a google.maps.Map2 class (our variable map).  From the API we see that setMapType requires a GMapType.  We don’t know what a GMapType is, so we click on the link in the API which takes us here:

http://code.google.com/apis/maps/documentation/reference.html#GMapType

and have a quick read.  Straight away it says that Google have provided some predefined map types, so scroll down to “Constants” and you can see a list of these predefined map types.  We’re going to use the G_SATELLITE_MAP type and because it’s a constant we can just refer directly to it:

map.setMapType(G_SATELLITE_MAP);

Then last of all we add the marker we created earlier to the map:

map.addOverlay(myMarker);

addOverlay() is a method of google.maps.Map2 and accepts the marker as an overlay to add.  Each marker on the map is an overlay.

And there you have it.  A map on your web page in only 27 lines including the HTML itself.  The final HTML file looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="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"/>
  <script type="text/javascript" src="http://www.google.com/jsapi?key=xxx"></script>
  <script type="text/javascript">
    google.load("maps","2", {"other_params":"sensor=false"});
    function init() {
      map = new google.maps.Map2(document.getElementById("map"));
      var myLatLng = new google.maps.LatLng(54.124634, -3.237029);
      var myMarker = new google.maps.Marker(myLatLng, {"draggable":"true","title":"A place on earth"});
      map.setCenter(myLatLng,17);
      map.addControl(new google.maps.LargeMapControl());
      map.addControl(new google.maps.MapTypeControl());
      map.setMapType(G_SATELLITE_MAP);
      map.addOverlay(myMarker);
    };
    google.setOnLoadCallback(init);
  </script>
  <title>My first Google Map</title>
</head>
<body onunload="google.maps.Unload()">
  <div id="map" style="width: 800px; height: 800px; margin: auto; background-color: red">
    This is where the map will soon appear.
  </div>
</body>
</html>

Note – we have slightly modified the <body> to include an additional method from the google.maps namespace.  This function ensures that when you close the browser window containing your map everything is tidied up.  This prevents memory leaks in browsers such as IE6.  You should always include this in your code when you are using Google Maps.

Challenge 1.  As a bit of fun, why not try to add one of these to the map:

http://code.google.com/apis/maps/documentation/reference.html#GControlImpl.GOverviewMapControl

Challenge 2.  See if you can trim the code by one line and increase the available map types at the same time:

http://code.google.com/apis/maps/documentation/reference.html#GMap2.setUIToDefault

Coming in Part 2…

In part two we’ll cover more things you can do with markers such as:

  • Create a function to add markers to the map.
  • Giving markers pop-up info windows containg text
  • Reading information back out of the marker

Useful References

Google Maps API Concepts
http://code.google.com/apis/maps/documentation/

Google Maps API Reference
http://code.google.com/apis/maps/documentation/reference.html

Google Maps Examples
http://code.google.com/apis/maps/documentation/examples/index.html