Adding GeoRSS to OpenLayers Vector Layer via jQuery

For a number of my OpenLayers projects I create a vector layer to hold markers and handle popups et al. I’ve found this more flexible than a marker layer, especially if you want to futz around with particular features later. I add a vector layer with a different vector type for each type of thing I might want to slap in there. Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Vector Marker Layer
var styleMap = new OpenLayers.StyleMap({
  fillOpacity: 1,
  pointRadius: 12
});
// images for vector marker layer
// 0=selected, 1=facility, 2=identify, 3=traffic
var lookup = {
  0: {externalGraphic: "image/home_marker.png", backgroundGraphic: "image/marker_shadow.png", backgroundXOffset: 0, backgroundYOffset: -7 },
  1: {externalGraphic: "image/facility_marker.png", backgroundGraphic: "image/marker_shadow.png", backgroundXOffset: 0, backgroundYOffset: -7 },
  2: {externalGraphic: "image/identify_marker.png", backgroundGraphic: "image/marker_shadow.png", backgroundXOffset: 0, backgroundYOffset: -7 },
  3: {externalGraphic: "image/traffic_marker.gif", backgroundGraphic: "image/marker_shadow.png", backgroundXOffset: 0, backgroundYOffset: -7 }
}
styleMap.addUniqueValueRules("default", "type", lookup);
markerLayer = new OpenLayers.Layer.Vector('Map Markers', {
  styleMap: styleMap, displayInLayerSwitcher: false
});

Then I have a generic function to add point features to the vector layer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
 * Add markers (vector) to the map.
 * Also removes popups and selects added feature.
 * @param {float} lon
 * @param {float} lat
 * @param featuretype:  the type of feature/marker (0=address,1=facility,2=identify)
 * @param label: the content to put in the popup
 * @param {boolean} clearFeatures: clear all other makers of same featuretype
 * @param {boolean} zoomToFeature: zoom to the added marker if not in map view/zoomed out too far
 * @param {boolean} selectFeature: select the feature, opening popup
 */
function addMarker(lon, lat, featuretype, label, clearFeatures, zoomToFeature, selectFeature) {
  // remove old features of same type if clearOthers is true
  if (clearFeatures) {
      feats = markerLayer.features;
      for(i = 0; i < feats.length; i++) {
          if (feats[i].attributes.type == featuretype) markerLayer.removeFeatures(feature);
      }
  }

  // Add new feature
  point = new OpenLayers.Geometry.Point(lon, lat);
  OpenLayers.Projection.transform(point, map.displayProjection, map.getProjectionObject());
  label = '<div>' + label + "</div>";
  label += '<br /><div><a href="#" onclick="zoomTo(' + point.x + ', ' + point.y + ', 8); return false">Zoom to Feature</a></div>';
  feature = new OpenLayers.Feature.Vector(point,
          {type: featuretype, label: label}
      );

  markerLayer.addFeatures(feature);

  // zoom to feature if zoomToFeature is true
  if (zoomToFeature) {
      if (!feature.onScreen() || map.getZoom() < 8) {
          zoomToLonLat (lon, lat, 8);
      }
  }

  // open feature popup if map width greater than 500 pixels (hides on portables)
  if (selectFeature &amp;&amp; $("#map").width() > 500 ) selectControl.select(feature);
}

Now let’s use jQuery to process the Yahoo Traffic GeoRSS feed and add the locations to the vector layer. When it comes to making AJAX requests and processing the results on the client side, I haven’t found anything easier or more intuitive than jQuery.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    // Add traffic to marker layer
$.ajax({
  type: "GET",
  url: "yahoo_traffic_proxy",
  dataType: "xml",
  success: function(xml) {
      $(xml).find('[nodeName=item]').each(function(){
          var lat = $(this).find("[nodeName=geo:lat]").text();
          var lon = $(this).find("[nodeName=geo:long]").text();
          var title = $(this).find('[nodeName=title]').text();
          var description = $(this).find('[nodeName=description]').text();
          addMarker(lon, lat, 3, "<strong>TRAFFIC/INCIDENT INFORMATION</strong><br />" + title + "<br />" + description, false, false, false);
      });
  }
});

And that’s it. Note to avoid the dread XSS error, you’ll need to proxy the GeoRSS feed. For each “item” in the RSS feed, we’re pulling out the location, the title, and the description, and adding the features to the vector layer on our map.

Like there’s ever fast traffic there.

One important thing to note. When using find in jQuery on XML, use:

1
var lat = $(this).find("[nodeName=geo:lat]").text();

And not:

1
var lat = $(this).find("geo//:lat").text();

Escaped strings in jQuery find for XML don’t work in Webkit based browsers, so you’d have to do something hacky like “geo//:lat, lat”. Use nodeName, and you’re golden.