Skip to content

Instantly share code, notes, and snippets.

@rclark rclark/Issues.md
Last active Sep 10, 2019

Embed
What would you like to do?
Leaflet WMS + GetFeatureInfo
<!doctype html>
<html>
<head>
<title>WMS GetFeatureInfo</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.css" />
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.ie.css" />
<![endif]-->
<script src="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>
<style type="text/css">
html, body, #map {
margin: 0px;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="L.TileLayer.BetterWMS.js"></script>
<script>
var map = L.map('map', {
center: [34,-111],
zoom: 7
});
var url = 'http://data.azgs.az.gov/arizona/wms';
L.tileLayer('http://{s}.tiles.mapbox.com/v3/rclark.map-wm3i8w1a/{z}/{x}/{y}.png').addTo(map);
L.tileLayer.betterWms(url, {
layers: 'azgs:mapunitpolys',
transparent: true,
format: 'image/png'
}).addTo(map);
</script>
</body>
</html>

There are a bunch of reasons why this is convoluted, mostly in building the URL to make the request:

  1. You have to rely on an AJAX request, this example uses jQuery
  2. To make a GetFeatureInfo request, you must provide a BBOX for a image, and the pixel coordinates for the part of the image that you want info from. A couple of squirrely lines of Leaflet code can give you that.
  3. Output formats. The info_format parameter in the request. We don't know a priori which will be supported by a WMS that we might make a request to. See Geoserver's docs for what formats are available from Geoserver. That won't be the same from WMS to WMS, however.
  4. WMS services return XML docs when there's a mistake in the request or in processing. This sends an HTTP 200, which jQuery doesn't think is an error.
L.TileLayer.BetterWMS = L.TileLayer.WMS.extend({
onAdd: function (map) {
// Triggered when the layer is added to a map.
// Register a click listener, then do all the upstream WMS things
L.TileLayer.WMS.prototype.onAdd.call(this, map);
map.on('click', this.getFeatureInfo, this);
},
onRemove: function (map) {
// Triggered when the layer is removed from a map.
// Unregister a click listener, then do all the upstream WMS things
L.TileLayer.WMS.prototype.onRemove.call(this, map);
map.off('click', this.getFeatureInfo, this);
},
getFeatureInfo: function (evt) {
// Make an AJAX request to the server and hope for the best
var url = this.getFeatureInfoUrl(evt.latlng),
showResults = L.Util.bind(this.showGetFeatureInfo, this);
$.ajax({
url: url,
success: function (data, status, xhr) {
var err = typeof data === 'string' ? null : data;
showResults(err, evt.latlng, data);
},
error: function (xhr, status, error) {
showResults(error);
}
});
},
getFeatureInfoUrl: function (latlng) {
// Construct a GetFeatureInfo request URL given a point
var point = this._map.latLngToContainerPoint(latlng, this._map.getZoom()),
size = this._map.getSize(),
params = {
request: 'GetFeatureInfo',
service: 'WMS',
srs: 'EPSG:4326',
styles: this.wmsParams.styles,
transparent: this.wmsParams.transparent,
version: this.wmsParams.version,
format: this.wmsParams.format,
bbox: this._map.getBounds().toBBoxString(),
height: size.y,
width: size.x,
layers: this.wmsParams.layers,
query_layers: this.wmsParams.layers,
info_format: 'text/html'
};
params[params.version === '1.3.0' ? 'i' : 'x'] = point.x;
params[params.version === '1.3.0' ? 'j' : 'y'] = point.y;
return this._url + L.Util.getParamString(params, this._url, true);
},
showGetFeatureInfo: function (err, latlng, content) {
if (err) { console.log(err); return; } // do nothing if there's an error
// Otherwise show the content in a popup, or something.
L.popup({ maxWidth: 800})
.setLatLng(latlng)
.setContent(content)
.openOn(this._map);
}
});
L.tileLayer.betterWms = function (url, options) {
return new L.TileLayer.BetterWMS(url, options);
};
@RadekHavelka

This comment has been minimized.

Copy link

commented Apr 18, 2014

Hi, I just want to say thanks for this code, very helpful !

@tommelluish

