Larsblog

Playing with the Google Maps API

Previous
Next

I sat down to try the Google Maps API yesterday, and came away very impressed by both it and the new AJAX style of web applications. Here is an introduction to the API, together with some musings on how it could be used with Topic Maps.

Using the API

The API is available for free, and you can use it to put maps onto web sites for free (provided the site is non-commercial). The way it works is that you use a script element to download the JavaScript code from Google. To do this you need to register and get a key from Google. This key is tied to your site URL, which is of course reported by the browser in the referrer header when the user's browser downloads the JavaScript.

Once this hurdle is passed, actually displaying a map with a zoom control on it is dead easy. In fact, the following would give you a nice map of London:

<!-- This loads the JavaScript code implementing the API -->
<script src="http://maps.google.com/maps?...">

<!-- This is where the map will be placed by the JavaScript -->
<div id="map" style="width: 700px; height: 650px"></div>

<script type="text/javascript">

// creating the map
var map = new GMap(document.getElementById("map"));
map.addControl(new GLargeMapControl());
map.centerAndZoom(new GPoint(-0.1, 51.5), 5);

</script>

That's it. That really is enough to give you a zoomable, draggable map of London. The GMap is a JavaScript class that basically implements all of the logic necessary. The GLargeMapControl is the overlaid zoom/navigate control on the upper left. There's also a smaller version if you prefer, and you can put in the satellite/map chooser, etc.

Of course, this isn't really that interesting. A link to Google Maps would accomplish the same thing more easily. What's more interesting is to put markers on the map. Again, this turns out to be dead easy. Just add the following to the script, below the map.centerAndZoom line:

map.addOverlay(new GMarker(new GPoint(-0.199642, 51.47405)));

