OpenCage API and ArcGIS API for JavaScript

tsamaya

Arnaud Ferrand

Posted on May 10, 2020

OpenCage API and ArcGIS API for JavaScript

How to use the OpenCage Data Geocoder API with ArcGIS API for JavaScript

This tutorial will walk you through how to create a map with ArcGIS API for JavaScript and a custom search widget using OpenCage Data Geocoder API.

Get started

  1. We will need a OpenCage Data API key, it is free, signup for your own key here

  2. Your favorite editor: local or online

Local

The Mozilla Developer Network has an excellent guide on setting up a local development server.

Online

You can use sites such as CodeSandbox, JS Bin, CodePen and our own ArcGIS API for JavaScript sandbox

Tutorial

Reference the ArcGIS API for JavaScript

First, set up a basic HTML document:

<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>ArcGIS Search widget with OpenCage Data API</title>
  </head>

  <body></body>
</html>
Enter fullscreen mode Exit fullscreen mode

Inside the <head> tag, reference the ArcGIS API for JavaScript using a <link> tag:

<link
  rel="stylesheet"
  href="https://js.arcgis.com/4.15/esri/themes/light/main.css"
/>
Enter fullscreen mode Exit fullscreen mode

Inside the <body> tag, reference the ArcGIS API for JavaScript using <script> tag:

<script src="https://js.arcgis.com/4.15/"></script>
Enter fullscreen mode Exit fullscreen mode

Create a map

In the <head> section add a <style> tag:

<style>
  html,
  body,
  #viewDiv {
    padding: 0;
    margin: 0;
    height: 100%;
    width: 100%;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

In the <body> section add a <div> tag before the <script> tag. This <div> will be the map view container:

<div id="viewDiv"></div>
Enter fullscreen mode Exit fullscreen mode

At the end of the <body>, add a <script> tag and an AMD require statement to load the Map and MapView

<script>
  require(['esri/Map', 'esri/views/MapView'], function (Map, MapView) {
    var map = new Map({
      basemap: 'topo',
    });

    var view = new MapView({
      container: 'viewDiv',
      map: map,
      center: [-2.547855, 54.00366], // lon, lat
      scale: 4000000,
    });
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Run your code to view a map centered on the United Kingdom

Add the search widget

In the require statement, add a reference to the Search module.

require([ 'esri/Map', 'esri/views/MapView', 'esri/widgets/Search' ],
function(Map, MapView, Search) {
Enter fullscreen mode Exit fullscreen mode

At the end of the code in the main function, create a Search widget and set the view. Add the widget to the top right corner of the view.

// Search widget
var searchWidget = new Search({
  view: view,
});

view.ui.add(searchWidget, 'top-right');
Enter fullscreen mode Exit fullscreen mode

Run the code and try searching for the following:

  • London
  • Buckingham Palace
  • ///index.home.raft (sorry joking, it is a different example)
  • -0.20358600,51.521251

Add the custom source : OpenCage Data

In the require statement, add references to the modules:

  • SearchSource the custom source,
  • Graphic so the Search widget can display a point result,
  • Point used with the Graphic,
  • geometryEngine to compute a buffer around the searched location,
  • request for the API request to OpenCage Data API.
require([
  'esri/Map',
  'esri/views/MapView',
  'esri/widgets/Search',
  'esri/widgets/Search/SearchSource',
  'esri/Graphic',
  'esri/geometry/Point',
  'esri/geometry/geometryEngine',
  'esri/request',
], function (
  Map,
  MapView,
  Search,
  SearchSource,
  Graphic,
  Point,
  geometryEngine,
  esriRequest
) {
  // ...
});
Enter fullscreen mode Exit fullscreen mode

Create a function for the geocoding operations at the beginning of the module (AMD require is only here for hint purpose):

require([
  // ...
  'esri/request',
], function (
  // ...
  esriRequest
) {
  var API_KEY = 'YOUR-API-KEY';
  var OPENCAGEDATA_URL = 'https://api.opencagedata.com/geocode/v1/json';

  function geocode(options) {
    return esriRequest(OPENCAGEDATA_URL, {
      query: {
        key: API_KEY,
        q: options.query,
        proximity: options.proximity,
        no_annotations: 1,
        limit: 6,
      },
      responseType: 'json',
    });
  }
  // ...
});
Enter fullscreen mode Exit fullscreen mode

Before the Search widget create the custom SearchSource:

// Custom SearchSource
var opencageSearchSource = new SearchSource({
  placeholder: 'example: W10',
  minSuggestCharacters: 3,
  getSuggestions: function (params) {
    var address = params.suggestTerm.replace(/ /g, '+');
    return geocode({
      query: address,
      proximity: view.center.latitude + ',' + view.center.longitude,
    }).then(function (response) {
      var suggestions = response.data.results.map(function (feature) {
        return {
          key: 'name',
          text: feature.formatted,
          location: {
            longitude: feature.geometry.lng,
            latitude: feature.geometry.lat,
          },
          sourceIndex: params.sourceIndex,
        };
      });
      return suggestions;
    });
  },
  // Provide a getResults method to find
  // results from the suggestions, the device location or the text input
  getResults: function (params) {
    var query;
    // Perform a different query if a location is provided
    // HTML5 device location or suggestion selected
    if (params.location) {
      query = params.location.latitude + ',' + params.location.longitude;
    } else {
      query = params.suggestResult.text.replace(/ /g, '+');
    }

    return geocode({
      query: query,
    }).then(function (results) {
      // Parse the results of your custom search
      var searchResults = results.data.results.map(function (feature) {
        // Create a Graphic the Search widget can display
        var graphic = new Graphic({
          geometry: new Point({
            x: feature.geometry.lng,
            y: feature.geometry.lat,
          }),
          attributes: {
            name: feature.formatted,
            label: feature.formatted,
            props: feature.properties,
          },
        });
        var buffer = geometryEngine.geodesicBuffer(
          graphic.geometry,
          250,
          'meters'
        );
        // Return a Search Result
        var searchResult = {
          extent: buffer.extent,
          feature: graphic,
          name: feature.formatted,
        };
        return searchResult;
      });

      // Return an array of Search Results
      return searchResults;
    });
  },
});
Enter fullscreen mode Exit fullscreen mode

Update the search widget, disabling the Esri's World Geocoder:

var searchWidget = new Search({
  view: view,
  sources: [opencageSearchSource],
  includeDefaultSources: false,
});
Enter fullscreen mode Exit fullscreen mode

Congratulations, you're done!

Your app should look something like this:

Screenshot

Try searching for the following:

  • London
  • Buckingham Palace
  • 51.521251,-0.20358600 (yes here it is latitude, longitude)

Thank for reading 🙏

You can find the sources in this GitHub repository

  • tutorial.html this step by step tutorial where you only have to change YOUR-API-KEY,
  • index.html an advanced version with an API key prompt, using localStorage for further usage and a basemap widget, as you can also be an addict to the National Geographic basemap, and split files (html, css, js).

Was this post helpful? Don't forget to share because Sharing is Caring.

Resources

💖 💪 🙅 🚩
tsamaya
Arnaud Ferrand

Posted on May 10, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related