Esri Leaflet Geocoder Crash Course

road map

I thought I’d introduce the Esri Leaflet Geocoder plugin in this post. It is one of many plugins Esri has developed to support integration with the Leaflet.js web mapping library. Although Esri states that they “provide no guarantee of individual features, nor a traditional product lifecycle to support planning,” they have integrated their technology with Leaflet pretty well. And they are also very active in fixing bugs.

I’ve also been experimenting with an address search plugin for Leaflet that uses Open Street Map’s Nominatim, and honestly, Esri’s World Geocoding Service is better in my opinion.  I’ve previously written about searching within GeoJSON data in a Leaflet map.  With this Esri plugin, you can search against a layer (map/feature service) and street addresses from the same control.  I consider that a great feature.  I have a live demo wired up on CodePen.

The Geocoder plugin allows you to search from the Esri World Geocoding service, a custom geocoding service, as well as within map/feature services. Esri also provide a user interface for performing the searches in the plugin. And while the default placement is below the zoom controls, the Calcite Maps project has a code sample to move the search control into a Bootstrap navigation bar.

leaflet web map with default placement of esri leaflet geocoder plugin widget
Default placement of geocoder/search widget for Esri Leaflet Geocoder
leaflet web map with esri leaflet geocoder plugin widget placed within navigation bar
Geocode/search widget is placed within navigation bar in Calcite Maps template

I’d like to share some code snippets of how to implement this plugin. As the majority of my map applications use the same type of search (custom geocode service), I’ve developed a module for geocoding. For the samples, I’ll provide an example of the Esri World Geocoding service, a custom geocoding service, and searching within a feature layer.

Setting up the Geocoder

To start with, we need to create a few variables to to create the geocode search and store results. The searchControl variable is the the L.esri.Geocoding.geosearch object, which we add to the map. There are many options for this object, including search providers, search bounds, and placeholder text.

The providers are separately constructed objects that can be the Esri World Geocoding service, a custom geocoding service, or a feature layer search. The search bounds are a L.latLngBounds object that allows you to limit the searching within latitude/longitude bounds. This can be especially nice when using a service with features outside of your map’s focus area to exclude those results (i.e, not returning California addresses for a map of Pennsylvania).

The searchResults variable is a L.layerGroup object that will hold the results of your search. I have only used this plugin to return a single result, so I’m not very familiar with using multiple results.

// the search widget that will be hooked into the leaflet map
var searchControl;
// the results of a query against a geocoding service and/or feature layer
var searchResults;
// the bounding box in which we will search for addresses/features
var searchBounds = L.latLngBounds([39.803052, -77.820029],[40.453170, -76.799358]);

// instantiate the search control and add to the map
searchControl = L.esri.Geocoding.geosearch({
    useMapBounds: false, // do not use extent of map to limit search results
    providers: [agolProvider, ccpaProvider, schoolsLayer], // providers are geocoding services or map/feature services that we can search against
    placeholder: 'Search for an address',
    title: 'Address Search',
    searchBounds: searchBounds, // limit search results within these coordinates
    zoomToResult: true
}).addTo(map);

// create an empty layer group and add to the map. we will add our results to this layer group 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
searchResults = L.layerGroup().addTo(map);

Setting up the Search Providers

Next, I’ll share some sample code for creating three search providers.

Esri World Geocoding Service

This is by far the easiest to set-up. There are some options for limiting results to certain countries or categories, although I haven’t used them.

// ArcGIS Online default geocoding service
var agolProvider = L.esri.Geocoding.arcgisOnlineProvider({
    // results from this provider will be listed under the label property
    label: 'ArcGIS Online World Geocoding Service',
    // limit the number of results from this provider
    maxResults: 6});

Custom Geocoding Service

For a custom geocoding service, you need to provide the URL of the service, and you can also provide options available to all search providers. The label option is the text used to group suggestions when more than one provider is used.

// Cumberland County Road Centerlines
var ccpaProvider = L.esri.Geocoding.geocodeServiceProvider({
        label: 'Cumberland County Composite Locator',
        maxResults: 6,
        // this will add an attribution to the map
        attribution: 'Cumberland County',
        // url for the geocoding service
 url:'//gis.ccpa.net/arcgiswebadaptor/rest/services/Roads_Locator/GeocodeServer'
});

Feature Layer Provider

This may be the coolest search provider. With a Feature Layer Provider, you can search for records within a map/feature service. In addition to providing the service’s URL, you provide the fields you want to search within. You can also format how the suggestion text will look.

// Schools
var schoolsLayer = L.esri.Geocoding.featureLayerProvider({
   // url for the map/feature service
   url: '//gis.ccpa.net/arcgiswebadaptor/rest/services/911/MapServer/7',
   // limit which fields can be queried against
   searchFields: ['Name', 'Address1', 'City'],
   // define a function for how the matching features will be displayed in the results list
  formatSuggestion: function(feature) {
     return feature.properties.Name + ', ' + feature.properties.Address1 + ', ' + feature.properties.City;
        },
  label: 'Schools'
});

Handling Results

The final step in using the Esri Leaflet Geocoder plugin is to configure the results event of the search. All of the results are stored in array, where each result is a Result Object. Each Result Object will contain the text that was passed to the provider, the latitude/longitude bounds (L.latLngBounds) for the result, and the latitude/longitude (L.latLng) for the result. It will also contain additional properties from the provider.

In my implementation of this plugin, I have only been interested in returning a single result. I start by clearing the previous result, then center the map view with the latitude/longitude of the result and a specific zoom level. Finally, I open a popup at the result’s location with the text passed to the search. Finally, I wrap all of this in a conditional statement to ensure there are actually results.  In a Residential Recycling & Disposal map, I add a marker to the search result using another Leaflet plugin.

searchControl.on('results', function(data) {
   // remove existing results from map
   searchResults.clearLayers();

   // test whether there are any results
   if (data.results.length > 0) {
      // set map view to coordinates of the first item in the results and the zoom level to 18
      map.setView(data.results[0].latlng, 18);

      // create popup for result. set coordinates to the coordinates of the first item in the results.  Set the result text to the contents of the popup. Open the popup on the map
      var popup = L.popup({closeOnClick: true}).setLatLng(data.results[0].latlng).setContent(data.results[0].text).openOn(map);
   }
});

Hopefully you have found this crash course for the Esri Leaflet Geocoder plugin useful. If you’d like to learn more, please visit the plugin’s API reference or the examples page.

I’ve also created a demo of this plugin in action on CodePen.

 

Advertisements

One thought on “Esri Leaflet Geocoder Crash Course

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s