Front-End Web & Mobile

Add Maps to your App in 3 Steps with AWS Amplify Geo powered by Amazon Location Service

Today’s release of AWS Amplify Geo allows developers to quickly and easily add maps with markers and location search to their JavaScript-based web apps. The location APIs are powered by Amazon Location Service and the UI components are extended from a popular open-source map library, MapLibre.

Benefits

What we’ll build

Use case: As a restaurant owner, I would like to create a website for my restaurant that displays all the branches of my restaurant on map. This offers a better user experience to my customers who want to view the locations of the all my restaurant branches.

To achieve the above use case, we can add a map to a web page either through simple script tags in the HTML webpage or by adding the necessary NPM packages to any JavaScript-based web framework like React.

In this blog post, we will build a React-based web application for a restaurant website that displays all of the restaurant branches on a map.

We will dive into different approaches of adding maps to your website in future blog posts.

What we’ll learn

  • How to create a React app with a map display
  • How to display markers on the map
  • How to customize the text in the popovers on markers

Prerequisites

Note: At the time of this post, Amplify Geo is only available in the following regions – US East (N. Virginia), US East (Ohio), US West (Oregon), Asia Pacific (Singapore), Asia Pacific (Sydney), Asia Pacific (Tokyo), Europe (Frankfurt), Europe (Ireland), and Europe (Stockholm)

  • Install Node JS greater than v12.0
  • Get the latest Amplify CLI by running npm install -g @aws-amplify/cli

Setting up a React App

This tutorial focuses on integrating AWS Amplify Geo into a React app – but, similar steps can be used with most modern web frameworks. To start with, we can run the following commands to create a React app for our restaurant home page.

npx create-react-app my-restaurants
cd my-restaurants

Run npm start from the project directory to test the my-restaurants project. This will automatically launch the React app in the browser pointing at http://localhost:3000. You will see something similar to the image below:

Initial React app screenshot

1. Setting up Amplify Geo

To get started with Amplify Geo, initialize an Amplify project for your new React app.

amplify init 

This command will prompt you initialize your Amplify project with preselected defaults. You can choose to edit these defaults. For the purpose of this project, we can stick to the defaults. The defaults are shown below:

Default configurations when running Amplify init

Now, add a map resource to display the map tiles on the screen. The following command will walk you through some configurations to set up your map.

amplify add geo

Choose to add a map resource to your project:

Adding Map resource to your project

If you do not have Amplify Auth category configured, the Amplify CLI will prompt you to configure it now. You can follow along with the default choices for the purpose of this project:

Default value selected for remaining prompts of amplify add geo

Next, either enter a custom name for your map or stick with the default name and hit enter. This name can’t be changed, but isn’t visible to end-users. And you can always add more map resources, as required.

Provide a name for the Map prompt

Next, select Authorized and Guest Users for Who can access this map? because you want anyone browsing the internet to be able to view the branches of the restaurant.

Note: If you select the Authorized users only option (the default), you will not see a map at the end of this tutorial until you make it possible for a user to login. The Amplify Authenticator UI component is a good way to do this for React apps.

Choose Authorized and Guest users access for the map

The next question, Are you tracking commercial assets for your business in your app?, is primarily for determining the pricing for your map resource. For this project, since we are not tracking any devices, choose the first option No, I do not track devices or I only need to track consumers’ personal devices. You can find additional pricing details at Amazon Location Service Pricing.

Select not tracking devices to determine pricing plan

For the purpose of this project, stick with the defaults and select No when prompted to configure advanced settings. Advanced settings allow you to further customize the map styles and data providers – you can come back to configure those later, if you choose.

Stick with default configurations and skip advanced settings for maps

Your map is now set up locally. To deploy this to the cloud, run the following command:

amplify push

Install the necessary client libraries for our application by running the following command:

npm install aws-amplify

Paste the following code to your index.js file.

import Amplify from 'aws-amplify'; 
import awsconfig from './aws-exports'; 

Amplify.configure(awsconfig);

The aws-exports.js is automatically generated by the Amplify CLI, and contains all of the details needed for your frontend web app to find all of the AWS services which have been configured for you.

2. Displaying Map on the Restaurant Home Page

First, clean up the web page to show the title of the restaurant and list out the different locations of the restaurant. Replace the contents of React App() main function in App.js to the code below.

function App() {
    return (
        <div className="App">
            <h1>My Restaurant</h1>
            <ul id="locations">
                <li><b>My Restaurant - Upper East Side</b> <br/> 300 E 77th St, New York, NY 10075 </li>
                <li><b>My Restaurant - Hell's Kitchen</b> <br/> 725 9th Ave, New York, NY 10019</li>
                <li><b>My Restaurant - Lower East Side</b><br/> 102 Norfolk St, New York, NY 10002</li>
            </ul>
        </div>
    );
}

Add the following CSS definitions in App.css to ensure a clean interface centered in the middle of the page.

#locations {
  display: inline-block;
  display: inline;
}

li {
  padding: 5px;
  display: inline-block;
  margin: 20px;
}

At this point, you have a page that looks like this

My Restaurant app showing three adresses

Now that all the ground work is completed for the Amplify app and map resources, edit the React app to display a map on the web page and show the desired location markers.

The popular map rendering library, MapLibre, is used to render the map on the web page. We have created an Amplify Geo<>Maplibre package that provides ready to use map UI components that are already connected to the Amplify Geo APIs.

Install the MapLibre dependencies:

npm install -S maplibre-gl@1 maplibre-gl-js-amplify

Now, paste the following code snippet in your App.js file, to import the necessary dependencies

import { createMap } from "maplibre-gl-js-amplify"; 
import "maplibre-gl/dist/maplibre-gl.css";
import { useEffect } from 'react';

