I have a Leaflet map in which I am displaying an Esri ArcGIS REST layer, using L.esri.dynamicMapLayer()
. The code that initializes this layer is passed the URL to the service and a comma-separated list of layers to be displayed - which service and which layers is configured by the user.
My task is to provide a means by which the user can click on the map and obtain feature information for the nearby facilities. I had been looking at L.esri.query()
, which was simply inappropriate.
Looking at L.esri.DynamicMapLayer
, I see that it has a function identify()
, which should return an IdentifyFeatures object. But I'm not having any luck with using it. Everything I try results in a
bbox must be specified
error.
The documentation for dynamicMapLayer is here: dynamic-map-layer.html It includes:
Returns a new L.esri.services.IdentifyFeatures object that can be used to identify features on this layer. Your callback function will be passed a GeoJSON FeatureCollection with the results or an error.
dynamicMapLayer.identify()
.at(latlng, latlngbounds, 5)
.run(function(error, featureCollection){
console.log(featureCollection);
});
Note that .at() is called with a latlong object, a latlngbounds object, and "5".
But the documentation for the IdentifyFeatures object is here: identify-features.html
And it's documentation for at() is:
at( latlng) this Identifies feautres at a given
Only one argument. No second bounds argument, or third numeric argument, simply a LatLng. The LatLng links to the Leaflet code, indicating that it's an L.latLng object, containing a lat and a lng property.
The example code for IdentifyFeatures is even more confusing:
L.esri.identifyFeatures({
url: 'http://sampleserver6.arcgisonline.com/arcgis/rest/services/WorldTimeZones/MapServer'
})
.on(map)
.at([45.543, -122.621])
.layers('visible:1')
.run(function(error, featureCollection, response){
console.log("UTC Offset: " + featureCollection.features[0].properties.ZONE);
});
Here, we're not passing a L.latLng object, we're passing an array.
What gives? How am I supposed to use this?
After some clarification as to what the proper arguments should be, I passed a single LatLng object, and continued to get the "bbox must be specified" error.
Tracking this down into the JS libraries, I discovered that this error message is being returned by the server. The esri-leaflet is building up the URL below, sending it to our customer's ArcGIS REST server, and getting back the error.
https://gis.elided.invalid/arcgis/rest/services/Secure/Korweb_App/MapServer/export/identify?sr=4326&layers=all&tolerance=3&returnGeometry=true&imageDisplay=431%2C600%2C96&mapExtent=-75.59185445308685%2C40.99650425834298%2C-75.58954238891602%2C40.998933489018704&geometry=-75.59079766273499%2C40.998492185433854&geometryType=esriGeometryPoint&f=json
I'm eliding the actual URL because one, this is a customer's production site, and I haven't permission to allow anyone else to access, and because it's behind an IP-filtering firewall, and nobody could access it, anyway.
So, we're down to the real question - should this URL have worked? Is there a bbox argument that should have been passed, that was somehow left out? Or is this a correct URL, and there's something on the server that has been misconfigured?
OK, it was something stupid.
Esri's ArcGIS REST API uses a base URL that looks like this:
https://tmservices1.esri.com/arcgis/rest/services/LiveFeeds/Earthquakes/MapServer
To which it appends the various actions that are requested. To export an image, you call:
https://tmservices1.esri.com/arcgis/rest/services/LiveFeeds/Earthquakes/MapServer/export/????
To do an identify, you call:
https://tmservices1.esri.com/arcgis/rest/services/LiveFeeds/Earthquakes/MapServer/identify/????
The configuration we were building our map from was handed a URL that ended in "/export". As a result, when we did an identify, we called a URL that included "/export/identify", so we weren't asking for an identify, we were asking for an export, and were passing invalid arguments.