3
votes

I am trying to render WMS layer on Google Maps and its working fine except getfeatureinfo event. When I open Geoserver and try to click on WMS featues I can get the feature info. But in my page I can see empty popup. I think the problem is with Google Maps Projection.

Code:

function init(){
    var gmap = new OpenLayers.Layer.Google("Google Streets", {
    visibility: false});
    var options = {
        controls : [],
        units : "m",
        numZoomLevels : 22,
        maxResolution : 156543.0339,
        projection: new OpenLayers.Projection("EPSG:900913"),
        displayProjection: new OpenLayers.Projection("EPSG:4326"),
        maxExtent : new OpenLayers.Bounds(-20037508.34, -20037508.34,
                20037508.34, 20037508.34)
    };
    var map = new OpenLayers.Map('map', options);
    var layer1 = new OpenLayers.Layer.WMS("Layer1 - Tiled",      
     "http://localhost:8090/geoserver/Layers/wms", {
                layers : "Layer1",
                transparent : "true",
                format : "image/png",
                srs : 'EPSG:4326', 
                zoomOffset : 3,
            }, {
                isBaseLayer : false
            });
    map.addLayer(gmap);
    map.addLayer(layer1);
    info = new OpenLayers.Control.WMSGetFeatureInfo({
        url: 'http://localhost:8090/geoserver/Layers/wms', 
        title: 'Identify features by clicking',
        layers: [layer1],
        infoFormat: 'text/html',
        queryVisible: true,
        eventListeners: {
            getfeatureinfo: function(event) {
                map.addPopup(new OpenLayers.Popup.FramedCloud(
                    "chicken", 
                    map.getLonLatFromPixel(event.xy),
                    null,
                    event.text,
                    null,
                    true
                ));
            }
        }
    });
    map.addControl(info);
    info.activate();
    map.setCenter(new OpenLayers.LonLat(-104.949, 40.924).transform(
    new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()),5);
     map.addControl(new OpenLayers.Control.Navigation());
}

<body onload="init()">
 <div style="visibility: visible; height: 100%;" id="map"></div>
</body>

Is there any way to getfeatureinfo in case of google maps (EPSG:900913) and WMS layer (EPSG:4326)? Do I need to change my code? Please share your valuable thoughts.

Help would be appreciated :)

