TUTORIAL:

How to make your own photo travel map using the Google Maps API




Links

See my travel photo map
My blog
Artefotodigitale
Contact me

More photo travel maps

GeoBlogg by Paal Christian Bjønnes







































First: the key

Sign up for a Google Maps API key. It's free and it will allow you to get your own map.



Second: the XML file

Create an xml file named "markers.xml". This file will contain all the information needed for the markers (position on the map, picture, title, caption, icon type).
The root element of the file is "markers"; the root element contains several elements named "marker".
Here is an example:

<markers>
<marker lat="37.88" lng="-119.73" loc="Yosemite National Park" type = "NP" pic="yose.jpg" cpt="One of the nicest places in California"/>
</markers>


This is the meaning of the attributes:
  • lat: the latitude in degrees N, with decimals (not minutes and seconds)
  • lng: the longitude in degrees E, with decimals
  • loc: the description of the location
  • type: the type of location; this defines which icon is going to be used for the marker; the types are associated with icons in the head code of the html file
  • pic: the name of the picture
  • cpt: an extended description of the location
The latitude and longitude are obviously mandatory; the descriptions and the pictures, if defined, will be displayed in the pop-up baloon.


Third: the HTML file

Create the html file that will contain the map. This file will include some JavaScript code in the <head> as well as the <body> tags.


<HEAD> code:

First you have to reference the Google Maps API with your key:

<script src="http://maps.google.com/maps?file=api&v=1&key=your-key-here" type="text/javascript">
</script>

You'll have to replace "your-key-here" with your actual key.


Then you have to open a script and a data tags:
<script type="text/javascript">
//<![CDATA[




Then you have to define the variables:

var map;
var picIcon = new GIcon(G_DEFAULT_ICON);
picIcon.image = "http://www.biondani.com/giordano/marker_y+r.png";
var NPIcon = new GIcon(G_DEFAULT_ICON);
NPIcon.image = "http://www.biondani.com/giordano/marker_dg.png";
var picNPIcon = new GIcon(G_DEFAULT_ICON);
picNPIcon.image = "http://www.biondani.com/giordano/marker_y+dg.png";
var skiIcon = new GIcon(G_DEFAULT_ICON);
skiIcon.image = "http://www.biondani.com/giordano/marker_w.png";
var picSkiIcon = new GIcon(G_DEFAULT_ICON);
picSkiIcon.image = "http://www.biondani.com/giordano/marker_y+w.png";
var seaIcon = new GIcon(G_DEFAULT_ICON);
seaIcon.image = "http://www.biondani.com/giordano/marker_b.png";
var picSeaIcon = new GIcon(G_DEFAULT_ICON);
picSeaIcon.image = "http://www.biondani.com/giordano/marker_y+b.png";
var artIcon = new GIcon(G_DEFAULT_ICON);
artIcon.image = "http://www.biondani.com/giordano/marker_c.png";
var picArtIcon = new GIcon(G_DEFAULT_ICON);
picArtIcon.image = "http://www.biondani.com/giordano/marker_y+c.png";

The variable "map" references the map itself and will be used throughout the rest of the code.

The GIcon variables refer to the different types of markers; each type of marker is assigned a different icon (the icons have different colors).
For example, the GIcon named "picIcon" (see the first var declaration) has its image associated with the file called "marker_y+r.png", which is my yellow/red marker.


Then you have to load and populate the map; this happens inside the function "loadMap".
Load the map:
function loadMap() {
map = new GMap(document.getElementById("map"));
map.setMapType(G_SATELLITE_TYPE);
map.addControl(new GSmallMapControl());
map.centerAndZoom(new GPoint(-40, 45), 14);

The variable map was declared in the previous step; now we are associating it with the document element named "map". The document element "map" is defined below, in the html body.
This code sets the map type (satellite), the navigation control type (small controls), centers the map on a point in the Atlantic, and sets the appropriate zoom level (found by trial and error).
Populate the map:
var request = GXmlHttp.create();
request.open('GET', 'markers.xml', true);
request.onreadystatechange = function() {
  if (request.readyState == 4) {
    var xmlDoc = request.responseXML;
    var markers = xmlDoc.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
      var point = new GPoint(parseFloat(markers[i].getAttribute("lng")), parseFloat(markers[i].getAttribute("lat")));
      var pictureSegment = "<br><small>No picture available</small></div>";
      var picName = markers[i].getAttribute("pic");
      if (picName != null) {
        pictureSegment = "<br><img src=\"" + markers[i].getAttribute("pic") + "\" height=300 width=400 /></div>";
      }
      var captionSegment = "<br>";
      var caption = markers[i].getAttribute("cpt");
      if (caption != null) {
        captionSegment = "<br>" + caption;
      }
      var html = "<div style=\"white-space:nowrap;\"><b>" + markers[i].getAttribute("loc") + "</b>"
        + captionSegment + pictureSegment;
      var type = markers[i].getAttribute("type");
      var marker = createMarker(point, html, picName, type);
        map.addOverlay(marker);
    }
  }
}
request.send(null);
}

