Monday, July 04, 2005

GeoURL To Google Maps using the Official API: Part II

Previously, I showed how to display the blogs in your immediate vicinity using GeoURL and Google Maps with the Official Google Maps API. I received a comment following this from Ask Bjørn Hansen who runs the GeoURL site. Ask suggested that it would be really good if you could make it so that as you scroll around the map it automatically updates the display showing the blogs in that vicinity. I took this as a bit of a challenge (I occasionally like the odd challenge) and I like to play with AJAXy stuff at the moment with it being flavour of the month.

It is easy using the Google Map API to add an event listener to monitor map scrolling events and read off the longitude and latitude readings. There is even an example of the code needed to do this in the API documentation. After looking through some of the GeoURL source code I discovered that I could receive a GeoURL RSS feed based on a longitude/latitude pair. My first attempt fetched new RSS feeds after every "moveend" event, this initially appeared to be working until the browser slowly ground to a halt. The problem was that I had been adding more and more "markers", those little red icons, until it just became too much for the browser to handle.

The API documentation gives three methods for dealing with markers these are referred to as overlays in the API documentation (as they can be a icon marker or a series of points joined together). These are:


addOverlay(overlay)
# Adds the given overlay object (e.g., GMarker or GPolyline) to the map

removeOverlay(overlay)
# Removes the given overlay object from the map

clearOverlays()

So therefore, I can add an overlay, remove an overlay (if I had a reference to it) or clear all the overlays on the map.

I modified my code to add the clearOverlays() command before adding any new markers and this made the code work better. The problem now was that the markers would blink on and off as they were removed and re-added after every new RSS feed load. This was not very satisfactory.

What I needed to do was this, after a "moveend" event:

  1. Remove overlays that were not now inside the bounds of the visible map (called viewport in the API documentation)
  2. Only add overlays if they would be visible within the bounds of the visible map

Now there didn't appear to be a way to iterate through the existing overlays on a map page, at least not in the official API documentation. I can forgive this as Google Maps is only in Beta and I put it down to an accidental omission in their documentation. After looking at a Google Maps Hacking page I saw a reference to overlays being a property of the map object. I thought that must be the array containing all the overlays in the map. By guesswork and pure dumb luck I was able then to access the longitude and latitude values of each overlay using:


map.overlays[0].point.x
map.overlays[0].point.y

Now I can access the overlay objects, their associate co-ordinates and I can delete the overlays using removeOverlay(overlay) method. I can now remove the overlays that would be outside of the visible map.

Hey presto, it works...it only took about a half day of head scratching. The following is a link to the live example, it works but I'm sure it could probably be improved further.

Access the standalone version here

You can of course copy the static HTML from the above page, I have opted for a Creative Commons license for the code I produce on this site.

It required a modified JSP page to proxy the RSS feed so that the AJAX code could read the XML from a local source. This jsp will fetch a GeoURL RSS feed if called with a reference to an URL or a longitude and latitude pair (For reference: I currently use JSP on Tomcat 4 and I believe it would need to be modified to use the JSTL core_rt taglib on Tomcat 5).


<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %><%--

// http://geourl.org/near/?lat=51.4595&long=-2.6018;format=rss10

--%>
<%@ page contentType="text/xml; charset=UTF-8"%><%--
--%>
<c:choose><%--
--%>
<c:when test="${not empty param.url}"><%--
--%>
<c:set var="fetchurl">http://geourl.org/near/?p=<c:out value="${param.url}" />;format=rss10</c:set><%--
--%>
</c:when><%--
--%>
<c:otherwise><%--
--%>
<c:set var="long"><c:out value="${param.long}" default="-2.6018" /></c:set><%--
--%>
<c:set var="lat"><c:out value="${param.lat}" default="51.4595" /></c:set><%--
--%>
<c:set var="fetchurl">http://geourl.org/near/?lat=<c:out value="${lat}"/>&amp;long=<c:out value="${long}"/>;format=rss10</c:set><%--
--%>
</c:otherwise><%--
--%>
</c:choose><%--
--%>
<c:import url="${fetchurl}"/>

1 comments:

Mark McLaren said...

Thank you Mark.

This is _exactly_ what I've been looking for. Saved me half a day of head scratching!

Cheers.
Note: Comment imported. Original by Anonymous at 2006-03-07 03:20