Archive for July, 2012

WMS GetFeatureInfo spanning the dateline in OpenLayers

Friday, July 27th, 2012

If you’re using OpenLayers to draw a WMS layer and calling GetFeatureInfo, you’re probably having trouble when looking across the antimeridian, where 180° longitude becomes -180°. This is because OpenLayers sends a bounding box to the WMS server (I’m only dealing with Geoserver 2.1.4 at the moment, not sure on other systems) that includes coordinates beyond the normal limit. If centered over New Zealand it might send a bounding box stretching from 160° to 190°. If your data is in normal (-180->180) space Geoserver won’t find any of the data beyond 180 and if you convert OpenLayers to sending rationalized coordinates (160° to -170°) Geoserver will complain that the minX is greater than the maxX. So what are we to do?
The solution I have come up with is to trim the box you are sending to the server so that it doesn’t cross the dateline. depending on where you were clicking in my example you’d either send 160° to 180° or -180° to -170°. The trick is to work out which side of the dateline you clicked on and which side your view is based on. If your view had been centered on the Chatham Islands OpenLayers would see those same boundaries as -200° to -170°.

Starting from the OpenGeo code to query a wms layer using OpenLayers I added come calculation to trim the bounding box and shift the X and Y values (which are the point the user clicked relative to the top left of the bounding box) if the left boundary has been moved.'click', map, function (e) {

bbox = map.getExtent();
width = map.size.w;
clickX = e.xy.x;

//Start dateline solution
clickRatio = e.xy.x/map.size.w;
fullMapWidth = Math.abs(map.getMaxExtent().left) + Math.abs(map.getMaxExtent().right);
if (bbox.right > map.getMaxExtent().right)
datelineRatio = (map.getMaxExtent().right-bbox.left)/(bbox.right-bbox.left);
if(datelineRatio < clickRatio)//Click was far side of dateline, normal bbox would not find data
bbox.left = map.getMaxExtent().left;
bbox.right -= fullMapWidth;
clickX -= width * datelineRatio;

width = width * (1-datelineRatio);
} else if (bbox.left < map.getMaxExtent().left){
datelineRatio = (map.getMaxExtent().left-bbox.left)/(bbox.right-bbox.left);
if(datelineRatio > clickRatio)//Click was far side of dateline, normal bbox would not find data
bbox.right = map.getMaxExtent().right;
bbox.left += fullMapWidth;
width = width * datelineRatio;
//end dateline solution

var url = wfsPath
+ "?REQUEST=GetFeatureInfo"
+ "&EXCEPTIONS=application/vnd.ogc.se_xml"
+ "&BBOX=" + bbox.toBBOX()
+ "&X=" + Math.round(clickX)
+ "&Y=" + Math.round(e.xy.y)
+ "&INFO_FORMAT=text/html"
+ "&QUERY_LAYERS=" + wfsLayer
+ "&LAYERS=" + wfsLayer
+ "&SRS=EPSG:900913"
+ "&STYLES="
+ "&WIDTH=" + Math.round(width)
+ "&HEIGHT=" + map.size.h;,