This code creates an http connection to the markers.xml file, then loops through the markers, reads their attributes, creates the markers, and lays them on the map.

While reading the attributes, it determines what to do if they are not found.

The description and image attributes are combined in an html segment that will be displayed by the pop-up balloon. The html segment is built as follows:
  • the pictureSegment variable contains the text "No picture available" or the file name and size of the picture, if available
  • the captionSegment variable contains an empty line or the caption, if available
  • the html variable contains the name of the location plus the pictureSegment and CaptionSegment variables. This variable is then passed on to the createMarker function.

The markers are created by the function "createMarker", which is defined below.


Function createMarker:
function createMarker(point, html, picName, type) {
  var marker;
  if (type == "NP") {
    marker = (picName != null) ? new GMarker(point, picNPIcon) : new GMarker(point, NPIcon); 
  } else if (type == "ski") {
    marker = (picName != null) ? new GMarker(point, picSkiIcon) : new GMarker(point, skiIcon);
  } else if (type == "sea") {
    marker = (picName != null) ? new GMarker(point, picSeaIcon) : new GMarker(point, seaIcon);
  } else if (type == "art") {
    marker = (picName != null) ? new GMarker(point, picArtIcon) : new GMarker(point, artIcon);
  } else {
    marker = (picName != null) ? new GMarker(point, picIcon) : new GMarker(point);
  }
  GEvent.addListener(marker, 'click', function(){
    marker.openInfoWindowHtml(html);
  });
  return marker;
}

This function expects as parameters the coordinates (point), the html segment, and the type.

Based on the type attribute of the marker, it decides which icon variable to use; each icon variable, as explained above, is associated with a specific icon.

Then we create an event listener associated with this marker; when the marker is clicked, the event handler opens a window that contains the html code defined above.

So the output of this function is a marker with the specified coordinates and icon, and with an event handler that pups up a baloon containing the description and picture of the location.


Then you have to close the data and script tags:

//]]>
</script>




<BODY> code

Load the map when the body is loaded:
<body onload="loadMap()">



Add the map to the page:
<div id="map" style="width: 1050px; height: 650px; border: 3px double gray;">
</div>

The id attribute is important because it's referenced by the loadMap function and by any other function that has to act on the map (see below).


If you want to create a link to a specific section of the map:

<a href="javascript:map.centerAndZoom(new GPoint(-114,39),11);">American West</a>
This inline command references the map id (defined above) and tells it to center and zoom to a new location.



This is the complete source of my photo travel map:
<!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">

<head>
<title>Giordano Biondani's Travel Pushpin Map</title>

<script src="http://maps.google.com/maps?file=api&v=1&key=xyz" type="text/javascript">
</script>

<script type="text/javascript">
//<![CDATA[
var map;
var picIcon = new GIcon(G_DEFAULT_ICON);
picIcon.image = "http://www.biondani.com/giordano/marker_y+r.png";
var NPIcon = new GIcon(G_DEFAULT_ICON);
NPIcon.image = "http://www.biondani.com/giordano/marker_dg.png";
var picNPIcon = new GIcon(G_DEFAULT_ICON);
picNPIcon.image = "http://www.biondani.com/giordano/marker_y+dg.png";
var skiIcon = new GIcon(G_DEFAULT_ICON);
skiIcon.image = "http://www.biondani.com/giordano/marker_w.png";
var picSkiIcon = new GIcon(G_DEFAULT_ICON);
picSkiIcon.image = "http://www.biondani.com/giordano/marker_y+w.png";
var seaIcon = new GIcon(G_DEFAULT_ICON);
seaIcon.image = "http://www.biondani.com/giordano/marker_b.png";
var picSeaIcon = new GIcon(G_DEFAULT_ICON);
picSeaIcon.image = "http://www.biondani.com/giordano/marker_y+b.png";
var artIcon = new GIcon(G_DEFAULT_ICON);
artIcon.image = "http://www.biondani.com/giordano/marker_c.png";
var picArtIcon = new GIcon(G_DEFAULT_ICON);
picArtIcon.image = "http://www.biondani.com/giordano/marker_y+c.png";