This comment has been minimized.

Copy link

commented Jun 13, 2014

Thanks very much for posting this example - it looks really useful! I had some problems getting it to work with my local geoserver, but firebug finally showed me that a CORS restriction was preventing geoserver returning the getFeatureInfo to my webserver. Enabling "Access data sources across domains" in Internet Explorer finally got around the problem - now I have to work out how to do that properly with CORS headers...

@Trac3rTong

This comment has been minimized.

Copy link

commented Aug 7, 2014

Hi,
is it possible to get the featureinfo from more than on layer in a single pop-up window?

thanks for any help!

@lurajon

This comment has been minimized.

Copy link

commented Nov 6, 2014

Hi,

I also need the popup window to display featureinfo from more than one layer.

Thanks!

Best regards,

Jone

@hoge6b01

This comment has been minimized.

Copy link

commented Mar 12, 2015

Hi, love it. Thank you very much.
One question. How and where do I define the attribute's table column that should be displayed in the popup (instead all like implemented now)? Thanks for your help. BR!

@akshara-chukkannagari

This comment has been minimized.

Copy link

commented Nov 18, 2015

Hi,
I love this simple and easy featureInfo in leaflet maps.
Is it possible to get the featureInfo (attributes) using an HTTP POST request instead of HTTP GET request (the URL)?
and also any way to choose the attributes to be displayed?

Thanks,
Akshara

@amarflybot

This comment has been minimized.

Copy link

commented Dec 4, 2015

No 'Access-Control-Allow-Origin' header is present on the requested resource
I get the above error when it hit the URL: http://:7070/geoserver/MSTRUNKCAR1_MINESTAR/wms?REQUEST=GetFeatureInfo&SERVICE=WMS&SRS=EPSG%3A4326&STYLES=&TRANSPARENT=true&VERSION=1.1.1&FORMAT=image%2Fpng&BBOX=0.7881295680999756%2C0.6926046010364527%2C0.8019590377807618%2C0.6994598214130091&HEIGHT=639&WIDTH=1289&LAYERS=MSTRUNKCAR1_MINESTAR%3AMSTRUNKCAR1_ROADS&QUERY_LAYERS=MSTRUNKCAR1_MINESTAR%3AMSTRUNKCAR1_ROADS&INFO_FORMAT=text%2Fhtml&X=371&Y=326

@ezgis504

This comment has been minimized.

Copy link

commented Dec 6, 2015

Thanks for creating this functionality.

For me, I get a popup window, but it is blank. I am using this WMS:
http://igems.doi.gov/arcgis/services/igems_haz/MapServer/WMSServer

image

@amarflybot

This comment has been minimized.

Copy link

commented Dec 22, 2015

@ezgis504 I think you need to map the returned function of parseResponse correctly into an object of alert. The above example is awesome.

@ezgis504

This comment has been minimized.

Copy link

commented Jan 3, 2016

I'm not sure how to do that. Is it something you can explain easily?

@ezgis504

This comment has been minimized.

Copy link

commented Jan 3, 2016

Actually, I have been playing around with it more. I can get the info window popup, but only when i click at the center of the polygon feature. Is it possible to get to work when click anywhere within the polygon?

@Tybion

This comment has been minimized.

Copy link

commented Jan 6, 2016

Thank you for unselfishly providing this code. You have saved me probably days of time.

@hoge6b01

This comment has been minimized.

Copy link

commented Jan 15, 2016

Hello, I created a webmap using the BetterWMS. The app can be found at www.carstenhogertz.de/c_section . My problem is that when I click on a feature it sometimes returns a FeatureInfo sometimes not. At very large scale it even shows Infos from another Feature that I've clicked. How do I manipulate the code to the correct Features? Thanks Carsten

@Huyeng

This comment has been minimized.

Copy link

commented Jan 16, 2016

Thanks for sharing this. I wonder that how do highlight the selected feature onclick to get info window?

@Ojaybee

This comment has been minimized.

Copy link

commented Apr 8, 2016

Hi I'm getting the following error when I click on a feature:

TypeError: t is undefined
...unction(t){var e=Math.PI/180,i=1-1e-15,n=Math.max(Math.min(Math.sin(t.lat*e),i),...

From leaflet.js line 5

Is this a known issue?

@hardisubagyo

This comment has been minimized.

Copy link

commented Aug 23, 2016

how that feature down instead of sideways

@renelikestacos

This comment has been minimized.

Copy link

commented Sep 29, 2016

Thanks for sharing this pretty useful function. I wonder why Leaflet doesn't come with that.

@AngAven

This comment has been minimized.

Copy link

commented Dec 5, 2016

captura de pantalla 2016-12-05 02 20 18

It's amazing that code, thanks.
@unnic

This comment has been minimized.

Copy link

commented Dec 20, 2016

Exactly what I need. Thanks for sharing.
Any Info on how you got around the CORS restriction? I get a CORS error if I click on the betterWMS layer but if I enter the resulting URL directly I get the server response correctly.

@Andrespebu

This comment has been minimized.

Copy link

commented Feb 9, 2017

Hola, tengo un problema que no sé resolver... Espero que alguien me ayude... Una vez inserto betterWms y ajusto los datos no aparece en mi navegador ningún popup pero la petición la hace correcta, alguna solución?
Saludos.

@fuhidev

This comment has been minimized.

Copy link

commented Mar 24, 2017

Thanks you. Very good <3

@thanhxuan2017

This comment has been minimized.

Copy link

commented Mar 30, 2017

Thank you @rclark.
But could you help me. I using your source code, i replace url base map and database (my wms). when i run index.html, it show image map. my mouse is hand on desktop (dont change as arrow to click a position) and dont show popup. Please, help me. Thank pro!

@thanhxuan2017

This comment has been minimized.

Copy link

commented Apr 2, 2017

Dear AngAven,
Could you send me source code in your example. My email: mrthanhxuan@gmail.com. Thanks for help me!

@santiblanko

This comment has been minimized.

Copy link

commented Apr 7, 2017

@thankxuan2017 in my opinion wms is old.

@marfeca94

This comment has been minimized.

Copy link

commented May 3, 2017

How can I display the popup only if I click on the layer and not in the basemap?

@eddiedehmous

This comment has been minimized.

Copy link

commented Jun 1, 2017

I have built a nice map with layers of images from geoserver using leaflet , now i would like to add this GetfeatureInfo functionality , get the values when user click on a point , a have tested this plugin leaflet.wmsBetter but when i run it nothing happened on the map .
I rad somewhere that it could be a problem of port configuration between leaflet and geoserver .
can you help me please ?

@mitsaras

This comment has been minimized.

Copy link

commented Jul 28, 2017

Exactly what I need. Thanks for sharing.
God bless you!

@salman03091992

This comment has been minimized.

Copy link

commented Aug 16, 2017

amarraja123 bro use this extension.
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi
i have the same issue like and this extension helped me out.

@maryandplus

This comment has been minimized.

Copy link

commented Aug 27, 2017

this code is great! thanks for sharing
i had trouble with the javascript cross domain but this video: https://www.youtube.com/watch?v=o8puzjzpjqo helped
so @salman03091992 is right... if anyone wants to check if their site is working just use the browser extension.

@maryandplus

This comment has been minimized.

Copy link

commented Sep 22, 2017

i had a problem with the pop up windows but now it's fixed.
so what you have to do if you want to upload many layers of the same type just group them in one .shp (qgis) or one directory (geoserver)

@obicd

This comment has been minimized.

Copy link

commented Nov 2, 2017

Hello please help. The request appears to be working, but I am not seeing the popup with the layer attributes.

@obicd

This comment has been minimized.

Copy link

commented Nov 2, 2017

below is the getinfo parameter that were posted:
N=1.1.1, X=343, Y=422, SERVICE=WMS, QUERY_LAYERS=UBDC1:SELECT_OA2, TRANSPARENT=true}
Request = GetFeatureInfo
RequestCharset = null
Version = 1.1.1
XPixel = 343
YPixel = 422

@MinChanSike

This comment has been minimized.

Copy link

commented Dec 6, 2017

Fix for blank popup window.

L.TileLayer.BetterWMS.js

 getFeatureInfo: function (evt) {
    // Make an AJAX request to the server and hope for the best
    var url = this.getFeatureInfoUrl(evt.latlng),
      showResults = L.Util.bind(this.showGetFeatureInfo, this);
    $.ajax({
      url: url,
      success: function (data, status, xhr) {
        var err = typeof data === 'string' ? null : data;
        //Fix for blank popup window
        var doc = (new DOMParser()).parseFromString(data, "text/html"); 
        if (doc.body.innerHTML.trim().length > 0)
          showResults(err, evt.latlng, data);
      },
      error: function (xhr, status, error) {
        showResults(error);
      }
    });
  },
@cgalvist

This comment has been minimized.

Copy link

commented Feb 7, 2018

This code is great. Thank you.

@souliotissa

This comment has been minimized.

Copy link

commented Feb 26, 2018

It Works verk well, but i Would be grateful IF you could help me With this. My getfeatureinfo is a table of a raster with Only one value. How to parse this value to variable?
Thanks in advance

@markgis

This comment has been minimized.

Copy link

commented Mar 20, 2018

This was really handy, thanks.

For 1.3.0 getfeatureinfo the lat and longs have been reversed so the bbox: this._map.getBounds().toBBoxString(), line doenst work. A quick function to create a string with the lat and longs in the right order solved it.

@dior1

This comment has been minimized.

Copy link

commented May 17, 2018

Is there a way to enlarge the klick area from who the info get? And if I get the info from 2 or more layers how do I show this in a popup with tabs?

@anakaine

This comment has been minimized.

Copy link

commented Oct 14, 2018

Hey Ryan, is seems like you 1st August blocks example of this is broken. Ive been trying to implement your solution but not been having much luck unfortunately. Not seeing a popup at all on leaflet 1.3.4

Also, @santiblanko wms may have been around for some time, but that neither makes it old or the implied 'not as useful. There are plenty of situations where it is still the best and fastest option, particularly with raster data.

http://bl.ocks.org/rclark/6908938

@ISURU9900

This comment has been minimized.

Copy link

commented Oct 25, 2018

I was able successfully run this BetterWMSLayer. But now I want to show the attributes of a raster through a marker popup. Any idea?

@ATejed

This comment has been minimized.

Copy link

commented Dec 17, 2018

Is there a way to enlarge the klick area from who the info get?

I have the same problem. How did you solve it? @dior1

@Tim0917

This comment has been minimized.

Copy link

commented Jan 11, 2019

Super awesome!

Question:
How do i select a single value of the wms?
So, i want just one popup, for one value.
Somewhere there is a selection needed, but how??

Please help :)