3
getLonLatFrompixel returns coordinates in lon/lat, whereas you are using 900913 (which is in metres). Have you tried the same transform that you used for map.setCenter on the map.getLonLatFromPixel(event.xy)?John Powell
@JohnBarça: Yes I tried bro. No luck :(Unknown
Obvious question, perhaps, but what are some sample values for event.text and map.getLonLatFromPixel(event.xy);John Powell
I am getting empty response John. I think when we click on feature OpenLayers getfeatureinfo is not able to call/get data from geoserver.Unknown
When you set up a layer in geoserver it asks you for a declared and native projection, and there is also a force declared option, which will attempt to convert all incoming queries into that projection. I would check what your outgoing request to Geoserver from OpenLayers looks like in the getFeatureInfo request and that it's projection matches whatever you have set up as native/declared in Geoserver.John Powell

3 Answers

3
votes
function fromLatLngToPoint(latLng, map) {
    var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
    var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
    var scale = Math.pow(2, map.getZoom());
    var worldPoint = map.getProjection().fromLatLngToPoint(latLng);
    return new google.maps.Point((worldPoint.x - bottomLeft.x) * scale, (worldPoint.y - topRight.y) * scale);
}


function getRadius(zoom) {
    var radius_px = 0.40/2
    var constMetersDegress = 1000; // TODO Verifiy

    //zoom <-> m/px = http://timwhitlock.info/blog/2010/04/google-maps-zoom-scales/
    var scaled_zooms = { 
        22: 0.02,
        21: 0.04,
        20: 0.09,
        19: 0.19,
        18: 0.37,
        17: 0.74,
        16: 1.48,
        15: 3,
        14: 6,
        13: 12,
        12: 24,
        11: 48,
        10: 95,
        9: 190,
        8: 378,
        7: 752,
        6: 1485,
        5: 2909,
        4: 5540,
        3: 10064,
        2: 16355,
        1: 21282,
        0: 30000
    }

    var radius_meters = radius_px * scaled_zooms[zoom];
    var radius_degrees = radius_meters / constMetersDegress;
    return radius_degrees;
}



function getFeatureInfoURL(latLng){
    var lat = parseFloat(latLng.lat());
    var lng = parseFloat(latLng.lng());

    //console.info('------------------------------')
    var radius_degrees = getRadius(map.getZoom());
    var buffer_sw_y_dd = lat-radius_degrees
    var buffer_sw_x_dd = lng-radius_degrees
    var buffer_ne_y_dd = lat+radius_degrees
    var buffer_ne_x_dd = lng+radius_degrees
    //console.info('bbox dd',buffer_sw_x_dd+','+buffer_sw_y_dd+','+buffer_ne_x_dd+','+buffer_ne_y_dd)

    var buffer_sw_dd = new google.maps.LatLng( buffer_sw_y_dd, buffer_sw_x_dd )//decimal degrees
    var buffer_ne_dd = new google.maps.LatLng( buffer_ne_y_dd, buffer_ne_x_dd )//decimal degrees

    var buffer_sw_px = fromLatLngToPoint(buffer_sw_dd, map);//pixels
    var buffer_ne_px = fromLatLngToPoint(buffer_ne_dd, map);//pixels
    //console.info('buffer_sw_px',buffer_sw_px,'buffer_ne_px',buffer_ne_px)

    var buffer_width_px = ( Math.abs( buffer_ne_px.x - buffer_sw_px.x ) ).toFixed(0);
    var buffer_height_px = ( Math.abs( buffer_ne_px.y - buffer_sw_px.y ) ).toFixed(0);
    //console.info('buffer_width_px',buffer_width_px, 'buffer_height_px',buffer_height_px)

    var center_x_px = (buffer_width_px / 2).toFixed(0);
    var center_y_px = (buffer_height_px / 2).toFixed(0);
    //console.info('center_x_px',center_x_px,'center_y_px',center_y_px)
    //console.info('------------------------------')


    var url = this.baseUrl;
    url +='&SERVICE=WMS';
    url +='&VERSION=1.1.0';
    url +='&REQUEST=GetFeatureInfo';
    url +='&TRANSPARENT=true';
    url +='&QUERY_LAYERS='+layerName;
    url +='&STYLES';
    url +='&LAYERS='+layerName;
    url +='&INFO_FORMAT=text/html';
    url +='&SRS=EPSG:4326';
    url +='&FEATURE_COUNT=10';
    url +='&WIDTH='+buffer_width_px;
    url +='&HEIGHT='+buffer_height_px;
    url +='&Y='+center_y_px;
    url +='&X='+center_x_px;
    url +='&BBOX='+buffer_sw_x_dd+','+buffer_sw_y_dd+','+buffer_ne_x_dd+','+buffer_ne_y_dd;


    return url;
};

Hope this will help

2
votes

I just ran up a demo using your exact code pointing to the geoserver demo site and it worked perfectly. The example below shows country borders etc so just head to the US/Canada border for something to click on. I suspect your issue is that GetFeatureInfo isn't guaranteed to always return something. It's possible to make that call and the WMS server return an exception that GetFeatureInfo is not available for the layer.

Another possible problem is that you're asking for GetFeatureInfo to return the info format in text/html. If you haven't defined HTML templates on the server it may also return an exception although I'm not exactly sure what the error would be here. You should switch to the simplest, default option which is text/plain. It won't look pretty but it'll remove one more place it could break while you figure everything else out.

I recommend you try this code sample in Chrome so you can use the debug tools and inspect the network tab and look at the content of the WMS requests flowing backwards and forwards.

Finally if you do see exceptions coming back you could code defensively for this by asking for the exceptions to be returned in JSON so you could potentially trap the error.

Good luck!

<html>
<head>
  <script src="lib/OpenLayers.js"></script>
    <script src="http://maps.google.com/maps/api/js?v=3&amp;sensor=false"></script>

  <script type="text/javascript">
  function init() {
    var gmap = new OpenLayers.Layer.Google("Google Streets", {
    visibility: false});
    var options = {
        controls : [],
        units : "m",
        numZoomLevels : 22,
        maxResolution : 156543.0339,
        projection: new OpenLayers.Projection("EPSG:900913"),
        displayProjection: new OpenLayers.Projection("EPSG:4326"),
        maxExtent : new OpenLayers.Bounds(-20037508.34, -20037508.34,
                20037508.34, 20037508.34)
    };
    var map = new OpenLayers.Map('map', options);
    var layer1 = new OpenLayers.Layer.WMS("Layer1 - Tiled",      
     "http://demo.opengeo.org/geoserver/ows?", {
                layers : "osm:admin_01234",
                transparent : "true",
                format : "image/png",
                srs : 'EPSG:4326', 
                zoomOffset : 3,
            }, {
                isBaseLayer : false
            });
    map.addLayer(gmap);
    map.addLayer(layer1);
    info = new OpenLayers.Control.WMSGetFeatureInfo({
        url: 'http://demo.opengeo.org/geoserver/ows?', 
        title: 'Identify features by clicking',
        layers: [layer1],
        infoFormat: 'text/html',
        queryVisible: true,
        eventListeners: {
            getfeatureinfo: function(event) {
                map.addPopup(new OpenLayers.Popup.FramedCloud(
                    "chicken", 
                    map.getLonLatFromPixel(event.xy),
                    null,
                    event.text,
                    null,
                    true
                ));
            }
        }
    });
    map.addControl(info);
    info.activate();
    map.setCenter(new OpenLayers.LonLat(-104.949, 40.924).transform(
    new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()),5);
     map.addControl(new OpenLayers.Control.Navigation());
}
  </script>

<body onload="init()">
 <div style="visibility: visible; height: 100%;" id="map"></div>
</body>
0
votes

I don't have a testing environment available (can you set up an appropriate jsfiddle, with a non localhost wms?), but maybe you are hitting an XSS filter on your browser.

See this post: http://cggis.wordpress.com/2011/05/19/getfeatureinfo/

Starting Chrome with the "--disable-web-security" flag should be a quick test to rule that possibility out.