function loadMap() {
map = new GMap(document.getElementById("map"));
map.setMapType(G_SATELLITE_TYPE);
map.addControl(new GSmallMapControl());
map.centerAndZoom(new GPoint(-40, 45), 14);

var request = GXmlHttp.create();
request.open('GET', 'markers.xml', true);
request.onreadystatechange = function() {
  if (request.readyState == 4) {
    var xmlDoc = request.responseXML;
    var markers = xmlDoc.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
      var point = new GPoint(parseFloat(markers[i].getAttribute("lng")), parseFloat(markers[i].getAttribute("lat")));
      var pictureSegment = "<br><small>No picture available</small></div>";
      var picName = markers[i].getAttribute("pic");
      if (picName != null) {
        pictureSegment = "<br><img src=\"" + markers[i].getAttribute("pic") + "\" height=300 width=400 /></div>";
      }
      var captionSegment = "<br>";
      var caption = markers[i].getAttribute("cpt");
      if (caption != null) {
        captionSegment = "<br>" + caption;
      }
      var html = "<div style=\"white-space:nowrap;\"><b>" + markers[i].getAttribute("loc") + "</b>"
        + captionSegment + pictureSegment;
      var type = markers[i].getAttribute("type");
      var marker = createMarker(point, html, picName, type);
        map.addOverlay(marker);
    }
  }
}
request.send(null);
}

function createMarker(point, html, picName, type) {
  var marker;
  if (type == "NP") {
    marker = (picName != null) ? new GMarker(point, picNPIcon) : new GMarker(point, NPIcon); 
  } else if (type == "ski") {
    marker = (picName != null) ? new GMarker(point, picSkiIcon) : new GMarker(point, skiIcon);
  } else if (type == "sea") {
    marker = (picName != null) ? new GMarker(point, picSeaIcon) : new GMarker(point, seaIcon);
  } else if (type == "art") {
    marker = (picName != null) ? new GMarker(point, picArtIcon) : new GMarker(point, artIcon);
  } else {
    marker = (picName != null) ? new GMarker(point, picIcon) : new GMarker(point);
  }
  GEvent.addListener(marker, 'click', function(){
    marker.openInfoWindowHtml(html);
  });
  return marker;
}

//]]>
</script>
</head>

<body onload="loadMap()">
<font face="Trebuchet MS, verdana" size=-1>
<h2><center>Giordano Biondani's Travel Pushpin Map</center></h2>
<p>This map shows most of the places that I have visited.
I will keep adding pictures, but you can find more on <a href="http://photo.biondani.com/">Artefotodigitale</a>.
</p>
<p>Jump to:<br>
<a href="javascript:map.centerAndZoom(new GPoint(-40,45),14);">Default View</a>  |  
<a href="javascript:map.centerAndZoom(new GPoint(0,0),15);">World</a>  | 
<a href="javascript:map.centerAndZoom(new GPoint(-98,38),13);">North America</a>  | 
<a href="javascript:map.centerAndZoom(new GPoint(-114,39),11);">American West</a>  | 
<a href="javascript:map.centerAndZoom(new GPoint(9,55),14);">Europe</a>  | 
<a href="javascript:map.centerAndZoom(new GPoint(12,47),12);">Central and Southern Europe</a>  | 
<a href="javascript:map.centerAndZoom(new GPoint(12,42),11);">Italy</a>  | 
<a href="javascript:map.centerAndZoom(new GPoint(9.62,46.36),9);">Alps</a>
</p>
<div id="map" style="width: 1050px; height: 650px; border: 3px double gray;"></div>
<h5>Legend:</h5>
<table width=1050>
<tr>
<td><img src="marker_dg.png"> National and State Parks<br>
<td><img src="marker_y+dg.png"> National and State Parks with a picture available<br>
<tr>
<td><img src="marker_c.png"> Artistic and historical cities<br>
<td><img src="marker_y+c.png"> Artistic and historical cities with a picture available<br>
<tr>
<td><img src="marker_w.png"> Ski resorts<br>
<td><img src="marker_y+w.png"> Ski resorts with a picture available<br>
<tr>
<td><img src="marker_b.png"> Sea or ocean resorts<br>
<td><img src="marker_y+b.png"> Sea or ocean resorts with a picture available<br>
<tr>
<td><img src="marker.png"> Other places that I have visited<br>
<td><img src="marker_y+r.png"> Other places with a picture available
</table>
<p><center>
Copyright &copy; 1999-2005, Giordano Biondani
</center></p>
</font>
</body>
</html>
Copyright (c) 2005-2006 Giordano Biondani