Using the createMap function from maplibre-gl-js-amplify imported above, add a function to initialize the map. Add the code snippet below to App.js

async function initializeMap() {
    const map = await createMap({
        container: "map", // An HTML Element or HTML element ID to render the map in https://maplibre.org/maplibre-gl-js-docs/api/map/
        center: [-73.98597609730648, 40.751874635721734], // center in New York
        zoom: 11,
    })
    return map;
}

Invoke the initializeMap() method in App() function with the React useEffect hook. The useEffect hook ensures that the code inside it runs after every render. This ensures the map is not initialized before the map div component is available. Since a div is needed to display the map in the HTML page, add the following div element in the App() function. It should now look like this:

function App() {
 useEffect( async () => {
    const map = await initializeMap();
  }, []);
  return (
    <div className="App">
      <h1>My Restaurant</h1>
      <ul id="locations">
        <li><b>My Restaurant - Upper East Side</b> <br/> 300 E 77th St, New York, NY 10075 </li>
        <li><b>My Restaurant - Hell's Kitchen</b><br/> 725 9th Ave, New York, NY 10019</li>
        <li><b>My Restaurant - Lower East Side</b><br/> 102 Norfolk St, New York, NY 10002</li>
      </ul>
      <div id="map"></div>
    </div>
  );
}

Lastly, add some CSS to render the map component correctly on the restaurant homepage:

#map { /* The id of the container you passed to createMap */
    height: 40vh;
    width: 40vw;
    margin: auto;
}

You can now view your map on the web page, it should now look like the image below:

My Restaurant app with map

3. Adding Branch Locations for Restaurant on the Map

Here, you will be adding 3 different branch locations for the restaurant in New York. To display markers on the map, you will be using the drawPoints method and the map automatically handles rendering the popups on click and clustering markers when they are nearby to offer a better user experience.

First, import the drawPoints method in App.js:

import { drawPoints } from "maplibre-gl-js-amplify";

Now, create a function addRestaurantLocations using the drawPoints method to load the markers on the map. The coordinates specified are locations of the restaurant branches. For more configuration options, please refer to the details of the drawPoints method reference at aws-amplify/maplibre-gl-js-amplify repo.

function addRestaurantLocations(map) {
  map.on("load", function () {
    drawPoints("mySourceName", // Arbitrary source name
        [
            {
              coordinates: [-73.98709247500821, 40.718839863699905],
              title: "My Restaurant - Lower East Side",
              address: "102 Norfolk St, New York, NY 10002",
            },
            {
              coordinates: [-73.9893305444102, 40.76329636720047],
              title: "My Restaurant - Hell's Kitchen",
              address: "725 9th Ave, New York, NY 10019",
            },
            {
              coordinates: [-73.95621342276895, 40.77225519589616],
              title: "My Restaurant - Upper East Side",
              address: "300 E 77th St, New York, NY 10075",
            },
        ], // An array of coordinate data, an array of Feature data, or an array of [NamedLocations](https://github.com/aws-amplify/maplibre-gl-js-amplify/blob/main/src/types.ts#L8)
        map,
        {
            showCluster: true,
            unclusteredOptions: {
                showMarkerPopup: true,
            },
            clusterOptions: {
                showCount: true,
            },
        }
    );
  });
}

Call the addRestaurantLocations() within useEffect() in App() function as well. Your App() function will look like this:

function App() {

  useEffect( async () => {
    const map = await initializeMap();
    addRestaurantLocations(map);
  }, []);

  return (
    <div className="App">
      <h1>My Restaurant</h1>
      <ul id="locations">
        <li><b>My Restaurant - Upper East Side</b> <br/> 300 E 77th St, New York, NY 10075 </li>
        <li><b>My Restaurant - Hell's Kitchen</b><br/> 725 9th Ave, New York, NY 10019</li>
        <li><b>My Restaurant - Lower East Side</b><br/> 102 Norfolk St, New York, NY 10002</li>
      </ul>
      <div id="map"></div>
    </div>
  );
}

Finally, cleanup the resources so that memory leaks wont be introduced into the application. To do this, copy the following highlighted code snippet in your useEffect :

function App() {

  useEffect( async () => {
    const map = await initializeMap();
    addRestaurantLocations(map);

    return function cleanup() {
      map.remove();
    };

  }, []);

  return (
    <div className="App">
      <h1>My Restaurant</h1>
      <ul id="locations">
        <li><b>My Restaurant - Upper East Side</b> <br/> 300 E 77th St, New York, NY 10075 </li>
        <li><b>My Restaurant - Hell's Kitchen</b><br/> 725 9th Ave, New York, NY 10019</li>
        <li><b>My Restaurant - Lower East Side</b><br/> 102 Norfolk St, New York, NY 10002</li>
      </ul>
      <div id="map"></div>
    </div>
  );
}

Voilà! run npm start and see your restaurant homepage that displays the many branches of the restaurant. You now have a fully functioning map on your restaurant’s homepage that displays its branches with additional information displayed in popovers!

My Restaurant app completed with popover pins showing on map

You can follow the Amplify Hosting documentation here to successfully host your restaurant’s homepage!

Clean up

Now that you have finished this walk through, it’s recommended that you delete your Amplify app if you don’t plan to use it any further. This ensures that your resources won’t incur unexpected charges in the event someone gains access to your project’s credentials.

To delete all the local Amplify associated files and the Amplify project in the backend, run the following command:

$ amplify delete

Conclusion

In this blog post, we covered how to

  • Configure a map in AWS
  • Initialize and display a map to your react application
  • Display location markers on a map with customized popover text

Next Steps: For more features and documentation on Amplify Geo, you can visit the Amplify Geo documentation

We are going to be adding more features to this new Amplify category, so stay tuned on our Twitter and Discord communications channels! 🎉