google earth, google maps and your photos: a tutorial earth and... · this article is available in...
TRANSCRIPT
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
About Packt
Our books and publications share the experiences of your fellow IT professionals in
adapting and customizing today's systems, applications, and frameworks.
Packt is a modern, unique publishing company with a focus on producing cutting-edge
books for communities of developers, administrators, and newbies alike.
For more information, visit: www.PacktPub.com.
About The Author
Rob Reed has over 10 years experience in the IT industry. He has held positions as the
Director of Technology, IT Director, and Research and Development Technical Lead for
various firms. Currently, he is an independent consultant and is pursuing a graduate
degree in Computer Science at Tufts University (Medford, MA). His thesis work looks at
issues of semantic information management. He is also interested in the topics of
computing platforms, network and systems security, programming languages, and
development. He maintains a weblog at http://robreed.net/weblog. He can be reached at
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Google Earth, Google Maps and Your Photos: a Tutorial
Introduction
A scholar who never travels but stays at home is not worthy to be accounted a
scholar. From my youth on I had the ambition to travel, but could not afford to
wander over the three hundred counties of Korea, much less the whole world.
So, carrying out an ancient practise, I drew a geographical atlas. And while
gazing at it for long stretches at a time I feel as though I was carrying out my
ambition . . . Morning and evening while bending over my small study table, I
meditate on it and play with it and there in one vast panorama are the districts,
the prefectures and the four seas, and endless stretches of thousands of miles.
WON HAK-SAENG
Korean Student
Preface to his untitled manuscript atlas of China during the Ming Dynasty,
dated 1721.1
To say that maps are important is an understatement almost as big as the world itself.
Maps quite literally connect us to the world in which we all live, and by extension, they
link us to one another. The oldest preserved maps date back nearly 4500 years. In
addition to connecting us to our past, they chart much of human progress and expose the
relationships among people through time.
Unfortunately, as a work of humankind, maps share many of the same shortcomings of
all human endeavors. They are to some degree inaccurate and they reflect the bias of the
map maker. Advancements in technology help to address the former issue, and offer us
the opportunity to resist the latter. To the extent that it's possible for all of us to
participate in the map making, the bias of a select few becomes less meaningful.
Google Earth2 and Google Maps
3 are two applications that allow each of us to assert our
own place in the world and contribute our own unique perspective. I can think of no
better way to accomplish this than by combining maps and photography.
1 Source: Library of Congress Geography and Maps: An Illustrated Guide
2 Google Earth: http://earth.google.com/
3 Google Maps: http://maps.google.com/
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Photos reveal much about who we are, the places we have been, the people with whom
we have shared those experiences, and the significant events in our lives. Pinning our
photos to a map allows us to see them in their proper geographic context, a valuable way
to explore and share them with friends and family. Photos can reveal the true character of
a place, and afford others the opportunity to experience these destinations, perhaps
faraway and unreachable for some of us, from the perspective of someone who has
actually been there.
In this tutorial I'll show you how to 'pin' your photos using Google Earth and Google
Maps. Both applications are free and available for Windows, Mac OS X, and Linux. In
the case of Google Earth there are requirements associated with installing and running
what is a local application. Google Maps has its own requirements: primary among them
a compatible web browser (the highly regarded FireFox is recommended).
In Google Earth, your photos show up on the map within the application complete with
titles, descriptions, and other relevant information. You can choose to share your photos
with everyone, only people you know, or even reserve them strictly for yourself.
Google Maps offers the flexibility to present maps outside of a traditional application.
For example you can embed a map on a webpage pinpointing the location of one
particular photo, or mapping a collection of photos to present along with a photo gallery,
or even collecting all of your digital photos together on one dynamic map.
Over the course of a short couple of articles we'll cover everything you need to take
advantage of both applications. I've put together two scripts to help us accomplish that
goal. The first is a Perl script that works through your photos and generates a file in the
proper format with all of the data necessary to include those photos in Google Earth. The
second is a short bit of Javascript that works with the first file and builds a dynamic
Google Map of those same photos. Both scripts are available for you to download, after
which you are free to use them as is, or modify them to suit your own projects. I've
purposefully kept the code as simple as possible to make them accessible to the widest
audience, even those of you reading this who may be new to programming or unfamiliar
with Perl, Javascript or both. I've taken care to comment the code generously so that
everything is plainly obvious. I'm hopeful that you will be surprised at just how simple it
is.
There a couple of preliminary topics to examine briefly before we go any further.
In the preceding paragraph I mentioned that the result of the first of our two scripts is a
'file in the proper format...'. This file, or more to the point the file format, is a very
important part of the project. KML (Keyhole Markup Language) is a fairly simple XML-
based format that can be considered the native "language" of Google Earth. That
description begs the question, 'What is XML?'
To oversimplify, because even a cursory discussion of XML is outside of the scope of
this article, XML (Extensible Markup Language) is an open data format (in contrast to
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
proprietary formats) which allows us to present information in such way that we
communicate not only the data itself, but also descriptive information about the data and
the relationships among elements of the data. One of the technical terms that applies is
'metalanguage', which approximately translates to mean a language that makes it possible
to describe other languages. If you're unfamiliar with the concept, it may be difficult to
grasp at first or it may not seem impressive. However, metalanguages, and specifically
XML, are an important innovation (I don't mean to suggest that it's a new concept. In fact
XML has roots that are quite old, relative to the brief history of computing). These
metalanguages make it possible for us to imbue data with meaning such that software can
make use of that data. Let's look at an example taken from the Wikipedia entry for KML4.
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Placemark>
<description>New York City</description>
<name>New York City</name>
<Point>
<coordinates>-74.006393,40.714172,0</coordinates>
</Point>
</Placemark>
</kml>
Ignore all of the pro forma stuff before and after the <Placemark> tags and you might be
able to guess what this bit of data represents. More importantly, a computer can be made
to understand what it represents in some sense. Without the tags and structure, "New
York City" is just a string, i.e. a sequence of characters. Considering the tags we can see
that we're dealing with a place, (a Placemark), and that "New York City" is the name of
this place (and in this example also its description). With all of this formal structure,
programs can be made to roughly understand the concept of a Placemark, which is a
useful thing for a mapping application.
Let's think about this for a moment. There are a very large number of recognizable places
on the planet, and a provably infinite number of strings. Given a block of text, how could
a computer be made to identify a place from, for example the scientific name of a
particular flower, or a person's name? It would be extremely difficult.
We could try to create a database of every recognizable place and have the program
check the database every time it encounters a string. That assumes it's possible to agree
on a 'complete list of every place', which is almost certainly untrue. Keep in mind that we
could be talking about informal places that are significant only to a small number of
people or even a single person, e.g. 'the park where, as a child, I first learned to fly a kite'.
It would be a very long list if we were going to include these sorts of places, and
incredibly time-consuming to search.
4 Wikipedia entry for KML: http://en.wikipedia.org/wiki/KML
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Relying on the structure of the fragment above, we can easily write a program that can
identify 'New York City' as the name of a place, or for that matter 'The park where I first
learned to fly a kite'. In fact, I could write a program that pulls all of the place names
from a file like this, along with a description, and a pair of coordinate points for each, and
includes them on a map. That's exactly what we're going to do. KML makes it possible.
If I haven't made it clear, the structural bits of the file must be standardized. KML
supports a limited set of elements (e.g. 'Placemark' is a supported element, as are 'Point'
and 'coordinates'), and all of the elements used in a file must adhere to the standard for it
to be considered valid.
The second point we need to address before we begin is, appropriately enough... where to
begin? Lewis Carroll famously tells us to "Begin at the beginning and go on till you come
to the end: then stop."5 Of course, Mr. Carroll
6 was writing a book at the time. If "Alice's
Adventures in Wonderland" were an article, he might have had different advice. From the
beginning to the end there is a lot of ground to cover. We're going to start somewhere
further along, and make up the difference with the following assumptions. For the
purposes of this discussion, I am going to assume that you have:
1. Perl7;
2. Access to Phil Harvey's excellent ExifTool8, a Perl library and command-
line application for reading, writing, and editing metadata in images (among
other file types). We will be using this library in our first script
3. A publicly accessible web server. Google requires the use of an API key9 by
which it can monitor the use of its map services. Google must be able to
validate your key, and so your site must be publicly available. Note that this
a requirement for Google Maps only
4. Photos, preferably in a photo management application. Essentially, all you
need is an app capable of generating both thumbnails and reduced size
copies of your original photos. An app that can export a nice gallery for use
on the web is even better
5. Coordinate data as part of the EXIF metadata10
embedded in your photos. If
that sounds unfamiliar to you, then most likely you will have to take some
5 Alice's Adventures in Wonderland
6 Lewis Carroll is a pen name of Charles Lutwidge Dodgson an English who lived during
the mid to late nineteenth century. 7 Perl: http://www.perl.org/
8 ExifTool: http://www.sno.phy.queensu.ca/~phil/exiftool/
9 Google Maps API Sign Up page: http://www.google.com/apis/maps/signup.html
10 EXIF metadata information at the ExifTool site:
http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html See also:
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
additional steps before you can make use of this tutorial. I'm not aware of
any digital cameras that automatically include this information at the time
the photo is created. There are devices that can be used in combination with
digital cameras, and there are a number of ways that you can 'tag' your
photos with geographic data much the same way you would add keywords
and other annotations.
Let's begin!
GPS tags: http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/GPS.html Wikipedia entry: http://en.wikipedia.org/wiki/Exif specifications at exif.org: http://www.exif.org/specifications.html
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Part 1: Google Earth
Section 1: Introduction to Part 1 Time to begin the project in earnest. As I've already mentioned we'll spend the first half
of this tutorial looking at Google Earth and putting together a Perl script that, given a
collection of geotagged photos, will build a set of KML files so we can browse our
photos in Google Earth. These same files will serve as the data source for our Google
Maps application later on.
Section 2: Some Advice Before We Begin Take your time to make sure you understand each topic before you move on to the next.
Think of this as the first step in debugging your completed code. If you go slowly enough
to be able to identify aspects of the project that you don't quite understand, then you'll
have some idea where to start looking for problems should things not go as expected.
Furthermore, going slowly will give you the opportunity to identify those parts that you
may want to modify to better fit the script to your own needs.
If this is new to you, follow along as faithfully as possible with what I do here the first
time through. Feel free to make notes for yourself as you go, but making changes on the
first pass may make it difficult for you to catch back on to the narrative and piece
together a functional script. After you have a working solution, it will be a simple matter
to implement changes one at a time until you have something that works for you.
Following this approach it will be easy to identify the silly mistakes that tend to creep in
once you start making changes.
There is also the issue of trust. This is probably the first time we're meeting each other, in
which case you should have some doubt that my code works properly to begin with. If
you minimize the number of changes you make, you can confirm that this works for you
before blaming yourself or your changes for my mistakes. I will tell you up front that I'm
building this project myself as we go. You can be certain at least that it functions as
described for me as of the date attached to the article. I realize that this is quite different
from being certain that the project will work for you, but at least it's something.
The entirety of my project is available for you to download. You are free to use all of it
for any legal purpose whatsoever, including my photos in addition to all of the code,
icons, etc. This is so you have some samples to use before you involve your own content.
I don't promise that they are the most beautiful images you have ever seen, but they are
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
all decent photos and properly annotated with the necessary metadata, including
geographic tags.
Section 3: Photos, Metadata and ExifTool To begin, we must have a clear understanding of what the Perl script will require from us.
Essentially, we need to provide it with a selection of annotated image files, and
information about how to reference those files.
A simple folder of files is sufficient, and will be convenient for us, both as the
programmer and end user. The script will be capable of negotiating nested folders, and if
a directory contains both images and other file types, non-image types will be ignored.
Typically, after a day of taking photos I'll have 100 to 200 that I want to keep. I delete the
rest immediately after offloading them from the camera. For the files that are left, I
preserve the original grouping, keeping all of the files together in a single folder. I place
this folder of images in an appropriate location according to a scheme that serves to keep
my complete collection of photos neatly organized. These are my digital 'negatives'. I
handle all subsequent organization, editing, enhancements, and annotations within my
photo management application. I use Apple Inc.'s Aperture11
but there are many others
that do the job equally well.
Annotating your photos is well worth the investment of time and effort, but it's important
that you have some strategy in mind so that you don't create meaningless tags that are
difficult to use to your advantage. For the purposes of this project the tags we'll need are
quite limited, which means that going forward we will be able to continue adding photos
to our maps with a reasonable amount of work.
The annotations we need are:
Caption
Latitude
Longitude
Image Date *
Location/Sub-Location
City
Province/State
Country Name
Event
People
ImageWidth *
ImageHeight *
* Values for these Exif tags are generated by your camera.
11
Aperture: http://www.apple.com/aperture/
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Note that these are labels used in Aperture, and are not necessarily consistent from one
application to the next. Some of them are more likely than others to be used reliably.
'City' for example should be dependable, while the labels 'People', 'Events', and
'Location', among others, are more likely to differ. One explanation for these variations is
that the meaning of these fields are more open to interpretation. Location, for example, is
likely to be used to narrow down the area where the photo was taken within a particular
city, but it is left to the person who is annotating the photo to decide that the field should
name a specific street address, an informal place (e.g. 'home' or 'school'), or a larger area,
for example a district or neighborhood. Fortunately things aren't so arbitrary as they
seem.
Each of these fields corresponds to a specific tag name that adheres to one of the common
metadata formats (Exif12
, IPTC13
, XMP14
, and there are others). These tag names are
consistent as required by the standards. The trick is in determining the labels used in your
application that correspond to the well-defined tag names. Our script relies on these
metadata tags, so it is important that you know which fields to use in your application.
This gives us an excuse to get acquainted with ExifTool15
. From the project's website, we
have this description of the application:
ExifTool is a platform-independent Perl library plus a command-line application for
reading, writing, and editing meta information in image, audio and video files...
ExifTool can seem a little intimidating at first. Just keep in mind that we will need to
understand just a small part of it for this project, and then be happy that such a useful and
flexible tool is freely available for you to use.
The brief description above states in part that ExifTool is a Perl library and command line
application that we can use to extract metadata from image files.
With a single short command, we can have the app print all of the metadata contained in
one of our image files. First, make sure ExifTool is installed. You can test for this by
typing the name of the application at the command line.
$ exiftool
12
Exif: (E)(x)changeable (i)mage (f)ile format. EXIF.org, http://exif.org/ is an unofficial site that at least links to the specifications. See the appendix for more information about the Exif standard. 13
(I)nternational (P)ress (T)elecommunications (C)ouncil. See the IPTC entry at Wikipedia for more information: http://en.wikipedia.org/wiki/IPTC 14
XMP home at adobe.com: http://www.adobe.com/products/xmp/index.html 15
The ExifTool homepage at http://www.sno.phy.queensu.ca/~phil/exiftool/ is the best reference for the project. Other than a tutorial like this one, you shouldn't need another resource.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
If it is installed, then running it with no options should prompt the tool to print its
documentation. If this works, there will be more than one screen of text. You can page
through it by pressing the spacebar. Press the 'q' key at any time to stop.
If the tool is not installed, you will need to add it before continuing. See the appendix at
the end of this tutorial for more information.
Having confirmed that ExifTool is installed, typing the following command will result in
a listing of the metadata for the named image:
$ exiftool -f -s -g2 /path/image.jpg
Where 'path' is an absolute path to image.jpg or a relative path from the current directory,
and 'image.jpg' is the name of one of your tagged image files.
We'll have more to say about ExifTool later, but because I believe that no tutorial should
ask the reader to blindly enter commands as if they were magic incantations, I'll briefly
describe each of the options used in the command above:
-f, forces printing of tags even if their values are not found. This gives us a better idea
about all of the available tag names, whether or not there are currently defined values for
those tags.
-s, prints tag names instead of descriptions. This is important for our purposes. We need
to know the tag names so that we can request them in our Perl code. Descriptions, which
are expanded, more human-readable forms of the same names obscure details we need.
For example, compare the tag name 'GPSLatitude' to the description 'GPS Latitude'. We
can use the tag name, but not the description to extract the latitude value from our files.
-g2, organizes output by category. All location specific information is grouped together,
as is all information related to the camera, date and time tags, etc. You may feel, as I do,
that this grouping makes it easier to examine the output. Also, this organization is more
likely to reflect the grouping of field names used by your photo management application.
If you prefer to save the output to a file, you can add ExifTool's -w option with a file
extension.
$ exiftool -f -s -g2 -w txt path/image.jpg
This command will produce the same result but write the output to the file 'image.txt' in
the current directory; again, where 'image.jpg' is the name of the image file. The -w
option appends the named extension to the image file's basename, creates a new file with
that name, and sets the new file as the destination for output.
The tag names that correspond to the list of Aperture fields presented above are:
metadata tag name Aperture field label
Caption-Abstract Caption
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
metadata tag name Aperture field label
GPSLatitude Latitude
GPSLongitude Longitude
DateTimeOriginal Image Date
Sub-location Location/Sub-Location
City City
Province-State Province/State
Country-PrimaryLocationName Country Name
FixtureIdentifier Event
Contact People
ImageWidth Pixel Width
ImageHeight Pixel Height
Section 4: Making Photos Available to Google Earth We will use some of the metadata tags from our image files to locate our photos on the
map (e.g. GPSLatitude, GPSLongitude), and others to describe the photos. For example,
we will include the value of the People tag in the information window that accompanies
each marker to identify friends and family who appear in the associated photo.
Because we want to display and link to photos on the map, not just indicate their position,
we need to include references to the location of our image files on a publicly accessible
web server. You have some choice about how to do this, but for the implementation
described here we will (1) Display a thumbnail in the info window of each map marker
and (2) include a link to the details page for the image in a gallery created in our photo
management app.
When a visitor clicks on a map marker they will see a thumbnail photo along with other
brief descriptive information. Clicking a link included as part of the description will open
the viewer's web browser to a page displaying a large size image and additional details.
Furthermore, because the page is part of a gallery, viewers can jump to an index page and
step forward and back through the complete collection. This is a complementary way to
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
browse our photos. Taking this one step further, we could add a comments section to the
gallery pages or replace the gallery altogether, instead choosing to display each photo as
a weblog post for example.
The structure of the gallery created from my photo app is as follows...
/ (the root of the gallery directory)
index.html
large-1.html
large-2.html
large-3.html
...
large-n.html
assets/
css/
img/
catalog/
pictures/
picture-1.jpg
picture-2.jpg
picture-3.jpg
...
picture-n.jpg
thumbnails/
thumb-1.jpg
thumb-2.jpg
thumb-3.jpg
...
thumb-n.jpg
The application creates a root directory containing the complete gallery. Assuming we do
not want to make any manual changes to the finished site, publishing is as easy as
copying the entire directory to a location within the web server's document root.
assets/: Is a subfolder containing files related to the theme itself. We don't need to
concern ourselves with this sub-directory.
catalog/: Contains a single catalog.plist file which is specific to Aperture and not relevant
to this discussion.
pictures/: Contains the large size images included on the detail gallery pages.
thumbnails/: This subfolder contains the thumbnail images corresponding to the large
size images in pictures/.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Finally, there are a number of files at the root of the gallery. These include index pages
and files named 'large-n.html', where n is a number starting at 1 and increasing
sequentially e.g. large-1.html, large-2.html, large-3.html, ... .
The index files are the index pages of our gallery. The number of index pages generated
will be dictated by the number of image files in the gallery, as well as the gallery's layout
and design. index.html is always the first gallery page.
The large-n.html files are the details pages of our gallery. Each page features an
individual photo with links to the previous and next photos in sequence and a link back to
the index. You can see the gallery I have created for this tutorial here:
http://robreed.net/photos/tutorial_gallery/
If you take the time to look through the gallery, maybe you can appreciate the value of
viewing these photos on a map. Web-based photo galleries like this one are nice enough,
but the photos are more interesting when viewed in some meaningful context.
There are a couple of things to notice about this gallery.
Firstly, picture-1.jpg, thumb-1.jpg, and large-1.html all refer to the same image. So if we
pick one of the three files we can easily predict the names of the other two. This
relationship will be useful when it comes to writing our script.
There is another important issue I need to call to your attention because it will not be
apparent from looking only at the gallery structure. Aperture has renamed all of my
photos in the process of exporting them.
The name of the original file from which picture-1.jpg was generated (as well as large-
1.html and thumb-1.jpg) is 'IMG_0277.JPG', which is the filename produced by my
camera. Because I want to link to these gallery files, not my original photos which will
stay safely tucked away on a local drive, I must run the script against the photos in the
gallery. I cannot run it against the original image files because the filenames referenced
in the output are unrelated to the files in the gallery.
If my photo management app provided me the option of preserving the original filenames
for the corresponding photos in the gallery, then I could run the script against the original
image files or the gallery photos because all of the filenames would be consistent, but this
is not the case. I don't have a problem as long as I run the script on the exported photos.
However, if I'm running the script against the photos in the web gallery, either the
pictures or thumbnail images must contain the same metadata as the original image files.
Aperture preserves the metadata in both. Your application may not.
A simple, dependable way to confirm that the metadata is present in the gallery files is to
run ExifTool first against the original file and then the same photo in the pictures/ and
thumbnails/ directories in the gallery. If ExifTool reports identical metadata, then you
will have no trouble using one of pictures/ or thumbnails/ as your source directory. If the
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
metadata is not present or not complete in the gallery files, you may need to use the script
on your original image files. As has already been explained, this isn't a problem unless
the gallery produces filenames that are inconsistent with the original filenames, as
Aperture does. In this case you have a problem. You won't be able to run the script on the
original image files because of the naming issue or on the gallery photos because they
don't contain metadata.
Make sure that you understand this point.
If you find yourself in this situation, then your best bet is to generate files to use with
your maps from your original photos in some other way, bypassing your photo
management app's web gallery features altogether in favor of a solution that preserves the
filenames, the metadata, or both. There is another option which involves setting up a
relationship between the names of the original files and the gallery filenames. This
tutorial does not include details about how to set up this association.
Finally, keep in mind that though we've looked at the structure of a gallery generated by
Aperture, virtually all photo management apps produce galleries with a similar structure.
Regardless of the application used, you should find:
A group of html files including index and details pages
A folder of large size image files
A folder of thumbnails
Once you have identified the structure used by your application, as we have done here, it
will be a simple task to translate these instructions.
Section 5: Referencing Files Over the Internet Now we can talk about how to reference these files and gallery pages so that we can
create a script to generate a KML file that includes these references.
When we identify a file over the internet, it is not enough to use the filename, e.g.
'thumb-1.jpg', or even the absolute and relative path to the file on the local computer. In
fact these paths are most likely not valid as far as your web server is concerned. Instead
we need to know how to reference our files such that they can be accessed over the global
internet, and the web more specifically. In other words, we need to be able to generate a
URL (Uniform Resource Locator) which unambiguously describes the location of our
files. The formal details of exactly what comprises a URL16
are more complicated than
may be obvious at first, but most of us are familiar with the typical URL, like this one:
http://www.ietf.org/rfc/rfc1630.txt
16
RFC 1630: http://www.ietf.org/rfc/rfc1630.txt
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
which describes the location of a document titled "Universal Resource Identifiers in
WWW" that just so happens to define the formal details of what comprises a URL.
http://www.ietf.org
This portion of the address is enough to describe the location of a particular web server
over the public internet. In fact it does a little more than just specify the location of a
machine. The http:// portion is called the scheme and it identifies a particular protocol
(i.e. a set of rules governing communication) and a related application, namely the web.
What I just said isn't quite correct; at one time, HTTP was used exclusively by the web,
but that's no longer true. Many internet-based applications use the protocol because the
popularity of the web ensures that data sent via HTTP isn't blocked or otherwise
disrupted. You may not be accustomed to thinking of it as such, but the web itself is a
highly-distributed, network-based application.
/rfc/
This portion of the address specifies a directory on the server. It is equivalent to an
absolute path on your local computer. The leading forward slash is the root of the web
server's public document directory. Assuming no trickiness on the part of the server, all
content lives under the document root.
This tells us that rfc/ is a sub-directory contained within the document root. Though this
directory happens to be located immediately under the root, this certainly need not be the
case. In fact these paths can get quite long.
We have now discussed all of the URL except for:
rfc1630.txt
which is the name of a specific file. The filename is no different than the filenames on
your local computer. Let's manually construct a path to one of the large-n.html pages of
the gallery we have created.
The address of my server is robreed.net, so I know that the beginning of my URL will be:
http://robreed.net
I keep all of my galleries together within a photos/ directory, which is contained in the
document root.
http://robreed.net/photos/
Within photos/, each gallery is given its own folder. The name of the folder I have
created for this tutorial is 'tutorial_gallery'. Putting this all together, the following URL
brings me to the root of my photo gallery:
http://robreed.net/photos/tutorial_gallery/
We've already gone over the directory structure of the gallery, so it should make sense
you to that when referring to the 'large-1.html' detail page, the complete URL will be:
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
http://robreed.net/photos/tutorial_gallery/large-1.html
the URL of the image that corresponds to that detail page is:
http://robreed.net/photos/tutorial_gallery/pictures/picture-1.jpg
and the thumbnail can be found at:
http://robreed.net/photos/tutorial_gallery/thumbnails/thumb-1.jpg
Notice that the address of the gallery is shared among all of these resources. Also, notice
that resources of each type (e.g. the large images, thumbnails, and html pages) share a
more specific address with files of that same type.
If we use the term 'base address' to refer to the shared portions of these URLs, then we
can talk about several significant base addresses:
The gallery base address: http://robreed.net/photos/tutorial_gallery/
The html pages base address: http://robreed.net/photos/tutorial_gallery/
The images base address: http://robreed.net/photos/tutorial_gallery/pictures/
The thumbnails base address: http://robreed.net/photos/tutorial_gallery/thumbnails/
Note that given the structure of this particular gallery, the html pages base address and
the gallery base address are identical. This need not be the case, and may not be for the
gallery produced by your application.
We can hard-code the base addresses into our script. For each photo, we need only
append the associated filename to construct valid URLs to any of these resources. As the
script runs, it will have access to the name of the file that it is currently evaluating, and so
it will be a simple matter to generate the references we need as we go.
At this point we have discussed almost everything we need to put together our script. We
have:
created a gallery at our server, which includes our photos with metadata in
tow
identified all of the metadata tags we need to extract from our photos with
the script and the corresponding field names in our photo management
application
determined all of the base addresses we need to generate references to our
image files
Section 6: KML The last thing we need to understand is the format of the KML files we want to produce.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
We've already looked at a fragment of KML. The full details can be found on Google's
KML documentation pages17
, which include samples, tutorials and a complete reference
for the format.
A quick look at the reference is enough to see that the language includes many elements
and attributes, the majority of which we will not be including in our files. That statement
correctly implies it is not necessary for every KML file to include all elements and
attributes. The converse however is not true, which is to say that every element and
attribute contained in any KML file must be a part of the standard.
A small subset of KML will get us most, if not all, of what you will typically see in
Google Earth from other applications.
Many of the features we will not be using deal with aspects of the language that are
either:
1. Not relevant to this project, e.g. ground overlays (GroundOverlay) which
"draw an image overlay draped onto the terrain"
2. Minute details for which the default values are sensible
There is no need to feel shortchanged because we are covering only a subset of the
language. With the basic structure in place and a solid understanding of how to script the
generation of KML, you will be able to extend the project to include any of the other
components of the language as you see fit.
The structure of our KML file is as follows:
1. <?xml version="1.0" encoding="UTF-8"?>
2. <kml xmlns="http://earth.google.com/kml/2.1">
3. <Document>
4. <Folder>
5. <name>$folder_name</name>
6. <description>$folder_description</description>
7. <Placemark>
8. <name>$placemark_name</name>
9. <Snippet maxLines="1">
10. $placemark_snippet
11. </Snippet>
12. <description><![CDATA[
13. $placemark_description
14. ]]></description>
15. <Point>
17
KML documentation at google.com: http://code.google.com/apis/kml/documentation/
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
16. <coordinates>$longitude,$latitude</coordinates>
17. </Point>
18. </Placemark>
19. </Folder>
20. </Document>
21. </kml>
Line 1: XML header
Every valid KML file must start with this line and nothing else is allowed to appear
before it. As I've already mentioned, KML is an XML-based language and XML requires
this header.
Line 2: Namespace declaration
More specifically this is the KML namespace declaration, and it is another formality. The
value of the xmlns attribute must be a URI referencing a resource that identifies elements
and attributes which are valid under the language. Remember that KML is one of many
XML based languages, each with its own vocabulary. Making namespaces unique to each
language avoids the obvious problems that would occur if all languages were required to
pull from a common pool of identifiers. In such a scheme all identifiers would need to be
unique among all XML based languages—a situation which would quickly prove
unworkable.
The first two lines are strictly boilerplate. They are required and will be identical in every
KML file you produce. They change only when the language itself is modified.
Line 3: <Document> is a container element representing the KML file itself. If we do
not explicitly name the document by including a name element then Google Earth will
use the name of the KML file as the Document element <name>.
The Document container will appear on the Google Earth 'Sidebar' within the 'Places'
panel. Optionally we can control whether the container is closed or open by default. (This
setting can be toggled in Google Earth using a typical disclosure triangle.) There are
many other elements and attributes that can be applied to the Document element. Refer to
the KML Reference for the full details.
Line 4: <Folder> is another container element. The files we produce will include a
single <Folder> containing all of our Placemarks, where each Placemark represents a
single image. We could create multiple Folder elements to group our Placemarks
according to some significant criteria. Think of the Folder element as being similar to
your operating system's concept of a folder.
At this point, note the structure of the fragment. The majority of it is contained within the
Folder element. Folder, in turn, is an element of Document which is itself within the
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
<kml> container. It should make sense that everything in the file that is considered part
of the language must be contained within the kml element.
From the KML reference
A Folder is used to arrange other Features hierarchically (Folders, Placemarks,
NetworkLinks, or Overlays). A Feature is visible only if it and all its ancestors are
visible.
Line 5: The name element identifies an object, in this case the Folder object. The text
that appears between the name tags can be any plain text that will serve as an appropriate
label.
Line 6: <description> is any text that seems to adequately describe the object.
From the KML reference:
User-supplied text that appears in the description balloon when the user clicks
on either the feature name in the Places panel or the Placemark icon in the 3D
viewer. This text also appears beneath the feature name in the Places panel if no
<Snippet> tag is specified for the feature.
The description element supports both plain text and a subset of HTML. We'll
consider issues related to using HTML in <description> at the discussion of
Placemark, lines 12 - 14.
Lines 7 - 17 define a <Placemark> element.
Note that Placemark contains a number of elements that also appear in Folder, including
<name> (line 8), and <description> (lines 12 - 14). These elements serve the same
purpose for Placemark as they do for the Folder element, but of course they refer to a
different object.
I've said that <description> can include a subset of HTML in addition to plain text. Under
XML, some characters have special meaning. You may need to use these characters as
part of the HTML included in your descriptions. Angle brackets (<, >) for example
surround tag names in HTML, but serve a similar purpose in XML. When they are used
strictly as part of the content, we want the XML parser to ignore these characters.
We can accomplish this a few different ways:
We can use entity references, either numeric character references or character entity
references, to indicate that the symbol appears as part of the data and should not be
treated as part of the syntax of the language. The character '<', which is required to
include an image as part of the description (something we will be doing), (e.g. <img
src=... />) can safely be included as the character entity reference '<' or the numeric
character reference '<'.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
The character entity references may be easier to remember and recognize on sight but are
limited to the small subset of characters for which they have been defined. The numeric
references on the other hand can specify any ASCII character. Of the two types, numeric
character references should be preferred. There are also Unicode entity references which
can specify any character at all.
In the simple case of embedding short bits of HTML in KML descriptions, we can avoid
the complication of these references altogether by enclosing the entire description in a
CDATA18
element, which instructs the XML parser to ignore any special characters that
appear until the end of the block set off by the CDATA tags.
Notice the string '<![CDATA[' immediately after the opening <description> tag within
<Placemark>, and the string ]]> immediately before the closing </description> tag. If we
simply place all of our HTML and plain text between those two strings, it will all be
ignored by the parser and we are not required to deal with special characters individually.
This is how we'll handle the issue.
Lines 9 - 11: <Snippet>
The KML reference does a good job of clearly describing this element.
From the KML reference:
In Google Earth, this description is displayed in the Places panel under the
name of the feature. If a Snippet is not supplied, the first two lines of the
<description> are used. In Google Earth, if a Placemark contains both a
description and a Snippet, the <Snippet> appears beneath the Placemark in the
Places panel, and the <description> appears in the Placemark's description
balloon. This tag does not support HTML markup. <Snippet> has a maxLines
attribute, an integer that specifies the maximum number of lines to display.
Default for maxLines is 2.
Notice that in the block above at line 9, I have included a 'maxLines' attribute with a
value of 1. Of course, you are free to substitute your own value for maxLines, or you can
omit the attribute entirely to use the default value.
The only element we have yet to review is <Point>, and again we need only look to the
official reference for a nice description.
From the KML reference:
A geographic location defined by longitude, latitude, and (optional) altitude.
When a Point is contained by a Placemark, the point itself determines the
position of the Placemark's name and icon.
18
The name CDATA is formed from the phrase 'Character DATA'
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
<Point> in turn contains the element <coordinates> which is required.
From the KML reference:
A single tuple consisting of floating point values for longitude, latitude, and
altitude (in that order).
The reference also informs us that altitude is optional, and in fact we will not be
generating altitude values.
Finally the reference warns:
Do not include spaces between the three values that describe a coordinate.
This seems like an easy mistake to make. We'll need to be careful to avoid it.
There will be a number of <Placemark> elements, one for each of our images.
The question is how to handle these elements. The answer is that we'll treat KML as a 'fill
in the blanks' style template. All of the structural and syntactic bits will be hard-coded,
e.g. the XML header, namespace declaration, all of the element and attribute labels, and
even the whitespace, which is not strictly required but will make it much easier for us to
inspect the resulting files in a text editor. These components will form our template.
The blanks are all of the text and html values of the various elements and attributes. We
will use variables as place-holders everywhere we need dynamic data, i.e. values that
change from one file to the next or one execution of the script to the next.
Take a look at the strings I've used in the block above. $folder_name,
$folder_description, $placemark_name, etc. For those of you unfamiliar with Perl, these
are all valid variable names chosen to indicate where the variables slot into the structure.
These are the same names used in the source file distributed with the tutorial.
Section 7: Introduction to the Code At this point, having discussed every aspect of the project, we can succinctly describe
how to write the code. We'll do this in 3 stages of increasing granularity.
Firstly, we'll finish this tutorial with a natural language walk-through of the execution of
the script.
Secondly, if you look at the source file included with the project, you will notice
immediately that comments dominate the code. Because instruction is as important an
objective as the actual operation of the script, I use comments in the source to provide a
running narration. For those of you who find this superabundant level of commenting a
distraction, I'm distributing a second copy of the source file with much of the comments
removed.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Finally, there is the code itself. After all, source code is nothing more than a rigorously
formal set of instructions that describe how to complete a task. Most programs, including
this one, are a matter of transforming input in one form to output in another. In this very
general sense, programming is similar to cooking, farming, manufacturing, or any
number of other pursuits. To take this idea a little further, you could think of gardening as
a sort of abstract form of organic object oriented programming.
After reading through the following high level description you'll want to move on to the
source file.
Section 8: Natural language walk-through 1. We need to prime the script by hard-coding some variable assignments.
These 'configurable variables' serve the same purpose as the preferences,
menus and dialog boxes typical of GUI applications.
Among other values we'll specify:
The names of the KML output files
The directory where the script should look for our photos
and our Google Maps API key
Important: If you haven't yet, now is a perfect time to sign up for a key19
.
Before running the script, open the source file and look for the 'configurable
variables' section of the code. Read through the comments describing each
required value, make whatever necessary changes, and save the file.
2. We need to create our KML output files.
If there is a problem which prevents the script from writing these files, we
can determine that at the beginning of execution before doing any other
work.
3. The script starts reading from the 'fill in the blanks' template included in the
data section of the source file, which is read via the __DATA__ pseudo-
filehandle. (See the comments in the source for more information.)
The template looks like this:
__DATA__
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.1">
<Document>
<Style id="tutorial_custom_icon">
<IconStyle>
19
Google Maps API Sign Up: http://www.google.com/apis/maps/signup.html
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
<scale>1.0</scale>
<Icon>
<href>http://!custom_icon_url_goes_here!</href>
</Icon>
</IconStyle>
</Style>
<Folder>
<name>!folder_name_goes_here!</name>
<description>
!folder_description_goes_here!
</description>
!placemarks_go_here!
</Folder>
</Document>
</kml>
All of the literal text in the template is written directly to the output files.
The term 'literal text' applies to those parts of our template written directly
into the source code, or in other words that are not part of the metadata
extracted from the image files or computed values.
Notice that there are a number of placeholder strings in the template:
!custom_icon_url_goes_here!
!folder_name_goes_here!
!folder_description_goes_here!
!placemarks_go_here!
Because these placeholders are all unique strings in the template we can
attempt to match against of them as we read each line and, wherever a
match succeeds, substitute the current value of the appropriate variable for
the placeholder. Note that some of these are from the configurable variables
section of the file while others are values set dynamically during execution.
We could simply include the values from the configurable variables section
in the template rather than assigning these values to variables, and then
substituting the values for placeholders as described.
Handling it the way it has been presented here allows us to group all of the
values we must set manually together in one small section at the top. This is
considered to be preferable to scattering these values throughout the source
because it makes it easier to configure the script and maintain the code. For
example, it minimizes the chance that we'll break something by making an
inadvertent change when we only intended to update one of these values.
There are a number of other benefits as well, including these commonly
noted advantages:
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
These values are essentially options or directives we use to modify
the behavior of the script. Grouping them together makes it more
efficient to use our little command line executable, just as well
organized menus make it easier to work with a GUI-based app.
Grouping these values together makes it easier to examine them.
Because the values are defined once and stored in variables, we can
repeatedly use the same values at more than one point in the code
without retyping them. Reusing values whenever possible, rather
than recreating them, significantly decreases the likelihood of a typo
or some other careless mistake breaking the execution of the
program or ruining our output.
Defining values only once avoids a common problem where two or
more independent values that are intended to be identical get out of
sync when the value is not updated everywhere it is used.
4. When we encounter the Placemarks section of the KML template (i.e. the
string !placemarks_go_here!) we need to append one Placemark element for
each of our image files.
The Perl module File::Find, which is part of the standard distribution,
defines a number of functions for traversing a filesystem hierarchy starting
at a specified root. One of these functions, find(), does a depth-first search
of the directory tree, running a routine we provide it against every item
found, where an item is any of the possible filesystem entry types (these
vary among platforms but always include files and directories among
others).
For example, Unix-like operating systems typically allow for seven (7)
unique entry types including:
plain files
directories
symbolic links
named pipes
block special files
character special files
sockets
These different types of entries and the differences among platforms aren't
particularly important to us. For our purposes, there are only 2 categories of
entries: plain files and everything else. If the item is not a file, we can
ignore it regardless of type.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
We need to define a routine that can be run against each item found. We
provide find() a reference to the routine and a starting location and it
arranges for the routine to run repeatedly, once for each item in the directory
tree starting at the root.
From the documentation for File::Find
find(\&wanted, @directories_to_search);
sub wanted { ... }
"find()" does a depth-first search over the given @directories in the order
they are given.
For each file or directory found, it calls the &wanted subroutine.
Additionally, for each directory found, it will "chdir()" into that directory
and continue the search, invoking the &wanted function on each file or
subdirectory in the directory.
The wanted function takes no arguments but rather does its work through a
collection of variables.
$File::Find::dir is the current directory name, $_ is the current filename
within that directory and $File::Find::name is the complete pathname to the
file.
Don't modify these variables.
The documentation confirms that we need to supply find() a reference to a
function, &wanted, and a list of directories to search,
@directories_to_search.
@directories_to_search is easy enough, we want to search the folder
containing our geotagged image files. This is the value of one of our
configurable variables ($photos_dir).
Let's describe the routine that find() will run against each item in
$photos_dir. Make sure you understand that the routine should be designed
to run against only one item. If there are many items, find() will call the
routine many times, but that is irrelevant as far as the design of the routine is
concerned.
For a single item:
5. First, the routine runs a series of tests to determine if it is:
a file
the appropriate type of file
and readable
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
The second test will make a determination based on the filename extension.
As written, the script considers any file that ends in .jpg or .jpeg (case
insensitive) a valid file type. You can expand this list to include extensions
for other types of image files or alternative extensions for jpeg files.
If the item fails any of these tests then we immediately return from our
routine, essentially skipping it.
6. If the item passes all of the tests, we use ExifTool to extract from the
image's metadata only those tag values we're interested in (detailed above).
7. Next check for the 'GPSLatitude' and 'GPSLongitude' tags among the list
returned from ExifTool. If there are not defined values for these tags then
the tag names will not be included among the list returned. Though the item
may be a valid image file, without coordinate data we can't know where to
position a marker representing this photo on a map, so there's nothing we
can do with it in our mapping application. We have no choice but to skip it.
Note that any photo for which there is no coordinate data will be missing
from our output files.
8. Assuming we have at least the two tags 'GPSLatitude' and 'GPSLongitude',
we use the tag values to build a Placemark element for the image and write
the element to output.
We assemble a <description> element for the Placemark by combining
several of the tag values.
We can account for optional tags, which may or may not have been
populated in the metadata for the image (the tag People for example) by
determining if ExifTool was able to find values for the associated tag
names. If no value was found, because the tag was not used, the
corresponding variable will be undefined.
The Placemark description for each of our image files can be illustrated by
the following block, which is another template:
<ul>
<li>People: $People</li>
<li>Event: $Event</li>
<li>Location: $Location</li>
<li>City: $City</li>
<li>State: $State</li>
<li>Country: $Country</li>
<li>Date: $DateTimeOriginal</li>
</ul>
<p>$thumbnail_img</p>
<p>$image_link</p>
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Variables are replaced by tag values extracted from the current image file. If
one or more of the variables is undefined, we simply do not include the
entire line.
$thumbnail_img is a complete URL to a thumbnail which will be included
in the description via the <img> tag's src attribute, e.g.
<img src="$thumbnail_img" />
$image_link is a complete URL to the gallery detail page featuring the
photo. We include a link to the page in the description, e.g.
<a href="$image_link">Gallery details page for this image</a>
At this point we've done everything required to represent the photo in our
output file, but we're not quite ready to return from the routine.
As we have just seen, among the metadata tags we want to extract are the
regional tags 'City', 'State/Province' and 'Country'. Assuming values for
these tags are defined, we will include the information as part of the
description in our <Placemark>, which means we will see it displayed in the
information window when we click the marker representing this image on
the map.
We also use these tags to assist us with clustering in our Google Maps
application and as a first step to implementing a feature called 'Regions' in
Google Earth (more on the topic of Regions later).
Throughout the tutorial I've said that we will be generating more than one
output file, but we haven't identified what these files are until now.
By default, the names of the output files generated in the script
accompanying the tutorial are:
photos.kml
cities.kml
states.kml
countries.kml
photos.kml is the only file of interest as far as this part of the tutorial is
concerned. It is the output file we've been discussing to this point. This is
the file that includes one <Placemark> for each of our geotagged image
files.
What are the others?
In the source we declare the three hashes:
%known_cities
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
%known_ states
%known_countries
These hashes will contain one key for each unique region represented
among the geotagged images (i.e. one key in the appropriately named hash
for each city, state, and country represented).
The purpose of these hashes is to enable clustering of markers on our maps
around large, well-defined geographical areas at lower zoom levels.
What is clustering?
Until we are above some threshold level, we will not be able to distinguish
between markers for photos first within the same country, then
state/province, and finally city, assuming we have more than one photo for
the region. In these cases we create a single marker at the center of the
region to indicate that there are photos available which cannot be displayed
at the current zoom level.
9. Before we return from the routine, we check the hashes to see if the keys
corresponding to the tag values from the current image file already exist. If
they don't, we add them.
For example, if the current image file is a photo of Boston, Massachusetts
(USA), the following is a partial list of tag values from ExifTool:
City: "Boston"
State: "MA"
Country: "USA"
Let's say that the script has already come across a photo of someplace in the
United States. If that's the case, then the key "USA" will already exist in the
%known_countries hash. We don't have to add it again.
If we've also seen at least one photo taken somewhere in Massachusetts,
then the key "MA, USA" will exist in
%known_states; but let's say this is the first photo of Boston, Massachusetts.
Then the key "Boston, MA" will not exist in %known_cities, so it will be
added to the hash.
If this is all a little unclear, it may help to look at the source file.
After all items have been evaluated, find() returns. At this point in
execution, we've generated a Placemark element for each image, and
finished populating the regional hashes.
10. For each key in the regional hashes, the script creates a Placemark element
in one of cities.kml, states.kml or countries.kml (these are the default output
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
filenames). For example, for every key in the %known_countries hash, a
Placemark is created in the countries.kml file.
There are a couple of important differences between photos.kml and these
regional files.
A. There will be only one Placemark element for each unique regional
location. So if we have 100 image files and all of them are photos of
Boston, MA, then we will have a single Placemark element in each
of cities.kml, states.kml, and countries.kml - not 100 identical
Placemark elements in each.
B. Because these Placemarks represent regions, not photos, there is no
metadata for us to work with. How do we get a coordinate pair for
each city, state, and country?
We have two options.
The Google Maps API includes a geocoder we can use. From the
documentation we have this definition of geocoding:
Geocoding is the process of converting addresses (like "1600 Amphitheatre
Parkway, Mountain View, CA") into geographic coordinates (like latitude
37.423021 and longitude -122.083739), which you can use to place markers
or position the map based on street addresses in your database or addresses
supplied by users.
We can pass the geocoder any one of our hash keys and it will return the
geographic coordinates representing the center of the named region.
The problem is that it returns coordinates for what I'll call the 'computed
center' of the region, which is not always what we want. For example, the
following is a link to maps.google.com identifying the computed center of
Massachusetts (my home state).
http://maps.google.com/maps?f=q&hl=en&geocode=&q=Massachusetts&ie=UTF8&ll=42.008489,-71.71875&spn=3.98356,7.03125&z=7&om=1
The arrow identifies the computed center of the state as reported by
Google's geocoder, which seems to indicate that the center is along the
southern border. This makes sense when you consider that Massachusetts
includes Cape Cod and Nantucket, which are much further southeast than
the rest of the state.
If you aren't bothered by these odd-looking but technically accurate
computed coordinates, then Google's geocoder may be all you need. Also, if
your regions are regularly shaped then this issues won't be apparent to you.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Alternatively, you could build a set of associations between region names
and the geographic coordinates you want to represent these places.
As written, the script allows you to do both. In addition to using the
geocoder, you can manually associate regional locations with specific
coordinates in the configurable variables section of the code. Instructions
are included in the source file itself. If you have manually placed a
particular region, then it will use your coordinates, otherwise it will use
Google's geocoder.
Note: Use of the geocoder here is the reason that you must include a Google
Maps API key in the script.
These regional places are useful for clustering with Google Maps and
Google Earth. Clustering in Google Earth requires the use of Regions which
are not implemented in this tutorial. The topic of clustering will come up
again in the Google Maps portion of the project.
11. After generating all of our Placemark elements, there are a couple of lines
from the KML template at DATA that must still to be appended to the
output before we're finished. These are nothing more than closing tags for
the <Folder>, <Document> and <kml> elements and can be written directly
from our template to the the output files.
12. At the end of execution we print a few statistics that have been collected
throughout execution to help users identify problems, or confirm that the
script ran as expected. These are simple counters or based on simple
counters, but are useful nonetheless.
At the end of execution we have generated our KML files:
photos.kml, cities.kml, states.kml, countries.kml
Of primary interest is photos.kml.
Because we're not dealing with Regions for clustering in Google Earth, the regional kml
files aren't useful for this part of the tutorial, but don't delete them because we will be
using clustering in Google Maps. Should we decide to use Regions in the future,
implementing the feature will be a much simpler proposition than it would be otherwise
because we've already done some of the work involved.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Section 9: Finishing up You can, and probably should, validate your KML files to ensure that they adhere to the
standard. This doesn't take a long time and it's easy to do. If you've uploaded your files to
a publicly accessible web server, visit the Feed Validator20
Once at the site, type the complete URL of your KML file(s), one at a time, into the text
entry field and click the validate button.
A note about the results:
The validator makes a distinction between warnings and errors.
If your file conforms to the standard, but the validator has some suggestions for
improving it you'll see the message:
Warning
This feed is valid, but may cause problems for some users. We recommend fixing these problems.
If you scroll down the page you will see a message confirming that the feed has
validated.
If there are actually errors in the file it will not validate, and you will see the message:
Sorry
This feed does not validate.
In either case, the validator will identify the lines in the file that produced the messages
as well as an attempted explanation of the issue.
Once your feed validates, all that's left to do is enjoy browsing and sharing your photos.
Section 10: Sharing KML Files 1. You can open the KML files locally.
Doubling-clicking photos.kml should open Google Earth. Alternatively,
launch Google Earth, choose 'Open...' from the 'Edit' menu and use the
standard dialog box to navigate the filesystem to your photos.kml file.
2. You can share the file via email.
Because the files contain only text, you can depend on file sizes being
relatively small. Remember that images are referenced in the file via URL
not included directly.
20
Feed Validator: http://feedvalidator.org/
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
3. If you upload the file to a public web server, something you'll want to do in
preparation for the Google Maps portion of the project, then others can
access your images from within Google Earth by adding a Network Link.
However you choose to share the KML file, you can select the folder containing all of
your photo markers in Google Earth's Places panel and 'tour' your photos. A tour moves
from one marker to the next on the map, pausing for a short amount of time at each and
(optionally) displaying the marker's information window.
Finally, and as a preview of what we'll be doing next, you can display your KML file in
Google Maps in either of two ways:
You can visit the Google Maps site at maps.google.com and type the full URL to your
photos.kml file into the search field on the page.
Equivalently, you can pass the URL for the photos.kml file as the value to that
application's 'q' parameter.
For example, the KML file I've created for this project is located at:
http://robreed.net/maps_tutorial/photos.kml
I can display the data from the file in Google Maps at:
http://maps.google.com?q=http://robreed.net/maps_tutorial/photos.kml
We can't change anything about the Google designed page, which works well for only
small numbers of images. If you had hundreds of image files on the other hand, the
'Contents' list in the sidebar on the page would be very long and unwieldy. Also, we
cannot incorporate clustering or other features available to us through the API.
Take a look at my kml file and you'll see the problem that clustering solves on display
around the area of Boston, MA, where the majority of the 113 photos in the collection
were taken. As you zoom in, the space between the markers on the map increases. At
some point, you will be able to clearly distinguish between all of them, but at the default
zoom level there are a jumble of indistinguishable, overlapping icons.
Limitations notwithstanding, using Google Maps and KML in this way is useful in its
own right and a good demonstration of what's possible.
Section 11: Next Steps What could be done to improve on this script?
The next topic you should familiarize yourself with related to Google Earth is 'Regions',
which make it possible to efficiently work with very large datasets in Google Earth, even
when publishing data over a network.
Regions define areas in Google Earth in terms of a 'bounding box' and 'levels of detail'.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
The bounding box defines the northern, southern, eastern, and western boundaries of the
user's current view of the Google Earth map (and also possibly min and max altitude
values if appropriate, for example when working with 3D objects).
Level of detail describes the number of pixels the Region currently occupies on screen.
Keep in mind that even a large area (large in terms of coordinate boundaries) may occupy
only a small portion of the map at low zoom levels. Of course the reverse is also true, i.e.
very small geographic areas may fill a large portion of the display at the highest zoom
levels. Or we can say that at high zoom levels the resolution of the view is much greater
than it is at the lowest levels. As a result of this higher resolution, more markers can be
distinguished on the map but the field of view is decreased. At lower resolutions, adding
a lot of detail to the map, i.e. many Placemarks, only results in overlapping,
indistinguishable markers. Google Earth and your computer must work harder to display
these Placemarks. In the case of Network Links, all of this data must be transmitted over
relatively slow connections, significantly reducing the performance of the application and
detracting from the appeal of using Google Earth as a solution for sharing your photos.
This discussion may sound confusing the first time you read it. Suffice it to say that it
makes little sense to produce markers for photos on your map that are not visible to your
audience because they exist outside the current view or because they are obscured by
other markers. Regions solve these issues by ignoring data that is either outside of the
current bounds of the map, or indistinguishable because of the current resolution. While
we are dealing with only hundreds or thousands of images, this isn't necessarily a
significant concern. At the point when we are sharing tens of thousands of photos, or
perhaps hundreds of megabytes worth of data, Regions are critically important.
Because the use of Regions is not necessary given the scope of this project (hundreds of
photos) I'll not pursue this topic further. I can say that you will be able to incorporate
Regions into the rest of this project if you choose to do so. Nothing that we do here
precludes the use of Regions or complicates their use.
Note that we will be implementing a similar feature in Google Maps, because the issue of
inefficiency is a problem with far fewer markers. Google provides a 'marker manager'
that is similar in functionality to the Regions feature in Google Earth. Allowing the
application to ignore photos outside the current view and 'cluster' (i.e. reduce the number
of markers generated) in response to the resolution of the map at various zoom levels.
The discussion of the marker manager should help you with the concept of Regions.
Section 12: Conclusion We've finally come to the end of the Google Earth project, which is actually the first half
of a 2-part tutorial.
If you haven't looked at the source code yet, now is the time.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
If you followed along with the tutorial, the code will seem very familiar to you. Also, if
you have some questions after reading through the tutorial, the extensive comments in the
source should help. If you've successfully generated your KML files, congratulations! If
you're still working on it, and especially if you're having some trouble, I would encourage
you to keep at it. Maybe take a break and come back. It's always been surprising to me
just how much clearer a problem becomes after spending some time away from it doing
anything else.
In the second project, we look at building a Google Map from the KML files that we've
generated. In the process we'll cover the Google Maps API, Javascript, object models, the
DOM, and we'll talk a little bit about XHTML.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Part 2: Google Maps
Section 1: Introduction to Part 2 When approaching any sufficiently high-level computing topic, it is often true that we
need to be familiar with a broad range of underlying and related concepts to establish the
foundation necessary to learn the new material. Virtually every technology not only
borrows from, but also builds on others. Furthermore, it is often the case with
programming projects that the bulk of the work comes at the beginning and involves
carefully thinking through the problem, devising a solution, and building those parts of
the project that we need to write before we can get to the code we want to write.
In the first part of the tutorial we wrote a Perl script which allows us to generate valid
KML files from collections of geotagged photos. Using our new tool, we generated a
number of files containing all of the data (about our photos) that we'll use to populate our
Google Maps. We also looked at the structure of KML, and covered a number of other
important topics, which are key to understanding the material presented here. If you have
not read part 1, do take the time at least to glance through it to confirm for yourself that
you won't have trouble following along with this discussion.
Now we turn our attention to Google Maps.
After this short introduction we'll handle the tutorial in 3 parts.
Part 1: This section discusses the document-object-model (DOM), which is a formal
methodology for negotiating XML files, like the KML files we created in part 1.
Part 2: Next we'll look at XHTML and the XHTML file we'll use to display our Google
Map. As you'll see, the file included with the project is no more than a shell, but it does
suffice to allow us to present our map. Furthermore, it affords us an opportunity to talk
about integrating XHTML, Javacript, and the Google Maps API. There are a few
important things we'll need to understand.
Working with a simple page will help us avoid complicating the issues unnecessarily and
will make it easy for you to relocate the map to a page of your own (maybe as part of a
weblog for example) with a minimum amount of fuss.
Part 3: Finally, we'll look at Javascript and the Google Maps API.
Before we get to all of that, there are a couple of preliminary topics to talk about:
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
XML We've already looked at XML, describing it as an open, extensible markup language.
We've said that XML is a metalanguage which allows us to define other languages with
specific syntactic structures and vocabularies tailored to discrete problem domains.
Furthermore we've said that KML is one such XML-based language, engineered to
address the problem of describing geographical data and the positioning of geographical
placemarks and other features to display on a map, among other applications.
XHTML We haven't yet talked about XHTML which is a reimplementation of HTML as a
standard, XML-based format. HTML21
(Hypertext Markup Language) has served as the
preeminent language for authoring documents on the World Wide Web since the web's
inception in the late 1980s and early 1990s.
HTML is the markup language22
which makes hypertext23
linking between documents on
the web possible and defines the set of tags, i.e. elements and attributes, that indicate the
structure of a document using plain-text codes included alongside the content itself. Just
as the web was not the first hypertext system24
, HTML was not the first markup language,
though both have become extremely important.
Without delving too deeply into the primordial history of markup, HTML is a descendant
of SGML (Standard Generalized Markup Language) which is itself an offspring of GML
(Generalized Markup Language).
The Wikipedia entry for GML offers this description of the language:
GML frees document creators from specific document formatting concerns such as font
specification, line spacing, and page layout required by Script.
SCRIPT was an early text formatting language developed by IBM, and a precursor to
modern page description languages like Postscript and LaTeX, that describe the structure
21
HTML entry at Wikipedia: http://en.wikipedia.org/wiki/HTML 22
A markup language is any language that uses text codes or symbols alongside the content itself to specify the style and layout of the document. 23
A simple definition of hypertext from the The W3Cs what is Hypertext glossary of Hypertext terms: http://www.w3.org/WhatIs.html. The full list of terms is available at: http://www.w3.org/Terms.html. Note that this document is not a complete list of terms, nor does it necessarily reflect current usage. (Last updated 1995.). See the appendix for additional resources. 24
The History of Hypertext: http://ei.cs.vt.edu/~wwwbtb/book/chap1/htx_hist.html
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
and appearance of documents. Not surprisingly the goal of GML is echoed in the intent of
HTML, though the two are far removed from each other.
Berners-Lee25
considered HTML to be an application of SGML from the very beginning,
but with a clear emphasis on simplicity and winnowing down much of the overhead that
had always characterized formal markup languages. In the early days, the web had to
struggle for acceptance. The birth of the web is a story of humble beginnings26
. The
significance of the web was by no means a forgone conclusion and early adoption
required that the markup syntax of the web be as accessible as possible. After all, more
stodgy languages already existed.
The simplicity of HTML certainly contributed to the success of the web (among many
other factors), but it also meant that the standard was lacking in key areas. As the web
gained wider appeal there was a tendency to take advantage of the early permissiveness
of the standard. Developers of mainstream web browsers exacerbated the problem
significantly by tolerating noncompliant documents and encouraging the use of
proprietary tags in defiance of efforts on the part of standards organizations to reign in
the syntax of the language.
In the short term, this was a confusing situation for everyone and led to incompatibilities
and erratic behavior among an ever increasing multitude of documents on the web and
the various web browsers available, which differed in their support for, and interpretation
of, what were in essence emerging 'dialects' of HTML. These web browsers not only
differed from one another, but also frequently from one version to the next of the same
application.
There was a real need to establish stability in the language. Lack of dependable syntax
meant that the job of building a parser capable of adequately adhering to the standards,
and at the same time accommodating various abuses of the standard, had become an
exercise in futility. Unlike HTML, XHTML must strictly adhere to the XML standard,
which means that any compliant XML parser can negotiate properly formatted
documents with relative ease. This reliability paves the way for a more efficient and
sophisticated web, resulting in not only more consistent rendering of content, but the
development of software that is able to differentiate and act on content based on context,
and relationships among data. This is one of the primary advantages of XML, as has
already been discussed, and this is a key advantage of XHTML as well.
Berners-Lee, who currently serves as the director of the World Wide Web Consortium
(W3C)27
and a senior researcher at MIT's Computer Science and Artificial Intelligence
25
Sir. Tim Berners Lee who is considered the father of the web and currently serves as the director of the World Wide Web Consortium (W3C) 26
The World Wide Web: A very short personal history: http://www.w3.org/People/Berners-Lee/ShortHistory 27
World Wide Web Consortium: http://www.w3.org/
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Laboratory (CSAIL)28
, continues to actively pursue the vision of a Semantic Web29
. That
is, a web that can be mined as a rich repository of data by intelligent software agents,
which not only present information, perform basic pattern matching, and the like, but are
capable of analysing information (in a truer sense - keep this or get rid of it?).
From the W3C's Semantic Web Roadmap we have this brief introduction to the concept:
The Web was designed as an information space, with the goal that it should be useful not
only for human-human communication, but also that machines would be able to
participate and help. One of the major obstacles to this has been the fact that most
information on the Web is designed for human consumption, and even if it was derived
from a database with well defined meanings (in at least some terms) for its columns, that
the structure of the data is not evident to a robot browsing the web. Leaving aside the
artificial intelligence problem of training machines to behave like people, the Semantic
Web approach instead develops languages for expressing information in a machine
processable form.
Whether this vision accurately predicts the future of the web remains to be seen. At the
moment the Semantic Web is a veritable stew of protocols, frameworks, concepts,
extensions, namespaces, vocabularies, schema, ontologies, and other components. It is
the subject of much debate, virtually all of it far beyond the scope of this tutorial. But this
'brave new web' is not purely academic.
The increased emphasis on standards-compliant markup has resulted in developers of
web browsers and content creation tools steering their apps toward the standards. This in
turn motivates authors to produce compliant documents. In fact the Strict variations of
XHTML do not allow for deviation from the standards. Two immediate benefits of this
work, whether or not it ultimately leads to some future web, are (1) more consistent
document rendering across platforms among mainstream web browsers, (2) and the
emergence of the Document Object Model (DOM). We'll look at the DOM shortly.
Section 2: Object Models and the DOM An object model is a collection of objects and the typically hierarchical, often complex,
relationships among them, where the most generic definition of an object is simply a
'thing'. Object models are all around us and are not limited to programming or the broader
topic of computing for that matter. If, for example, you were to describe a car in terms of
its object model:
28
MIT Computer Science and Artificial Intelligence Laboratory: http://www.csail.mit.edu/index.php 29
W3C Semantic Web Activity: http://www.w3.org/2001/sw/
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
You might start by talking about the chassis, or base frame, and then go on to describe
the body of the car, its wheels, axles, exhaust system, the drivetrain, etc.; everything that
is directly attached to the frame.
For each of these you could describe various attributes and elements of that object; for
e.g. the body material is an attribute of the body object. The elements may in fact be other
objects that collectively comprise those objects within which they are contained.
The body of the car contains the engine compartment, passenger compartment, and trunk
elements. The engine compartment includes the engine which is itself a collection of
smaller objects. The passenger compartment can be described as the collection of front
and rear compartment objects, where the front compartment object includes at least a
driver side compartment with a steering wheel, instrument panel, etc. These objects have
their own attributes and elements perhaps consisting of other objects each of which is an
object itself, with a more specific function than the objects in which they are contained.
If you've ever put together a toy model of a car you may remember seeing an exploded
schematic diagram of the completed model which clearly shows all of the objects from
the largest container elements to the smallest ties, screws and other fasteners that hold all
of the pieces together. This is a nice way to visualize the object model of the toy car.
Of course the object model I have described is only an informal example. It may be fair
to dispute the model I've sketched here. As long as you have a better general
understanding of what an object model is then this example has served its purpose.
Object models are very common within the realms of computer technology, information
technology, programming languages, and formal notation.
The Document Object Model The Document Object Model (DOM)
30 is a standard object model for describing,
accessing and manipulating HTML documents and XML-based formats. The often
quoted description of the DOM from the W3C's site dedicated to the specification is:
The Document Object Model is a platform- and language-neutral interface that will allow
programs and scripts to dynamically access and update the content, structure and style of
documents. The document can be further processed and the results of that processing can
be incorporated back into the presented page.
Remember that XHTML is a special case of XML (i.e. it is an XML based format) and
essentially no more than a formalization of HTML. Because it is an XML based format
the XML DOM applies. Furthermore, because XHTML describes a single format with a
number of required structural elements and only a limited collection of allowable
30
W3C Document Object Model: http://www.w3.org/DOM/
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
elements and attributes, the HTML DOM has a number of unique objects and methods
for acting on those objects that are not available in the more generic XML DOM. Having
said that, I want to emphasize the the two are more alike than the are different.
Technically we will look at the XML DOM here but nearly everything discussed is
applicable to the HTML DOM as well. Though there are differences, some of which we'll
encounter later in this tutorial, as an introduction it is appropriate to limit ourselves to
fundamental concepts, which the two share in common. We need both. We'll rely on the
XML DOM to parse the KML files we generated in part one of the tutorial to populate
our Google Map, and the HTML DOM to add the map to our webpage. By the time we've
completed this part of the tutorial hopefully you will appreciate just how integral the
DOM is for modern web design and development, though we'll only have skimmed the
surface of it.
The concept of the DOM is actually quite easily understood. It will seem intuitive to
anyone who has ever dealt with tree structures (from filesystem hierarchies to family
trees). Even if you haven't had any experience with this sort of data structure, you should
anticipate being able to pick it up quickly.
Under the Document Object Model individual components of the structure are referred to
as nodes. Elements, attributes and the text contained within elements are all nodes.
The DOM represents an XML document as an inverted tree with a root node at the top.
As far as the structure of an actual XML document is concerned, the root is the element
that contains all others. In every structure all other nodes are contained within a
document node. In the KML files we've generated the Document element is the root
element.
Every other node is a descendent of Document. We can express the reciprocal
relationship by stating that Document is an ancestor of every element other than itself.
Relationships among nodes of the document are described in familial terms. Direct
descendants are called child nodes or simply children of the their immediate ancestor,
referred to as a parent.
In our KML files, <Folder> is the only child of <Document>. (It would be just as correct
to say that <Document> is the parent node of <Folder>.) Note that there could be more
than one Folder node. We could use additional folders to group Placemarks (a) by year,
with one folder per year, (b) by event, with each folder dedicated to a single event, or (3)
by image gallery so that each folder corresponds to a discrete image gallery, or maybe
some combination of these and other criteria. Furthermore, we can have more than one
type of child node under a single parent. For example Placemark is the parent node of
<name>, <Snippet>, <description> and <Point> in our files. These nodes can all be
described as siblings, because they all have the same parent. Also, notice that
<coordinates> is a child of <Point>, and a grandchild (not a child) of Placemark.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
We can make a couple of other useful observations about this structure:
1. Every node other than the root has exactly one parent.
2. Parents may have any number of children including zero, though a node
without any children won't be referred to as a parent. (A node with no
children is called a leaf.)
Implicitly there are other familial relationships among nodes. For example, elements with
parents that are siblings could be thought of as 'cousins' I suppose, but it is unusual to see
these relationships named or otherwise acknowledged.
There is one important subtlety. Text is always stored in a text node and never directly in
some other element node. For example, the description elements in our KML files
contain either plain text or html descriptions of associated Placemarks. This text is not
contained directly in the description node. Instead the description node contains unseen
text node which contains the descriptive text. So the text is a grandchild of the description
node, and a child of a text node, which is the direct descendent of description. Make sure
that you understand this before continuing.
Because of the inherent structure of XML, we can unambiguously navigate a document
without knowing anything else about it, except that it validates. We can move around the
tree without being able to name the nodes before we begin. Starting at the root document
node, we can traverse that node's children, move laterally among siblings, travel more
deeply from parent to child, and then work our way back up the tree negotiating parent
relationships. We haven't yet described how we move among siblings.
The DOM allows us to treat siblings as a list of nodes, and take advantage of the
relationships that exist among elements in any list. Specifically, we can refer to the first
(firstChild) and last (lastChild) nodes to position ourselves in the list. Once we are at
some location in the list, we can refer to the previous (previousSibling) and next
(nextSibling) nodes to navigate among siblings. Programmatically we can use the DOM
to treat siblings in a XML data structure as we would any other list. For example, we can
loop through sibling nodes working on each node in turn.
Keep in mind that we are using generic terminology, not referring to specific node names
and we are relying only on the structure of XML which we know must be dependable if
the document adheres to the standard. This will work well for our KML files, and it is
certainly not limited to KML.
There are primarily two techniques we can use to find and manipulate elements in our
XML structure using the DOM.
1. Node Properties
Firstly, we can take advantage of relationships among element nodes as we
have been discussing.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
A number of node properties, some of which have already been mentioned,
allow us to move between nodes in the structure. These include:
firstChild,
lastChild,
previousSibling,
nextSibling,
parentNode
If we look at a fragment of KML, similar to the KML files generated in part
1 of the tutorial, starting at the Placemark element...
<Placemark>
<name>value</name>
<Snippet maxLines="1">
value
</Snippet>
<description><![CDATA[value]]></description>
<Point>
<coordinates>value</coordinates>
</Point>
</Placemark>
...we see a number of these properties:
a. <name> is the firstChild of <Placemark>
b. <Point> is the lastChild of <Placemark>
c. The nextSibling of <name> is <Snippet>
d. The previousSibling of <Point> is <description>
e. <Placemark> is the parentNode of <name>, <Snippet>, <description>, and
<Point>
2. getElementsByTagName()
Secondly, we can use the method getElementsByTagName() to find any
element regardless of the document structure.
For example, using the syntax...
getElementsByTagName("name")
...we can retrieve all <name> elements as a nodeList from the document
which are descendants of the element we are using when we call the
method.
The following Javascript statement returns a list of all <name> elements in
the document and stores that list at the variable list_of_nodes.
var list_of_nodes = getElementsByTagName("name");
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
What is a node list?
A node list (NodeList) is an object representing an ordered list of nodes, where each node
represents an element in the XML document. The order of the NodeList is the same as
the order of the elements in the document. Elements at the top of the document appear
first in the list, and the first element returned, i.e. the first position in the list, is numbered
0.
Keep in mind that the list includes all <name> elements. If you look at the KML files
we've generated you may notice that both <Folder> and <Placemark> elements contain
<name>. We need to be aware that getElementsByTagName("name") will return all of
these if we are starting at the document root. We can differentiate between these <name>
elements in a number of different ways. For example we can insist that the node is a child
of a Placemark node to exclude <name> elements that are the children of <Folder>
elements.
We need to be able to refer to various properties of these nodes if we are going to act on
them in any reasonable way. The XML DOM exposes several useful node properties incl:
nodeName, nodeValue, and nodeType.
nodeName: is (quite obviously) the name of the node. What might be less obvious is
precisely how the DOM defines nodeName.
The tag name is always the name of an element, e.g. 'Placemark' is the name
of the <Placemark> elements.
The attribute name is the nodeName of an attribute, e.g. the name of the
maxLines attribute of <Snippet> is 'maxLines'.
The name of any text node is always the string '#text'. e.g., the plain text or
html that we're using as our Placemark descriptions are each contained in a
text node, as has already been discussed, and the name of this text node is
'#text', and not the name of the element which surrounds the value in the
XML document.
The nodeName of the root document node is always the literal string
'#document'.
nodeValue: is what you might expect.
The value of text nodes is text itself. So the text node of one of our
Placemark <description> elements is all of the plain-text or html within the
description tags. Again, as far as the DOM is concerned the text is actually
contained within a text node which is a child of a description node.
The value of an attribute node is simply the attribute value. e.g.
maxLines="1" has a nodeValue of 1.
nodeValue is not defined for the document node and all element nodes.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
nodeType: is certainly not something you could guess.
A specific value is assigned to each of the available types (categories) of nodes. The
following is an incomplete list of common node types.
Element, type 1
Attribute, type 2
Text, type 3
Comment, type 8
Document, type 9
As I have already said, we will take advantage of the DOM to parse our KML files and
populate our Google Maps. Many of the ideas we've seen here will seem much more
concrete when we put them to use. Still, this has been a very brief look at an interesting
topic that is especially important to web developers and designers. I would recommend
that you pick up a book that does a good job of describing the document object model if
you are planning on doing any significant amount of that kind of work. This need not be
an intimidating topic, though I have found that the majority of books and articles do an
inadequate job with it. If you are only interested in following along with this tutorial then
this brief treatment of the DOM, the comments in the included source files, and the
javascript code itself should be sufficient for you to complete the project.
Section 3: XHTML The next topic we need to look at before moving on to the Javascript that will complete
the project is the XHTML page on which we will present our map. A very simple page
has been provided. It will be obvious from looking at the file that it is no more than a
shell; the basic framework necessary to present our map in a web page. I doubt that any
effort I put into building an elaborate XHTML page would accomplish more than
confusing the issues and detracting from the overall value of the tutorial. Absolutely no
one should be intimidated by the page nor should it take more than a moment to
understand it.
There are some noteworthy parts of the page you will want to pay attention to:
1. The page is compliant with the XHTML 1.0 Strict standard as written. It
could just as easily be XHTML 1.1, HTML 4.0.1 Transitional, or any other
specification. In the case of XHTML 1.1, all that would need to change is
the doctype declaration and MIME type:
Compare the two doctype declarations
XHTML 1.0 Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
XHTML 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
and the MIME types
XHTML 1.0 Strict
text/html
XHTML 1.1
application/xhtml+xml
I chose XHTML 1.0 Strict because it is an XML based format and closer to
HTML 4.01 than XHTML 1.1. Furthermore, you may need to reconfigure
your web server or change the extensions on your XHTML 1.1 files before
your server will deliver the proper MIME types. Again, this point is fairly
trivial considering how simple the page is. However, it does present an
opportunity to mention validation.
We've already discussed validating the KML files generated in the first part
of this tutorial. In that case we used the Feed Validator at
http://feedvalidator.org/ to confirm that our KML files were up to spec so
that we wouldn't run into trouble opening the files in Google Earth, or when
it came time to incorporate them into our Google Maps script.
Here we'll use the W3C's Markup Validation Service
(http://validator.w3.org/) to check our XHTML file. The procedure is
similar to what we did with KML validation though we're using a different
validation service against a different type of file.
(1) Simply visit the validator's page in your web browser, (2) type or paste
the complete URI to your map page at the text entry box labeled "Address:',
and (3) click the 'Check' button.
A valid page will result in the following message:
"This Page Is Valid XHTML 1.0 Strict!"
while an invalid page will produce the error message:
"This page is not Valid XHTML 1.0 Strict!"
Like the Feed Validator, the W3C validation service makes a distinction
between errors, which are failures of the page to comply with the standard
and must be corrected, and warnings, which are detected deviations from
what may be considered ideal. You should take these warnings under
advisement and correct as many as you are able to, unless you're
intentionally ignoring them for some good reason.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Besides validating a page publicly available on the web by URI, you have
the option of uploading a local file, or even copying and pasting a full
document into a text entry box for validation, what the validator calls
'Validate by Direct Input'. There are some options you can use to affect the
behavior of the service. The default behavior should be fine, but using
options you can do things like:
temporarily override the automatically detected Document Type
group reported error messages by type
display the source of the page being validated with the results
fix problems with your page using the HTML Tidy library, which is
code that can correct common editing mistakes (for example it can
add closing tags, fix simple tag nesting issues, etc.) and apply a
consistent structural style to messily written pages
The validator is a valuable tool for all of us and I encourage you to make a
habit of using it, especially when designing your own pages, including
weblog templates or themes. Keep in mind that there is no such thing as a
personal publicly accessible web page. If your site is accessible on the web
then you have a responsibility to produce clean markup for your visitors and
the rest of the global community. If you're unmotivated by the argument that
you should validate because it's 'the right thing to do', then keep in mind that
invalid markup may effectively reduce the size of your audience and impact
your site's ranking with search engines. Furthermore, nonstandard markup is
ultimately more time-consuming and difficult to maintain, and is likely to
break in unpredictable ways.
This brings up a dirty little not-so-secret truth about some of the more
popular web services, which are becoming increasingly important these
days. Many very useful, slick-looking web services generate broken
markup. What can you do about it? Well, from a practical standpoint, don't
be too upset by this. The services wouldn't be popular if they weren't
functional. So, if you want to use one of them and it works for you and your
audience then I say go for it.
Of course, this is no excuse to produce invalid markup yourself. In fact, this
is yet another very practical reason to do everything you can to keep your
own code as compliant as possible. The problems you introduce that work
on their own may react badly and unpredictably with the problems you
inherit from others, which may also function correctly until they conflict
with your broken markup. These are likely to be very difficult issues to
diagnose and resolve, which is good reason to avoid them to begin with.
There is a well known quote from internet pioneer Jon Postel
(http://en.wikipedia.org/wiki/Jon_Postel) that applies here,
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
"be conservative in what you do, be liberal in what you accept from others".
Of course, feel free to complain to whichever organization is responsible for
the web services you use that are fouling up your otherwise standards-
compliant site. Something along the lines of...
Thank you for the service you provide but please invest whatever resources
are necessary to clean up the code you're asking others to embed in their
sites
...is probably the right approach.
2. Notice the <script> tags in the header that we use to include our own
Javascript functions and the code necessary to interact with the Google
Maps API.
From the Google Maps API documentation:
The URL (http://maps.google.com/maps?file=api&v=2) is the location of
a JavaScript file that includes all of the symbols you need for placing
Google Maps on your pages. Your page must contain a script tag
pointing to that URL, using the key you got when you signed up for the
API. If your Maps API key were "abcdefg", then your script tag might
look like this:
<script src="http://maps.google.com/maps?file=api&v=2&key=abcdefg"
type="text/javascript"></script>
It's not necessary that you understand these lines to use them, but they are
simple enough. The script tag references the location of Javascript code
hosted at maps.google.com (a specific server or more likely group of servers
in the google.com domain) that defines the various functions we'll use on
our page, and in our own Javascript code to produce and manipulate the
Google Map.
We provide some information to Google with our request. We need only
refer to the official documentation to learn about these and possibly other
available parameters.
From the documentation:
The v parameter within the http://maps.google.com/maps?file=api&v=2
URL refers to the version number of the Google Maps API to use. Most
users of the API will want to use the stable "Version 2" API by passing
the v=2 parameter within that URL. You may instead obtain the latest
release (including the latest features) by passing v=2.x instead. However,
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
be aware that the latest release may not be as stable as the v=2 release.
We update the Google Maps API about every two weeks, at which point
features within the v=2.x release are migrated into the stable v=2 release
unless problems are discovered.
We have already identified the 'key' parameter which is required to
authorize the page against a valid Google Maps API key. Remember that
these keys are tied to a specific directory on your server. You must keep
your pages that contain code that references the API in the directory you
specified when you requested the key. It will not work with pages in
subdirectories.
You can request additional keys to serve pages from multiple directories or
in the case that you lose track of the key(s) you have already generated. You
do not need to request that unused or misplaced keys be revoked. In fact
there is no established procedure for doing this even if you wanted to.
There are of course terms of service governing the Google Maps API. In
most cases these terms won't interfere with what you want to do, but I'm
sure there are many legitimate uses of the API that do not meet the terms of
service for one reason or another. You will find all of the legal information
you need to know about the API on the 'Google Maps API - Sign Up' page
(http://www.google.com/apis/maps/signup.html), including the complete
Terms of Use and a link to a form for contacting Google if you are unsure
that your usage will meet their terms.
Concerning our own Javascript code, you will see the following script tag in
the XHTML file
<script src="maps_tutorial.js" type="text/javascript"></script>
which references an external file where we will create our Javascript code.
Notice that this is a relative link. The tag will work for you as written if you
keep the filename 'maps_tutorial.js', and if you place the file in the same
directory as your XHTML page. Of course you are free to use any filename
you like at any location by simply changing the value of the src attribute.
Any relative path will work, as will absolute paths from your web server's
document root and fully qualified URLs, e.g.
http://sample.net/maps_tutorial/maps_tutorial.js.
There are a few ways for us to include javascript on our XHTML pages.
Javascript can be included:
in the head section of the page,
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
the body of the page,
in an external file referenced by the script tag's src attribute.
a. Javascript code written into the head section of a page is available
from anywhere on the page, but only on the page. Defined functions
are executed on request, either because they are explicitly called, or
triggered in response to an event.
b. Javascript written into the body of the page is executed as soon as the
page is loaded. You might include code this way to generate the
content of the page dynamically.
c. Javascript in an external file is available to possibly many
documents. For example, Google's Maps API is available globally to
anyone who requests an API key. This is a significant advantage of
creating external Javascript files but it is not the only one.
I've repeatedly said just how simple and blatantly obvious the included
XHTML file is. It's all of 30 lines long including all of the header info and
basic structural bits. On the other hand, the relatively simple Javascript file
accompanying the tutorial is hundreds of lines long (including comments).
The XHTML file would seem to be radically more complex, and
unnecessarily so, if we simply dumped all of the Javascript into the file.
This separation of structure (XHTML) from behavior (Javascript) is an
important tenet of modern web development. Unless you are doing
something highly unusual the Javascript code should exist in its own file(s)
referenced from your pages as we have done here.
Except where appropriate the other two techniques mentioned amount to no
more than bad habit which you should work to break or be careful to avoid
in the first place. Even with a page as simple as this, separating the structure
of the XHTML page from the behavior of the code makes it easier to
discuss each as discrete aspects of the project.
3. You will notice if you look at the body tag that two HTML events have
been specified along with behaviors (Javascript functions) triggered by the
events.
<body onload="setup_map()" onunload="GUnload()">
onload is a trigger that causes the associated script to execute when the page
is loaded. setup_map() is the name of one of the functions in our external
Javascript file. It is responsible for (a) working with the Google Maps API
to create a new map on our page (b) defining the custom icons we'll use to
represent markers on our map, (c) initiating the process of adding markers
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
to the map by calling the other functions we'll define. As the name implies,
setup_map() is the function that gets the whole process of generating our
custom map started.
As you might guess, the behavior associated with the event onunload is
triggered when the visitor leaves the page. GUnload() is a function from the
Google Maps API that takes care of cleaning up the data structures created
by the API.
From the documentation:
function GUnload - You can call this function to cause the map API to
cleanup internal data structures to release memory. This helps you to
work around various browser bugs that cause memory leaks in web
applications. You should call this function in the unload event handler of
your page. After this function was called, the map objects that you've
created in this page will be dysfunctional.
As you can see from this description, we're doing the right thing by
associating GUnload with the onunload event.
We'll be dealing with the Google Maps API and taking a closer look at
setup_maps() later in the tutorial.
4. I'm including a basic stylesheet which does no more than center the map on
the page horizontally, and style the font used on the page. For the purposes
of this tutorial, you can either keep the CSS file as it is, make any
modifications you like, or even choose not to use it altogether.
If you do choose to forgo the stylesheet, just delete the included tutorial.css
file and remove the link tag from the head section of the XHTML file.
If you keep the file, notice that I've used a relative link. The style info will
be available to your XHTML page without making any changes as long as
you keep the filename 'tutorial.css' and place the file in the same directory
as your XHTML page. You are free to use any filename you like at any
location by simply changing the value of the src attribute. Any relative path
will work, as will absolute paths from your web server's document root, and
fully qualified URLs, e.g. http://sample.net/maps_tutorial/tutorial.css.
There is one bit of style information that I am purposefully keeping out of the
external stylesheet and instead including in the XHTML file as an inline style;
that is the height and width of the div which will contain our map.
From the Google Maps API Documentation:
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
When you create a new map instance, you specify a named element in the page
(usually a div element) to contain the map. Unless you specify a size explicitly
for the map, the map uses the size of the container to determine its size.
I've left the size of the map div outside of the stylesheet to de-emphasize the the topic of
CSS as much as possible. This is not meant to imply that CSS is an unimportant topic. In
fact CSS is well worth your time and effort to learn. But, there are already quite a few
topics that we must cover to do a responsible job of introducing Google Maps as a
tutorial like this. CSS is not necessarily one of them, so I'm pushing it to the side in favor
of emphasizing other required topics. Of course, I am still using a style sheet for much
the same reasons I opted to use an external Javascript file. Separating presentation from
structure is as important as separating structure and behavior.. Unfortunately, a discussion
of CSS is beyond the scope of the article. Fortunately there are many good books and
other resources available on the topic.
Other than what has already been discussed, the XHTML file consists of a number of div
elements each named by an id attribute. For example:
<div id="map"></div>
Is the container for our map, as we have discussed.
The other divs specify locations on the page where we'll output status messages related to
the operation of our script.
For example:
After we request the photos.kml file from our server, so that we can include markers for
each of our photos on our map. The response code returned from our web server will be
written to
<div id="photos_kml_response"></div>
The other divs are target locations for response codes resulting from requests for the other
KML files we need to download, and some basic statistics, e.g. the number of markers
generated, etc.
The purpose of each of these divs should be obvious to you after looking through the
source for our Javascript code, which is responsible for writing these messages, and the
XHTML file itself. In fact you may be able to predict the purpose of each from the name
chosen for the id attributes. Alternatively, we could have included a single 'status' div for
all of these messages, but considering the simplicity of the XHTML file, I decided that
handling each in a separate div would be a more explicit way of structuring the file.
Typically, you would not expose this sort of 'debugging' message to your visitors. They
are useful only during development and then the code responsible for producing them
should be disabled in the Javascript and the divs removed from your XHTML pages.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Section 4: A Note about Web Programming Why include these messages at all? Because it can be difficult to debug Javascript code.
This is true of all web based application development and network programming more
generally. There are a number of reasons that this is the case.
Firstly, the success or failure of our code is dependent on many factors that are out of our
control.
If you are connecting to a remote machine and that computer is
malfunctioning, then your code may fail to execute as expected.
Transient networking issues may cause significant problems even if the
machines and all of the code involved are behaving properly.
Network applications tend to get complicated quickly because the
requirement of network communication means that the applications depend
on many underlying network services (e.g. name resolution) and network
devices (routers, switches, other gateway devices, etc.). What's more,
because of increasing concerns about security, many of these devices are
intentionally designed to interfere with network communications. Of course
the idea is that this interference affects only unwanted or harmful apps but
practically speaking this is virtually impossible.
Compromises inherent in the design of the security mechanisms,
configuration errors, other mistakes introduced during development or
implementation, and the intentional actions of those agents who endeavor to
abuse the network all contribute to the sorts of problems you may encounter
when developing network applications.
Fortunately for us, our network application is particularly simple. Traffic
over HTTP between web client and server is almost universally allowed,
because the web is viewed as such a fundamentally important application.
Furthermore, our communications with Google are almost entirely mediated
by functions provided to us as part of the Maps API. Assuming we trust that
Google knows what they are doing, then we can hope to avoid many of the
problems that might otherwise affect client/server interactions. Of course,
Google can't guarantee the stability of the network and those network
services that are out of its control any better than we can. For example,
transient network issues may still disrupt our application. What's more, we
are responsible for understanding the API so that we can be sure that we are
using it correctly. We need to supply the various functions Google provides
with appropriate data in the correct formats, and we must be prepared for the
values returned. A well-designed API simplifies these interactions, but we
must do our part as well.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Secondly, and this is more specifically an issue with Javascript and other web
programming, a web browser is extremely limited as a debugging environment. We must
do a lot of the heavy lifting to expose even the most basic information that will be useful
to us when it comes to identifying problems with our code. This is a particularly
annoying situation considering that the sorts of errors we may encounter are so varied and
difficult to predict, as has already been discussed.
Unfortunately the topic of debugging Javascript is well beyond the scope of this tutorial.
In fact, it deserves a substantial article of its own. So what can we do?
The single best piece of advice I can give is to use Firefox when you are working on the
Javascript portion of this project. Firefox includes an Error Console that will show you
warnings and errors encountered during the execution of this script. This basic
information will be incredibly useful to you if you find yourself staring at an empty
webpage where your map should be. You will find the 'Error Console' under the 'Tools'
menu.
While we're on the topic of debugging Javascript code, I want to point out that this is
another reason to use a very basic shell of an XHTML file before dumping your maps
into an existing page, e.g. an existing weblog theme. It very often is the case that your
existing webpages have a number of problems that will generate warnings or errors in the
Error Console. There is quite a bit of code involved when a Weblog engine generates a
page dynamically, especially considering all of the various extensions to the base script
that you have the opportunity to add. It would be a mistake to assume that all of this code
runs without throwing off a number of errors, even if the finished page displays perfectly
in your browser. These errors have nothing to do with your map of course, but will
nonetheless complicate the task of identifying and resolving problems you encounter
when building it.
A page as simple as the XHTML file included with this tutorial will not contribute any
errors or warnings to the messages you see in the Error Console. Once you have your
map working, it's a trivial task to move it to another page simply by copying and pasting
the script tags to your new page, and adding a 'map' div where you want the map to be
displayed.
If you want something more than the Error Console, take a look at the Venkman
Javascript Debugger (http://www.mozilla.org/projects/venkman/) which is available as an
add-on for Firefox and other Mozilla-based browsers.
From the Introduction on the Venkman project page:
Venkman is the code name for Mozilla's JavaScript Debugger. Venkman aims
to provide a powerful JavaScript debugging environment for Mozilla based
browsers namely Firefox 2.x, the Netscape 7.x series of browsers, Netscape 9.x
series, Mozilla Seamonkey 1.x and Mozilla Seamonkey 2.x.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Having discussed all of the preliminary topics, we can succinctly describe how to write
the Javascript code that will generate our map. Following the pattern established in the
first part of the tutorial we'll do this in 3 passes.
Section 5: An Introduction to the Code We'll begin with a high level, natural language discussion that faithfully describes the
code.
The second and third passes can be found in the source file itself, accompanying this
tutorial. What I'm referring to as a second pass are the detailed comments you will find
throughout the source. Pass 3 is the code itself.
After reading through the discussion here I recommend that you read through the source
file. Not only will this help familiarize you with the code but it will give you the
opportunity to make any changes necessary so that the code meets your needs. You'll find
the complete source code for the javascript portion of this tutorial in the file
'maps_tutorial.js'.
This discussion will frequently refer to the official Google Maps documentation pages
and version two of the API Reference. The documentation is well written and fairly easy
to understand. After you have finished with this tutorial you will want to remember to
spend some time reviewing the API reference. You will no doubt find answers to many of
your questions and discover new ways of doing things. Where the descriptions presented
in the reference are clearly written (and relevant of course) I will quote them here rather
than complicating the issue with my own clumsy explanations.
I'll take this opportunity to say that this is not intended to be an introduction to the
Javascript language. I will be careful to describe the execution of the script, i.e. how it
operates even when it may seem obvious to those of you who have some programming
experience. This is done intentionally to make the code as accessible as possible. Those
of you who find this discussion too chatty are welcome to move on directly to the source
code. I will not be spending any significant amount of time on the syntax of Javascript.
There are any number of good introductory Javascript books and other resources
available. It shouldn't take you much time at all to pick up enough of the syntax to follow
along with the rest of the tutorial, especially given that a completely functional script is
available for you to download, use and modify. I'm hopeful that even those of you who
have had little to no exposure to Javascript before now will be able to copy, paste and
reason your way through the script well enough to get your Google Map up and running.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Section 6: Natural language walk-through The first function definition we see is setup_map(). You may remember from the the
discussion about the XHTML page above that setup_map() is attached to the onload
event on our page. Accordingly, this function is called when the page is loaded.
First, we check that the browser is compatible with the Google Maps API using the
function GBrowserIsCompatible().
From the API Reference:
This function decides whether the maps API can be used in the current browser.
If the browser is compatible then we continue, or else we return having done nothing.
You may want to handle the case that the browser is incompatible with the API by
writing a helpful message to the page. Alternatively, you could do something more
complicated, but certainly you won't be generating a map so the best way to handle this
may be a simple message that is informative without wasting your visitors' time or
causing some unexpected behavior.
Assuming the browser is compatible we generate a map by creating an instance of the
class GMap2. The class defines a Google Map, and we can request an instance of that
class with a single statement:
map = new GMap2(document.getElementById("map_container"));
From the API Reference:
class GMap2 - Instantiate class GMap2 in order to create a map. This is the
central class in the API. Everything else is auxiliary.
Creates a new map inside of the given HTML container, which is typically a DIV
element. If no set of map types is given in the optional argument opts.mapTypes, the
default set G_DEFAULT_MAP_TYPES is used. If no size is given in the optional
argument opts.size, then the size of the container is used. If opts.size is given, then the
container element of the map is resized accordingly. See class GMapOptions.
You can safely ignore the discussion of optional arguments. In the absence of these
options sensible defaults will be used.
From the statement above:
map, which is the target of the assignment, is a variable which going forward will be a
reference to the map object created with this statement. We will manipulate this object
throughout the execution of the script to modify the map that appears on the page.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
There is also "map_container", which is the structural element of the page that will
contain our map. We saw this div when we looked at our XHTML file.
Note the use of the HTML DOM in the statement. Though our use of the XML DOM
with the KML files containing our Placemark data will be a little more extensive, what
we do with the HTML DOM will not be much more complicated than what we see here.
We have already discussed the method getElementsByTagName() when we looked at the
XML DOM. getElementById() is similar. We simply pass the method the unique name of
one of the id attributes included on the page to target the named container. Because all id
names are unique we can ignore the nested structure of the document and relationship
among elements when using getElementById. Technically the method returns a reference
to the first object with the named id, but there should be only one.
In the HTML DOM, the document object represents the entire page. So,
document.getElementById("map")
returns a reference to the first container with the id "map" anywhere on the page.
Adding standard controls to our map is just as easy thanks to the API.
map.addControl(new GLargeMapControl());
This statement adds the built-in large pan and zoom control. This the standard control
which typically appears along the left side of a Google Map and allows the user to select
the zoom level of the map either by incrementally increasing or decreasing the level or
jumping directly to the desired resolution utilizing a slider. The control also allows
visitors to pan the map in any direction.
The statement instructs the API to create a new GLargeMapControl() object and then add
the control to our map object.
Alternatively we could have opted for the equally common smaller control with the
statement,
map.addControl(new GSmallMapControl());
which offers much the same functionality but lacks the slider. The advantage is that the
control takes up significantly less space. This may be especially important for smaller
maps. The choice is yours.
Next we'll add a type control which allows visitors to switch between the three primary
map views, 'Map', 'Satellite', and 'Hybrid':
map.addControl(new GMapTypeControl());
This is functionality that most users appreciate and it does seem appropriate for our map
of photos. Map view is often the least cluttered of the three, and so the least distracting,
and the easiest to navigate. Satellite view on the other hand may help users better
understand the context of our photos. Hybrid view combines the two so that we can have
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
the satellite imagery but still find our way around the map with street names and other
important indicators.
It is possible to implement your own controls by taking advantage of several classes
Google makes available via the API for enabling and disabling standard overlay
information and toggling between map types. You may have a good reason for doing this,
and if so I don't want to discourage you. I do want to say however, that unless you have
cause to do something else, keeping the standard controls is recommended. Chances are
good that your visitors will be familiar with the standard controls and replacing them just
for the sake of being different is unnecessarily disorienting for users. Interface
consistency should be one of the primary goals of any developer. Keep in mind that your
map is essentially an instance of the Google Maps application. The more consistent we
all are, the more comfortable our visitors will be with our collective maps.
We've created a map (an instance of the GMap2 class), specified where to place the map
on the page, and we've added some controls. Before we can expect the Google API to be
able to generate a map, we need to tell it what to display, i.e. what location to show us.
We do this by setting the center point of the map and defining an initial zoom level.
Taken together, a center point, zoom level, and the size of the map (determined by the
height and width attributes of the 'map' div on our XHTML page), completely defines the
map that we see. A better way to think about an interactive Google Map might be to
imagine it as a dynamic window offering a view of a potentially much larger map of the
world. We can change the resolution of that view by adjusting the zoom level, or adjust
our vantage point by panning our view of the map.
The API provides the function setCenter() to set the position of the map.
From the reference:
setCenter
Sets the map view to the given center. Optionally, also sets zoom level and map
type. The map type must be known to the map. See the constructor, and the
method addMapType(). This method must be called first after construction to
set the initial state of the map. It is an error to call other operations on the map
after construction.
Do not overlook this line from that description:
This method must be called first after construction to set the initial state of the map.
map.setCenter(initial_center, initial_zoom);
This statement, from setup_map() sets the center of our map object.
setCenter must be provided a point and a zoom level. Technically the zoom level is
optional, but it's one of those optional arguments that you will specify most of the time.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Generally a point is a coordinate pair, i.e. standard latitude and longitude values. When
working with the Google Maps API, a coordinate pair is represented by a GLatLng
object.
From the API reference:
class GLatLng
GLatLng is a point in geographical coordinates longitude and latitude.
Notice that although usual map projections associate longitude with the x-coordinate of
the map, and latitude with the y-coordinate, the latitude cooridnate is always written first,
followed by the longitude, as it is custom in cartography.
Notice also that you cannot modify the coordinates of a GLatLng. If you want to compute
another point, you have to create a new one.
When working with GLatLng objects be very careful about the order of the values in the
pair. The reference tells us that the latitude must always be written first. Also notice that
the latitude and longitude must be specified in decimal degrees, as opposed to degrees,
minutes, and seconds. We have already taken care of converting the coordinate metadata
from our photos to the proper format in the first part of the project.
The second argument in the call to setCenter above is the zoom level. Google Maps
allows for a range of zoom levels. The higher the integer value the greater the amount of
detail (the higher the resolution) of the map. Of course higher resolution comes at the
expense of field of view. In other words, as we make the map larger, we get a more
detailed image of a smaller area. This correctly implies that smaller zoom level values
(lower integer values) present a wider field of view (more of the Earth is visible on the
map) but less detail (any specific area is smaller in terms of the number of pixels it
occupies).
The smallest zoom level available is 0, which displays a map of the entire world.
At a zoom level of 4 we can fit all of (Western) Europe on a map roughly 800px wide by
500px tall:
http://maps.google.com/?ie=UTF8&ll=47.279229,21.884766&spn=30.453577,72.246094&z=4&om=1
Increasing the zoom level to 6, adjusts the resolution such that France occupies nearly the
entire map:
http://maps.google.com/?ie=UTF8&om=1&ll=46.800059,4.130859&spn=7.671813,18.061523&z=6
and at 12 we have a map just larger than the city of Paris in France:
http://maps.google.com/?ie=UTF8&om=1&ll=48.856358,2.350731&spn=0.115203,0.282211&z=12
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
There is one issue about zoom level that we want to be careful to remember. Though 0
consistently represents the low end of the scale, always producing a very wide world
map, the high end is less reliable. In an urban area, for example the city of Paris, high
zoom levels are likely to be useful because at this level we can clearly distinguish
between individual streets, and even buildings and landmarks, like this satellite map of
the Eiffel Tower in Paris at zoom level 17.
http://maps.google.com/maps?f=q&hl=en&geocode=&q=&ie=UTF8&ll=48.858278,2.294705&spn=0.0036,0.008819&t=k&z=17&om=1
On the other hand, there are many areas of the planet where high zoom levels will result
in a map displaying nothing of any interest. This issue is especially problematic with
Satellite maps. The satellite imagery available via Google Maps is fairly inconsistent and
somewhat unpredictable at high zoom levels. The problem is that Google simply does not
have high resolution satellite imagery covering the entire planet. Where no images exist
instead of a map you will see the message 'We are sorry, but we don't have imagery at
this zoom level for this region'.
Your only choice is to move to a different region, or reduce the zoom level until you
reach a point where a lower resolution image is available. We need to be aware of these
issues when working with Google Maps or our visitors may find themselves staring at a
broken looking page.
In some cases, adding a feature to our map is as simple as invoking a function from the
API with a single statement, as is the case with the next line from our setup_map
function.
map.enableDoubleClickZoom();
This does what you might guess from the name. With this statement included among our
Javascript code double clicking on the map will increase the zoom by one integer level,
while centering the map on the position clicked. Holding the Control key while double-
clicking will decrease the zoom level. Without this statement, double-clicking the map
centers the map without affecting the zoom level. This feature is disabled for all maps by
default in the API, so if you would rather disable the 'double click zoom' feature, simply
comment out this line in the source file or remove it entirely.
At this point we've defined our initial map. It is complete except that there are no
markers. There are no icons indicating the location of the markers, no info windows with
descriptive text, thumbnails, and links to our photo gallery attached to the non-existent
markers. In fact there is nothing linking our photos to the map whatsoever. This is no
small omission. We had better get started on customizing our rather generic map.
Still in the setup_map function, we define all of the custom icons we'll use in our project.
Icons (GIcon) are very visible components on the map.
Icons are the symbols that represent markers at a particular point on the map but you
should think of the marker (GMarker) as the primary object. It is this object which will
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
represent each of our photos. The marker includes an icon (GIcon) described above, a
point (GPoint) which describes where to place the marker, and optionally an info window
(GInfoWindow) which is an area of content containing descriptive information about the
marker displayed when it is clicked. It is not uncommon for people to confuse points and
markers either because they do not understand the distinction or because of simple
carelessness, but the two are not interchangeable. We'll discuss markers later. Here we're
defining the icons we'll use so that later we can refer to them by name.
Icons are a required component of markers but it is not necessary to create custom icons.
If we don't supply a custom icon then Google Maps will use a default.
Why then go through the bother of creating custom icons at all? There is no single answer
to that question. In fact it's perfectly acceptable to decide to use the defaults. Someone at
Google has taken the time to design icons that work quite well, and it would be a mistake
to waste your time and effort creating icons that aren't as nice. But there are a number of
common reasons why you might want to consider creating your own, and why I have
decided to include custom icons with this project.
Branding and identification of markers as belonging to a specific application
or set.
It's possible for a Google map to include not only your markers but also
markers from Google (e.g. search results), and even third party applications.
The term 'Mashup' has been coined to describe an application that combines
data from multiple sources to create what is in some sense a completely new
application. Mashups can be much more than the sum of their collected data
sources. Custom icons allow users to distinguish markers related to your data
from all of the others.
Custom markers can communicate more information than the default icon.
Using a default icon tells a visitor where a marker is located but not much
else. With custom icons you can vary the size, color, and even create a
number of entirely different icon styles to indicate that the icons represent
different categories of data or to communicate information about the status of
a marker. For example a weather application may use several different icons
to represent possible weather conditions, e.g. the weather for a particular
location may be sunny, raining, overcast, warm, cold, or even a combination
of these conditions, maybe sunny but cold. The developer may choose to
vary the size of the icons to indicate the severity or intensity of the weather
pattern. For example, an icon depicting a rain cloud might be enlarged to
indicate a storm and reduced in size to indicate a light rain. The same
weather map may use red colored icons to immediately warn users of
dangerous conditions.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
Size of icons influences visibility of markers on the map.
While large icons may be more noticeable, and small icons more likely to
blend into the background detail if there is not a lot of contrast between the
map and the icon, it is possible to fit more small icons than large in a given
area and resolution without overlap.
Icons which indicate general regions vs icons which mark a specific point on
the map.
Frequently icons may be used to indicate either a region of the map or a
specific place. Icons that represent a precise location should clearly indicate
that by attaching to the map at a specific point. It's less useful, maybe even
inappropriate, for an icon designating a region to appear to indicate a specific
location. We can make regional icons to resemble 'badges' which appear to
float over the map, while point specific icons can be made with lines, tails or
arrows that appear to extend down to the point of attachment, in much the
same way as Google's default icons.
Aesthetic sensibility.
Of all of these common reasons for using custom icons, this is the hardest to
justify. You may choose to use custom icons because you consider Google's
default icons ugly. That's fair enough, certainly taste is subjective. The
problem with this argument is that it is difficult to completely banish
Google's icons from your maps, even if you do choose to use custom icons
for your markers.
I've chosen to use several different custom icons for all of the reasons just discussed,
except for aesthetic sensibility. I like Google's default icon and wouldn't create a custom
icon, something that requires a nontrivial amount of time and effort, just to be different.
Let's briefly discuss the rationale for the icons we'll be using before we get to the
business of the code for creating the icons.
First, let's quickly review the concept of clustering. We've described what clustering is
and its advantages. Because the topic has already been discussed I'll just remind you that
clustering is a way of replacing multiple markers with one representing the group when
the resolution of the map (i.e. the zoom level) and the proximity of the markers would
result in overlap such that it would not be possible to distinguish any one from the others.
Let's say that at every possible zoom level we want to guide visitors toward our photos.
At the lowest zoom levels a visitor will be looking at large geographical areas condensed
within a small amount of space in terms of display size. Entire countries are reduced to
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
the size of a small number of pixels. At these levels even just two markers representing
photos taken literally thousands of miles away from each other may overlap. A typical
collection of photos may include hundreds of photos or more with large groupings of
them appearing in the same relatively small geographical areas. For example, the
majority of the photos included in the gallery accompanying this tutorial were taken in
and around Boston, Massachusetts, USA. It would be ineffective to display markers for
these photos at many of the lowest zoom levels. Instead we'll create an icon to indicate
areas on the map where photos are available at higher zoom levels. By displaying
markers attached to regions appropriate for the current zoom level of the map, we avoid
the issue of overlapping markers and the performance issues that would result from trying
to display a world's worth of photos in a single view. The details of how to do this are
discussed in the comments included with the source code.
The first type of icon we want to create is a regional icon. Depending on the zoom level
we will draw a marker with this icon centered on a country, state/province, or city, where
we have at least one photo in our collection. You may remember that we created a KML
file matching each of these regions. We will rely on these KML files to create our
regional markers. For example for the lowest few zoom levels, let's say levels 0 - 2, we
can distinguish between countries but not smaller regions. At these zoom levels our
regional icons will indicate countries where we have at least one photo. At higher zoom
levels the same icons will be used with markers to indicate states and then, as the level
increases, eventually cities where we have photos to display on the map.
At intermediate zoom levels the resolution is such that there is a reasonable amount of
separation between small geographical areas so that we can add markers for individual
photos and expect that many of the icons will be visible without overlap and, for any one
view, we will not have so many markers that we overwhelm the map. It may be true that
we have thousands of photos but many of the corresponding markers will fall outside the
bounds of the view. However, at these levels it may be that we have a number of images
appearing in the same small area of the map. In this case we include only a single marker
for one of the images, and use an icon to not only indicate the location of a specific
photo, but also to let visitors know that there are additional icons which are currently
obstructed by this one.
Where we can clearly distinguish between the icons for all of our markers, we will use a
third custom icon that simply indicates the location of a particular photo. At the highest
zoom levels this is the icon we will use for all of our markers.
Though we have described only three distinct styles we need to define one more type. So
that we can include markers for as many photos as possible at intermediate zoom levels,
we will need two differently sized icons—one for the highest zoom levels and a smaller
one for intermediate levels.
Now we can discuss how we will create these icon styles. This is only intended to be an
overview, for the full details please refer to the Javascript file accompanying this tutorial.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
From the API reference:
class GIcon
An icon specifies the images used to display a GMarker on the map. For
browser compatibility reasons, specifying an icon is actually quite complex.
Note that you can use the default Maps icon G_DEFAULT_ICON if you don't
want to specify your own.
There are quite a few properties to consider when it comes to creating a new icon. All of
these properties are not required and in fact we do not use all of them in the tutorial.
Refer to the API Reference for the full details. We will limit ourselves to the following
list of properties: image, shadow, iconSize, iconAnchor, and infoWindowAnchor.
To create a custom icon we create a new instance of the GIcon class
icon = new GIcon();
The image property specifies a URL referencing a file used as the foreground image.
photo_icon_large_image = "http://robreed.net/maps_tutorial/images/photo_icon_large.png";
The shadow property specifies a URL referencing a file used as a shadow image for this
icon. The shadow image should be based on the foreground image of course. I'll have
more to say about the shadow at the end of the list of properties.
photo_icon_large_shadow = "http://robreed.net/maps_tutorial/images/photo_shadow_large.png";
iconSize is the size in pixels of the foreground image, listed as (width, height)
photo_large.iconSize = new GSize(32, 34);
shadowSize is the size in pixels of the shadow image, also listed as (width, height)
photo_large.shadowSize = new GSize(56, 32);
iconAnchor is:
The pixel coordinate relative to the top left corner of the image at which this icon is
anchored to the map. (This description is taken from the API reference)
icon.iconAnchor = new GPoint(6, 20);
infoWindowAnchor is:
The pixel coordinate relative to the top left corner of the image at which the info window
is anchored to the icon. (This description is taken from the API reference)
icon.infoWindowAnchor = new GPoint(5, 1);
We create a new instance of the GIcon class and define all of these properties for each of
the following custom icon styles.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
regional_icon = new GIcon();
photo_large = new GIcon();
photo_small = new GIcon();
photo_bunch = new GIcon();
Before we move on, a couple of notes about the icon foreground and shadow images.
The foreground image should be of reasonable size. Google's own default image is
approx 32px high by 20 pixels wide. We've already discussed the tradeoffs involved in
creating larger versus smaller icons.
The shadow image is derived from the foreground image. Using an image editing
application of your choice (I used Adobe's Photoshop), the steps are as follows:
a. Copy the foreground image to a new file.
b. Fill the shape of the object so that it's black. The icons included in the
project started out as Adobe Illustrator files, which I opened in Photoshop.
Once in Photoshop I could select the object and set the fill and outline
colors to black. If you have another type of image you may need to use a
selection tool to grab the shape and set the fill that way.
c. Shear the shape at a 45 degree angle. (Note that shearing is not the same as
rotating. Shearing the image essentially stretches it at the specified angle
rather than turning it around a fixed point. It's the shearing effect that gives
it the look of a shadow.)
d. Scale the image to half its original height without adjusting the width.
(Don't do a proportional scale.)
e. Blur the image. In Photoshop this means applying a blur filter. Whatever is
identified in your application as a standard blur should work fine.
f. Finally, adjust the opacity of the image to lighten it a bit.
g. Save the image as a transparent png.
After defining all of the icons, we're essentially finished setting up the map itself. The last
statement of the setup_map() function calls setup_markers() which controls the rest of the
execution of the script. In setup_markers() we do the following:
1. Download from the server the KML files generated in the first part of the
tutorial which contain all of the data about our photos. To do this we take
advantage of the function GDownloadUrl() from the Google Maps API.
This is an important function for us and its use is described at length in the
comments of the sourcecode.
2. After parsing the KML structure from the data files using a parse method,
again from the API, we create a number of NodeLists, which are objects
that mimic lists of nodes from the DOM. I want to emphasize that these
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
aren't lists in the traditional sense. A NodeList is a particular type of object
which represents an ordered collection of nodes (not an array of nodes).
This distinction may seem subtle, but it's not. For example, virtually all of
the array object methods that you may be used to using aren't available for
NodeList objects. Still, we can loop through these NodeLists and create
markers for each of the <Placemark> elements from the original KML files
where each Placemark corresponds to one of our photos.
3. We push all of these markers onto one or more arrays where they're
collected until we're done processing all of the nodes from the KML
structure.
4. Finally, we pass these arrays to a number of marker managers
(GMarkerManager), which are objects the API makes available to us to
control display of collections of markers based on the bounds and zoom
level of the map.
Marker Managers The marker managers automatically remove markers that fall outside of the bounds of the
view. Without the marker manager, all of the markers, including those that can't be seen,
are added to the map. This adds to the amount of work the application must do but isn't
useful. Alternatively, we could accomplish the same thing by determining the bounds of
the map and checking that each marker falls within the view before adding it. We'd need
to repeat this every time the map was moved or the zoom level increased or decreased.
The marker managers handle this for us.
Another advantage is that we can define a number of marker managers and assign
different collections of markers to each. For each marker manager we set a zoom range
over which it is active; that is to say, levels at which it adds and removes all of the
markers it's responsible for from the map, subject to the bounds of the view as just
described. We can set these marker managers up to accomplish clustering. As we move
from low to higher zoom levels we can enable different managers to display increasingly
more of our markers so that we're never overloading the map, but always representing as
many of our photos as can be accommodated at the current zoom level.
Though we've described the setup_map function here, I'll refer you to the source code for
detailed discussion of the rest of the project. It simply makes more sense to structure the
discussion as the source code is written. The easiest way to handle that is in the source
file itself. Certainly don't be intimidated by the source. It is all explained very explicitly.
In fact, because the file is so heavily commented, I'm including a duplicate
maps_tutorial.js that omits the commenting so that those of you who feel that the
narration is distracting can focus on the code itself.
This article is available in its entirety with downloadable code files online at
http://www.packtpub.com/article/Google-Earth-Google-Maps-and-Your-Photos-a-Tutorial-Part-I.
This means we've come to the end of the tutorial, except that you must read through the
source file to come to the end of the story of the javascript portion of the project. If your
Google Map works, congratulations. If not, keep at it. When it comes to programming,
persistence is a virtue. Review those portions of the tutorial that you may not have
understood completely, or double-check your source file looking for any small mistake.
As has already been mentioned, Firefox's Error Console should help point you in the right
direction.
Once you get the project working, it will only take a few minutes to create a map of your
geotagged photos going forward. It really is something that is valuable on its own and
potentially the beginning of any number of other more sophisticated projects.
Google Maps has been a fantastically successful application for Google and in
recognition of this, the amount of time and effort they continue to invest is only
increasing. Recently the API has gotten radically better. They've added their geocoder,
which we've used in this project, and expanded it to reach literally billions of new people.
Moreover, they're improving their own applications based on the API. For example,
they've recently launched My Maps, which is a simple web-based interface for
customizing a Google Map with information including photos, markers, routes, etc. And
they're doing everything they can to encourage independent developers like us.
Literally, from the time I started writing this tutorial to the time it was completed, it's
become possible to do more with Google Maps. One of the best places to find out about
improvements to Google Maps and the Maps API is the Official Google Maps API Blog
at http://googlemapsapi.blogspot.com/
Whether this project we've put together is everything you want to do with Google maps
or just the beginning of something bigger, I hope this tutorial helps you to enjoy your
photos.
Books from Packt
Packt will be publishing the following books over the next two months:
PHP Web 2.0 Mashup Projects: August, 2007
Create practical mashups in PHP grabbing and mixing data from Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo!, Last.fm, and 411Sync.com www.PacktPub.com/php-web-20-mashups/book
Learning PHP Data Objects: August, 2007
A Beginner's Guide to PHP Data Objects, Database Connection Abstraction Library for PHP 5 www.PacktPub.com/Learning-PHP-Data-Objects-Open-Source/book
Professional Plone Development: August, 2007 Building robust content-centric web applications with open-source Plone 3 CMS www.PacktPub.com/Professional-Plone-web-applications-CMS/book
Programming Microsoft Dynamics NAV: September, 2007
Create, modify, and maintain applications in NAV 5.0, the latest version of the ERP application formerly known as Navision
www.PacktPub.com/Microsoft-.NET-Dynamics-NAV-5.0-ERP-Navision/book
SOA and WS-BPEL: August, 2007 Composing Service-Oriented Architecture Solutions with PHP and Open-Source ActiveBPEL www.PacktPub.com/SOA-WS-BPEL-PHP-Open-Source-ActiveBPEL/book
Java EE 5 Development using GlassFish Application Server: September, 2007 The complete guide to installing and configuring the GlassFish Application Server and developing Java EE 5 applications to be deployed to
this server www.PacktPub.com/Java-EE-5-GlassFish-Application-Servers/book
Mastering OpenLDAP: August, 2007 Install, Configure, Build, and Integrate Secure Directory Services with OpenLDAP server in a networked environment www.PacktPub.com/OpenLDAP-Developers-Server-Open-Source-Linux/book
For more information, visit: www.PacktPub.com.
OSWorkflow: A guide for Java developers and architects to integrating open-source Business Process Management: August, 2007 Get your workflow up and running with this step-by-step guide authored by an active developer of the OSWorkflow project with real-world examples www.PacktPub.com/OSWorkflow-Java-open-source-Business-Process-Management/book
How to get a free book
We are happy to supply copies of our books for review purposes. To qualify, you need to
be:
A blogger with your own blog site who would like to read the book and then
review it/recommend it on their blog
A reviewer for a magazine or popular and relevant website with a reasonable
prospect of a review being published
An academic or trainer considering the title for adoption on a course you are
teaching. You will need to write to us from a valid academic e-mail address
and include a postal address to an academic institution. You will need to
provide information about the course, including title and the number of
students. Out of courtesy, we may ask applicants to write book reviews for
us.
Email review copy requests to: [email protected]
If you don't qualify for a free copy based on these criteria, then we are willing to consider
exchanging a free book for an original article written by you that we can publish on
Packtpub.com. Articles should be about 1500 words long, and be a technical how-to or
case study that would be of interest to other Packt readers.
All submitted articles must be original, not having been published before,
and not under consideration for publication elsewhere
All articles will be edited as necessary for content, style, clarity, grammar,
and spelling
Articles once submitted become the property of Packt Publishing
Email your ideas to us at the address above.