Sunday, July 03, 2005

GeoURL To Google Maps using the Official API

This morning I didn't really know what a GeoURL was, I've seen the button badge on a few blogs but I didn't get as far as clicking on them. It turns out that getting a "GeoURL" is really easy, all you need is the longitude and latitude of the blogs location, you can get this from multimap and the like, and you then just insert a couple of metatags in the head of your webpage and register with GeoURL (they even give you the HTML for the button badges). In my case the metatags are:


<meta name="geo.position" content="51.4595;-2.6018" />
<meta name="ICBM" content="51.4595, -2.6018" />
<meta name="DC.title" content="Mark McLaren's Weblog" />

This is swell you can now go to GeoURL and see what other blogs are registered in your area. One very sexy application of this is to combine this data with Google Maps (UK and US maps only at the moment) to get a visual representation of what blogs are in my vicinity. Leigh Dodds, from Bath [howdy neighbour], did this using the unofficial myGmaps web service. See Leigh's app here

Now as anybody who knows me will tell you, I am a good boy ;-> so when I saw that those clever chaps at Google had realised an official Google Maps API I just had to see what I could do with it. I thought why not try and use it to emulate Leigh's clever little application and blimey, I only went and got it working!!!!

Some interesting points I found along the way, the Google API requires you to sign up for an API key with your domain name in order to use it. It looks to me that this API key is actually verified in the client side JavaScript because in order to get my Tomcat server working I had to specify the domain localhost:8080 (API key for localhost:8080 shown in the example code below, I hope I'm not breaking any rules). The live example uses another API key obtained specifically for use on this blogs server (including the application directory). Out of interest, I did try to look at the Google JavaScript but anyone would think they were trying to obfuscate it or something (strange for a company that are starting to embrace the Open Source culture, see: Google code).

The official API uses AJAX technology to obtain the XML and process it. Due to security concerns the XML that the JavaScript accesses must be located on the same host as the JavaScript page. In order to obtain the GeoURL RSS feed that I need to use I needed another JSP page that downloads this feed on my behalf so that it appears local for the JavaScript's benefit.

I use Firefox browser but I recognise that most people would want this to work in IE (I recognise it but still don't understand why!!). The GeoURL RSS stores two of its key elements (longitude and latitude) with a special GeoURL XML namespace, as you would expect as these elements are currently not part of the RSS specification. I found that I had to do some browser detection in my JavaScript in order to get the namespace stuff working. This is because IE does not support the getElementsTagnameNS method and Firefox doesn't support the way IE supports obtaining tags with namespaces (no surprise there as the IE method looks just plain wrong).

One final point is I have learnt how to spell longitude, I’d always previously thought the word was longtitude (you live and learn!).

Access the standalone version here to see a live working example showing the blogs in my vicinty.

Here is the very simple GeoURL RSS feed proxying JSP needed so that the JavaScript can load the XML from a local server:


<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %><%--
--%>
<%@ page contentType="text/xml; charset=UTF-8"%><%--
--%>
<c:import url="http://geourl.org/near/?p=http://cse-mjmcl.cse.bris.ac.uk/blog;format=rss10"/>

Here is the page containing the JavaScript that uses the Google Maps API to do the work (API key shown is for localhost:8080):


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://maps.google.com/maps?file=api&amp;v=1&amp;key=ABQIAAAA4Wxrd1ZmQfRHvggZWM0QkxTwM0brOpm-All5BF6PoaKBxRWWERTxZC7TxHvaaZq75azqC6aFU4f4gA" type="text/javascript">
</script>
<script type="text/javascript">
//<![CDATA[

function onLoad() {
var ua = navigator.userAgent;
var isFirefox = ( ua != null && ua.indexOf( "Firefox/" ) != -1 );
var isMSIE = ( ua != null && ua.indexOf( "MSIE" ) != -1 );
var request = GXmlHttp.create();
request.open("GET", "obtain_geourl_rss.jsp", true);
request.onreadystatechange = function()
{
if (request.readyState == 4)
{
var xmlDoc = request.responseXML;
var blogs = xmlDoc.documentElement.getElementsByTagName("item");
var results="";
// Get first set of co-ordinates to set the centre of the map.
var long1;
var lat1;
if (isMSIE)
{
long1=blogs[0].getElementsByTagName("geourl:longitude")[0].firstChild.data;
lat1=blogs[0].getElementsByTagName("geourl:latitude")[0].firstChild.data;
}
if (isFirefox)
{
long1=blogs[0].getElementsByTagNameNS("http://geourl.org/rss/module/","longitude")[0].firstChild.data;
lat1=blogs[0].getElementsByTagNameNS("http://geourl.org/rss/module/","latitude")[0].firstChild.data;
}
// Centre on the first item in the list
var map = new GMap(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.centerAndZoom(new GPoint(parseFloat(long1), parseFloat(lat1)), 4);

for (var i = 0;i < blogs.length;i++)
{
// Title
var title=blogs[i].getElementsByTagName("title")[0].firstChild.data;
// Link
var link=blogs[i].getElementsByTagName("link")[0].firstChild.data;

var long2;
var lat2;

if (isMSIE)
{
long2 = blogs[i].getElementsByTagName("geourl:longitude")[0].firstChild.data;
lat2 =blogs[i].getElementsByTagName("geourl:latitude")[0].firstChild.data;
}
if (isFirefox)
{
long2 =blogs[i].getElementsByTagNameNS("http://geourl.org/rss/module/","longitude")[0].firstChild.data;
lat2 =blogs[i].getElementsByTagNameNS("http://geourl.org/rss/module/","latitude")[0].firstChild.data;
}
var point = new GPoint(long2,lat2);
var marker = createMarker(point, "<b>"+title+"<\/b><p><a href="\""+link+"\">View Blog<\/a><\/p>");
map.addOverlay(marker);
}
}
}
request.send(null);
}

function createMarker(point, html)
{
var marker = new GMarker(point);
GEvent.addListener(marker, "click", function()
{
marker.openInfoWindowHtml(html);
}
);
return marker;
}
//]]>
</script>
<title></title>
</head>
<body onload="onLoad()">
<div id="map" style="width: 500px; height: 500px"></div>
</body>
</html>

10 comments:

Mark McLaren said...

Now you just need to make it reload the RSS when you scroll... :-)



(actually, if you do that and are willing to contribute your work to GeoURL then let me know so I can copy the javascript you come up with. :-) )





- ask
Note: Comment imported. Original by Ask Bjørn Hansen website: http://askask.com/ at 2005-07-04 07:26

Mark McLaren said...

Hi ask,





I’d be delighted to contribute anything to GeoURL that you would find useful. As regards the scrolling behaviour, it seems that this is likely to be very possible as the ability to track the centre of the map is part of the API see for example see link below:





Tracking the centre longitude and latitude of a Google Map





What I’d need to get the functionality you describe working is someway to query GeoURL by longitude and latitude rather than by URL. Is this possible at the moment? (Forgive my ignorance as I only started playing with this yesterday!)





Also another question is does the “dist�? parameter work with the RSS feed?


Note: Comment imported. Original by markmc website: http://cse-mjmcl.cse.bris.ac.uk/blog at 2005-07-04 10:30

Mark McLaren said...

Update:





I see from the source code of GeoURL in Near.pm that the RSS feed does support latitude and longitude queries.





I have a version of above working but it needs work, I've had to clear the map of all markers after a move event which is a little clumsy. This is necessary currently because without clearing the markers it really slows the browser down to a standstill.





Version 0.1




Note: Comment imported. Original by markmc website: http://cse-mjmcl.cse.bris.ac.uk/blog at 2005-07-04 22:23

Mark McLaren said...

Thanks, thanks, thanks! I've been struggling like you wouldn't believe to get the href tag correct in the java; I had no idea what I was doing. Thanks for your help!
Note: Comment imported. Original by Jeff website: http://northending.org at 2005-10-14 18:53

Mark McLaren said...

Hi, I'm trying to connect a php database with java query to the javascript part of google maps api on a html page...Any suggestion for a beginner in this field lik me???
Note: Comment imported. Original by carol at 2005-12-12 18:21

Mark McLaren said...

Hi Carol,



You seem a little confused. I'm not really sure what you mean by "PHP database". PHP is a scripting language and not a database. Do you mean MySQL?





Also the Google Maps API is entirely JavaScript.





Are you sure you need to use Java at all?





Maybe something like a tutorial showing you how to use PHP, MySQL and Google Maps is what you need. Such as Google Maps via PHP/Mysql Tutorial





I'd need a more accurate description of your problem to find a better solution.


Note: Comment imported. Original by markmc website: http://content.mark-mclaren.info/ at 2005-12-12 18:37

Mark McLaren said...

Hi Mark. I'm trying to use Mysql and Google Maps with JSP/Servlets. I'm new to this area and I'm badly stuck. Could you give me any pointers or even point me in the direction of some tutorials??

Thanks.
Note: Comment imported. Original by Stephen at 2006-03-09 17:22

Mark McLaren said...

Hi Stephen,



I don't know how far you have got so far but it sounds very intriguing.





Without knowing more about what you are doing specifically I would suggest you start by using JSTL. First I'd write a JSP that accessed my database and output the data in a suitable format (XML or JSON for example). See my Yet another Google Suggest clone for an example of how to use the JSTL SQL tag library (also see Shawn Bayern's JSTL Appendix A from Manning's JSTL in Action [PDF]).





Once you have a JSP producing the co-ordinates you need then you can start writing the Google Maps API JavaScript that you need. See this for an example of some JavaScript which dynamically calls a JSP (which in turn calls a remote RSS feed) GeoURL To Google Maps using the Official API: Part II.





If this is still unclear to you please explain your situation a little more to me and I'm sure I could help you further.




Note: Comment imported. Original by markmc website: http://cse-mjmcl.cse.bris.ac.uk/blog at 2006-03-09 20:00

Mark McLaren said...

For some reason the direct link to the JSTL PDF chapter is not working.



Access it here

instead!


Note: Comment imported. Original by markmc website: http://cse-mjmcl.cse.bris.ac.uk/blog at 2006-03-09 20:04

Mark McLaren said...

Thought you might find this interesting...I've been writing a JSP Taglibrary to provide full GoogleMaps capabilities with no scripting whatsoever. It includes synchronous and asynchronous event handling that can be handled by standard JavaBeans and/or Servlets & JSPs. There are online examples on my website, http://www.lamatek.com/GoogleMaps/
Note: Comment imported. Original by Anonymous website: http://www.lamatek.com/GoogleMaps/ at 2006-03-17 01:34