Build a Map Application on AWS in 10 Steps
Last week, the team I work on at AWS Amplify launched new map UI components. I wanted to take this opportunity to show what you can build using Amplify Geo and Amplify Studio together!
I'm an avid hiker, and AllTrails is one of my favorite sites, I duplicated a very, very small portion of their UI for this tutorial!
1. Create a new Studio Instance
Head to the Amplify Console and select build a new app.
Once your Studio instance is deployed, click "Launch Studio".
2. Create your data model
Once you're in Studio, click "Data" under "Set up" on the lefthand navigation. Add one model, Hike
. Add the fields name
, difficulty
, location
, lat
, long
, length
, time
, and coverImage
. lat
, long
, and length
should be floats, all other fields should be strings.
Once you've implemented your data model, click "Save and Deploy"!
Now, go to the "Content" tab under "Manage" and add a few hikes! You can find the latitude and longitude by Googling "trail name lat and long".
3. Enable auth
Once your data model is done deploying, go to "Authentication" under "Set up". Then deploy the default authentication mode. We won't implement a full sign in flow, though you can learn about how to here, we will just need auth enabled to enable mapping.
4. Change UI components in Figma
Head to the AWS Amplify UI Kit. Duplicate the Figma file to your account, and then head to the "My Components" page. You'll see a "CardB" card which we will modify for our app.
- Round the card corners by adding a border-radius to the card and the top corners of the image.
- Copy a small button from the
Primitives
page and paste it onto the card. - Change what's currently an address into three separate text fields, the middle one being a dot character.
When you're done, your card should look similar to the above.
I also deleted the components I'm not using.
5. Figma to Code
Then, back in Studio, head to the "UI Library" page. Click "Get Started" and paste in the link to your Figma file. Then accept all of your components.
Then, click on the CardB
component on the "UI Library" page. Then click "Configure". Once here, we'll bind data to our component!
Click the image, then set the src
to the hike.coverImage
. Then, click the $99 USD
and set the label
to hike.name
. Set the information about the beds/baths/sqft to the name of the hike.location
.
Set the button label to hike.difficulty
. I also want this element to be a div instead of a button - so I'll set the as
prop to "div".
I'll set the first text field under that to a concatenated property: hike.length
+ miles
. I set the second one to the hike.time
.
My final card looks like this:
I want to display all my hikes in a list, so I'll create a collection. Click the "Create a collection" button on the right side. I called my collection Hikes
.
Add margin as needed on the right side, and I added search and pagination. I kept the dataset as is, though you can add sorts or filters as desired.
6. Setup Local Code
Now we're ready to integrate this list into our app! First, create a React app:
npx create-react-app amplify-maps
Install the Amplify libraries and React components:
npm i aws-amplify @aws-amplify/ui-react
Run Amplify pull for your project. In Studio on the top right corner, you'll see a "Local setup instructions" link with a unique command for your app. Run this in your command line.
amplify pull --appId your-app-id --envName staging
Then, configure Amplify within your index.js
file:
// Add needed imports
import { Amplify } from 'aws-amplify'
import config from './aws-exports'
import { AmplifyProvider } from '@aws-amplify/ui-react'
import '@aws-amplify/ui-react/styles.css'
// Configure Amplify
Amplify.configure(config)
// use the Amplify Provider component to intialize CSS
ReactDOM.render(
<AmplifyProvider>
<App />
</AmplifyProvider>,
document.getElementById('root')
)
Now, go to your App.js
file and import the Hikes
component.
import { Hikes } from './ui-components'
Replace the body of your App.js
file with the following:
function App () {
return (
<div className='container'>
<Hikes />
</div>
)
}
Now, if you run your React server, you'll see your list of hikes on the page!
7. Add Geo
Let's add the map to our application. First, we'll need to initialize Amplify Geo.
Run amplify add geo
from your command line.
Answer the ensuing questions with the following:
? Select which capability you want to add: Map (visualize the geospatial data)
✔ Provide a name for the Map: (enter for default)
✔ Who can access this Map? · Authorized and Guest users
Available advanced settings:
- Map style & Map data provider (default: Streets provided by Esri)
✔ Do you want to configure advanced settings? (y/N) · no
Now, run amplify push
in order to deploy your changes.
8. Add a map to your UI
Now, we'll use the Amplify Geo UI components to add a map to the page. I'll use Denver's latitude and longitude as the center of my map. You also may want to play around with the initial Zoom level.
import { MapView } from '@aws-amplify/ui-react'
...
function App () {
return (
<div className='container'>
<Hikes />
<MapView
initialViewState={{
latitude: 39.113014,
longitude: -105.358887,
zoom: 7
}}
/>
</div>
)
}
Now, let's add markers to the map for each hike! I'll add a useEffect
to query for all of my Hikes.
// Add needed imports
import { useEffect, useState } from 'react'
import { Hike } from './models'
import { DataStore } from 'aws-amplify'
...
// at the top of App.js pull all the hikes and store them in state
const [hikes, setHikes] = useState([])
useEffect(() => {
const getHikes = async () => {
const hikes = await DataStore.query(Hike)
setHikes(hikes)
}
getHikes()
}, [])
Now, let's loop through the hikes and add a Marker
instance for each with its latitude and longitude:
import { Marker } from 'react-map-gl'
...
function App () {
return (
<div className='container'>
<Hikes />
<MapView
initialViewState={{
latitude: 39.113014,
longitude: -105.358887,
zoom: 7
}}
>
{hikes.map(hike => (
<Marker
latitude={hike.lat}
longitude={hike.long}
key={hike.id}
/>))}
</MapView>
</div>
)
}
Now your map should look something like this:
9. Add popups
Now we have a map with markers on it, let's add popups when a marker is clicked on so you can see more info about the hike! I'll render the CardB
component if the popup is open.
// Import the Popup
import { Marker, Popup } from 'react-map-gl'
...
function MarkerWithPopup ({ hike, latitude, longitude }) {
const [showPopup, setShowPopup] = useState(false)
// event listener that toggles whether the popup is displayed
const handleMarkerClick = ({ originalEvent }) => {
originalEvent.stopPropagation()
setShowPopup(true)
}
// render the marker and the popup, render the CardB again within the popup.
return (
<>
<Marker
latitude={latitude}
longitude={longitude}
onClick={handleMarkerClick}
/>
{showPopup && (
<Popup
latitude={latitude}
longitude={longitude}
offset={{ bottom: [0, -40] }}
onClose={() => setShowPopup(false)}
maxWidth='95%'
closeOnMove
>
<CardB hike={hike} />
</Popup>
)}
</>
)
}
Change the application to display the MarkerWithPopup
instead of just the original marker!
{
hikes.map(hike => (
<MarkerWithPopup
latitude={hike.lat}
longitude={hike.long}
hike={hike}
key={hike.id}
/>)
)
}
10. Add Styling
I also added the following CSS to my index.css
file, please forgive the !important
s! They were needed to override the existing styling on the popups!
@import url('https://fonts.googleapis.com/css2?family=Inter:slnt,wght@-10..0,100..900&display=swap');
.container {
display: flex;
}
.maplibregl-popup-content, .mapboxgl-popup-content {
background-color: transparent !important;
box-shadow: none !important;
border-radius: none !important;
z-index: 5 !important;
max-width: 95% !important;
}
.maplibregl-popup-close-button, .mapboxgl-popup-close-button {
color: white !important;
font-size: 30px !important;
font-weight: bold;
}
Now your app should have working popups when you click on a marker!
Conclusion
In this tutorial, we used Amplify Studio, the Amplify CLI, and Amplify UI components to build out a map interface. If you want to delete the resources used in this tutorial, run amplify delete
in your CLI. I would love to hear your feedback as you build with Amplify, especially since Studio is still in developer preview at the time of this writing!