The map now gets a nice red marker at the precise location of the famous White Horse pub in Parson's Green. As you scroll and move around, the marker will stay put. This is where it starts to get interesting, because once you have the coordinates of some places you can start putting them on the map. If you want, you can get even more fancy, and customize the icons (haven't gotten this to work yet), and also display information windows when the markers are clicked. (Actually, you can register events that do anything when they are clicked, but there's ready made functionality for the information windows.)

The code for registering information windows with layout etc is a bit more complex, but not much. Here is new code to replace the one-line snippet above with:

// helper function to add a pub to the map
function add_pub(x, y, popupid) {
  marker = new GMarker(new GPoint(x, y));
  marker.popupid = popupid; // register ID on object for later

  // register an event handler to open the window on click
  GEvent.addListener(map, 'click', marker_clicked);

  map.addOverlay(marker);
}

// event handler; opens info window for marker
function marker_clicked(marker) {
  // retrieve the element to show in the window
  element = document.getElementById(marker.popupid);

  // we can't pass this element in because it gets destroyed
  // once the window is closed, so we make a copy
  element = element.cloneNode(true); 

  // switch display from off to on
  element.style.display = ""; 

  // then open the window
  map.openInfoWindow(marker.getPoint(), element);
}

// having created the helper functions we can add our pub
add_pub(-0.199642, 51.47405, "white-horse");
</script>

<!-- This element is not displayed on the page, but get passed into
        the information window -->
<div style="display: none; font-family: Arial; font-size: 8pt; width: 350px" 
     id="white-horse">
<b>White Horse</b><br>
Famous pub, which is also a good restaurant. Wide beer selection,
upscale interior, good seating.
</div>

An example

Here is a working example, implemented with the code shown above. The markers show some of the most interesting places in London, but you need to click them to see what they are.

Building the data

So far we've only covered the functionality, but this only really becomes interesting once you have some data. So how to get that? How to find the coordinates of any given location? Well, to make the map center on London I started from Google's example, which focuses on Palo Alto, USA. Since the coordinates are longitude and latitude, one of them was easy. Zero longitude is Greenwich in eastern London (just visible on the far right of the map). Some quick trial and error (via southern Spain, northern Scotland, and the Channel) then led me to London.

This is a pretty cumbersome method, though. Another method is to extend the map interface a bit, so that you can go to a location and click on it to find the coordinates. This is pretty easy. Just add the following to your code, and you can cut and paste the coordinates from the popup.

// click to see where you are
GEvent.addListener(map, 'click', function(overlay, point) { 
  if (point) {
    alert('You clicked at: ' + point);
   }
});

However, even this is quite awkward. The easiest is to just use Google Maps and search for the name and street address (plus city name and country name) of the place you are looking for. You don't get to see the coordinates in the Google Maps interface (unfortunately), but you can go to http://maps.google.com/local?q=your+query+here&output=js. This gives you a very hard-to-read result, but searching for "<point" will find you the coordinates.

If you find this too awkward, here is a Python script you can use to extract the coordinates. Just give it the search string and the letter of the alternative you want, and it will spit it out for you. Here is an example of use:

[larsga@localhost tmp]$ python gxy.py "The Star, 6 Belgrave Mews West, London, UK" A
Longitude: -0.155352, latitude: 51.497988

JavaScript and AJAX

Playing around with this API, plus some recent development experiences, have really given me respect for both JavaScript and the recent wave of AJAX applications. To be frank, however, I think AJAX amounts to no more than the discovery that JavaScript is a real programming language, and that XML is the best way for it to get data from the server to work with.

I guess what is the most surprising for this is that it's taken so long to happen. After all, JavaScript has been with us for 10 years now, and XML for more than 7. Probably the fact that it was almost exclusively implemented in web browsers, that implementations were incompatible (and poor), and that most of the actual JavaScript code out there was of such crappy quality contributed a lot to this. And, not only was the code crappy, but what it did was mainly to annoy users. The only thing that's really changed is that it's now possible to write code that works in most of the browsers people actually use, that the JavaScript out there is a lot less annoying than it used to be, and that the perception of the language has changed. Which was about time, anyway.

I have to admit I was no quicker in the uptake here than most other developers. For me, the big turning point was playing around with the Google Maps API, and to some extent discovering that judicious use of simple JavaScript can do wonders for web applications. Having people like Robert Cerny tell me the obvious (JavaScript is a real programming language) also helped, of course.

Having said all this, one problem does remain, however. Debugging JavaScript is still a very unpleasant job. It's become easier than it was when scripts would just silently fail, but when you do something wrong (like adding the marker before the map.centerAndZoom call) it's pretty hard to work out what, exactly, you did wrong. If I use Google's example code to add a GIcon object to a marker I get the default icon, and it shows up in the wrong place. Nothing fails, but the marker winds up in the wrong place. Why is that? What's going on? I still don't know.

Topics on maps

One thing that is interesting to me about this is that it shows that creating a Google Maps integration with a Topic Maps product is dead easy. What you need is the located-in association type (which already has an Ontopia PSI) and two latitude and longitude occurrence types to capture the coordinates of specific places. If you want to be really fancy you can attach an marker-icon occurrence to the topic types as well, so that topics of different types can get different icons on the map.

The information about the White Horse pub used as an example above would then be encoded as follows in LTM:

[white-horse : pub = "White Horse"]
{white-horse, description, [[Famous pub, which is also a good
restaurant. Wide beer selection, upscale interior, good seating.]]}

{white-horse, geo:latitude, [[51.47405]]}
{white-horse, geo:longitude, [[-0.199642]]}
geo:located-in(white-horse : geo:containee, london : geo:container)

Given this, writing JSP (or whatever) that produces a Google Map showing all topics in a particular city is dead easy. In fact, it's how the map above was produced. I've created a topic map about beer which I use, among other things, to do research on beer-related places before travelling somewhere. I extended it with the longitude and latitude occurrence types, entered them for the places in London, and two simple tolog queries (one for the add_pub function calls, another for the popup divs) did the rest.

This could easily be productized into an OKS module that would let users specify a place topic and a zoom level (plus the desired map size, I guess) and it would then produce their nice Google Map, with icons, popup windows, and links back into the Topic Maps application. All they'd need to do is use the geography PSIs in their own topic map. And, probably, buy a Google Maps key, as anyone purchasing such an OKS module would probably be a commercial site. Which, I guess, only shows the wisdom of the Google Maps creators in building such a usable and powerful API, and then making it available to non-commercial users. Hats off to them for having done a fantastic job on this.







Comments

Robert Cerny - 2005-12-04 20:36:22

I am glad i could be of some help by pointing you to a place in the universe of symbolic information that you might have missed otherwise. Who knows which other treasures are around? Have you heard of Perspex (http://www.bookofparagon.com)?

I might add that there is, IMHO, a better way (at least as good :-) of transporting structured data between web server and client, and that is JSON. The JavaScript Object Notation has been around approx. as long as XML, but has gone unnoticed for various reasons, most of them can be reduced to a simple preference of the human perceptual system of acronyms starting with the letter X over those starting with the letter J or any other letter in the years 1998 - 2010. One of the advantages of JSON over XML is that it has a better markup/content ratio.

Parsing JSON in the browser is as simple as evaluating an assignment statement and then the data is ready to be messed with, e.g. you can augment the new born object with methods (that's what i do). Producing it on the server might be a little bit more of a challenge, but there is many libraries that support that.

One more thing: In respect to debugging JavaScript you need to look into Venkman for Firefox/Mozilla. That makes it a lot more comfortable and includes a Profiler. I wish i could just attach a Mini-TopicMap to give you the most important facts! I think we are not too far from that :-)

Lars Marius Garshol - 2005-12-05 09:42:48

Perspex was new to me. I'll have a look.

As far as JSON goes I think that you're probably right that it's superior as a solution for the "I'm writing JavaScript for this application and want the data from the server". On the other hand, I think XML has an advantage in the more general case in that it can be used by any client, as opposed to JavaScript clients only for JSON.

I'll remember your acronym design rule, though. :)

Venkman looks like it might be very helpful. I'll try that next time I'm doing JavaScript stuff.

Paul - 2006-02-15 23:53:03

This is a very simple to use script for a novice like myself but doesnt seem to work (when you click on markers to expand the info bubble) on IE. Needs a small tweek obviously. Cheers

Manish Sohaney - 2006-12-15 20:52:44

Error out when clicking on the marker on the map.

Lars Marius - 2006-12-30 20:16:34

I've now fixed the problem with the markers. It turns out I've used parts of the Google Maps API that were not public, and Google has changed them so that they stopped working. This was to be expected, of course. I've fixed it now so that I'm using only public parts of the API.

Robert - 2008-02-18 12:18:38

Your code is very simple but I think that you shoud provide multiple custom markers too.

Pete - 2008-03-05 22:38:46

When using this API on IE6/7, the <div> layout is mutilated. Any ideas on how to get around this? (I suspect it's a microsoft issue, as it often is...) ;>

Bill - 2009-03-31 01:31:30

Pete... did you ever get feedback on this?

I have the same issue, and it's annoying as hell... I've got an overlay... and in Firefox the overlay matches perfectly, but in IE, the overlay is the right size, but the map is larger, and so the overlay doesn't fit right...

sigh

Add a comment

Name required
Email optional, not published
URL optional, published
Comment
Spam don't check this if you want to be posted
Not spam do check this if you want to be posted

Last comments
RSS

Steven on A sudoku solver in P...

Jibrin Usman..B on What is an informati...

Gnurf on 7 tips on writing cl...

John on Bayesian identity re...

john on Bayesian identity re...

Khaizarani Ibrahým bako on What is an informati...

Bruce on Equivalence classes

Stig on Bitcoin: promises an...

Jon Bjerkelien on The curse of NOARK

Lars Marius on Impressions from Str...