@ivominic

This comment has been minimized.

Copy link

commented Feb 22, 2019

Is there a way to enlarge the klick area from who the info get?

I have the same problem. How did you solve it? @dior1

If you want to get info for multiple features, you should add
feature_count: '5',
to parameter list in getFeatureInfoUrl, and set number of maximum features you want to show info.

capture

@aichaous

This comment has been minimized.

Copy link

commented Mar 24, 2019

it worked but i have a blank popup

@nmtoken

This comment has been minimized.

Copy link

commented Aug 12, 2019

     params = {
      request: 'GetFeatureInfo',
      service: 'WMS',
      srs: 'EPSG:4326',
      styles: this.wmsParams.styles,
      transparent: this.wmsParams.transparent,
      version: this.wmsParams.version,      
      format: this.wmsParams.format,
      bbox: this._map.getBounds().toBBoxString(),
      height: size.y,
      width: size.x,
      layers: this.wmsParams.layers,
      query_layers: this.wmsParams.layers,
      info_format: 'text/html'
    };

params[params.version === '1.3.0' ? 'i' : 'x'] = point.x;
params[params.version === '1.3.0' ? 'j' : 'y'] = point.y;

You have switch of x/y for i/j dependent on version, but version also switches other things, for example the parameter for specifying the Coordinate Reference system is CRS not SRS in WMS 1.3.0.

Also in WMS 1.3.0 the axes order as specified by EPSG is honoured, so EPSG:4326 is specified with a lat/long bounding box and not as per WMS 1.1.1 in long/lat order.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.