Sort stores by distance
Familiarity with front-end development concepts. Some advanced JavaScript required.
This series of tutorials teaches you how to create a store locator using Mapbox GL JS then sort the stores by their distance from a given location using the Mapbox GL Geocoder plugin and Turf.js:- Part 1: Build a store locator- Part 2: Sort stores by distance
This tutorial shows you how to sort store locations based on their distance from a geocoded point, using Mapbox GL JS, the Mapbox GL Geocoder plugin, and Turf.js.
This tutorial extends the map created in the Build a store locator using Mapbox GL JS tutorial. If you haven't completed that tutorial yet, you can do so before starting this project, or you can download the starter code in the Getting started section of this tutorial.
Getting started
To complete this tutorial, you will need:
- Store locator final project. This tutorial builds off of the code created in the Build a store locator using Mapbox GL JS tutorial. Create a copy of the final version of that code for this new project, or you can download the starter code here.
- A Mapbox access token. Your Mapbox access tokens are on your Account page.
- Mapbox GL JS. Mapbox GL JS is a JavaScript API for building web maps.
- The Mapbox GL Geocoder plugin. The Mapbox GL Geocoder plugin is the Mapbox GL JS wrapper library for the Mapbox Geocoding API.
- Turf.js. Turf is an open-source analysis library that performs spatial analysis in the browser and in Node.js.
- A text editor. Use the text editor of your choice for writing HTML, CSS, and JavaScript.
Add plugins and initialize the map
For this project, we recommend that you create a local folder called "sort-store-locator" to house your project files. You'll see this folder referred to as your project folder.
Download the starter-code
zip file. Inside you'll find an index.html
file and an img
folder that contains the custom marker you'll be using to show store locations. Open the index.html
file in a text editor. Make sure you use your own access token and set it equal to mapboxgl.accessToken
.
Add Mapbox GL geocoder plugin and Turf.js
Next, set up your document by adding the Mapbox GL Geocoder plug-in and Turf.js library links to your HTML file.
Copy the following code and paste it inside your <head>
tags after your links to mapbox-gl.js
and mapbox-gl.css
.
{/* Geocoder plugin */}
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.1-dev/mapbox-gl-geocoder.min.js"></script>
<link
rel="stylesheet"
href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.1-dev/mapbox-gl-geocoder.css"
type="text/css"
/>
{/* Turf.js plugin */}
<script src="https://npmcdn.com/@turf/turf/turf.min.js"></script>
Add geocoder control
Add the geocoder control to your JavaScript code using the constructor new mapboxgl.Geocoder
. In this case, you'll limit the search results to the Washington DC area using the bbox
parameter. There are several other parameters you can specify. You can read more about the available parameters in the documentation on GitHub.
Copy the code below and paste it inside your <script>
tags, inside your map.on('load', () => { ... })
after map.addSource()
.
const geocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken, // Set the access token
mapboxgl: mapboxgl, // Set the mapbox-gl instance
marker: true, // Use the geocoder's default marker style
bbox: [-77.210763, 38.803367, -76.853675, 39.052643] // Set the bounding box coordinates
});
map.addControl(geocoder, 'top-left');
Now add some CSS to style your new geocoding search bar. You can add this code right before your closing </style>
tag.
.mapboxgl-ctrl-geocoder {
border: 0;
border-radius: 0;
position: relative;
top: 0;
width: 800px;
margin-top: 0;
}
.mapboxgl-ctrl-geocoder > div {
min-width: 100%;
margin-left: 0;
}
Save your HTML document, and refresh the page in your web browser. The result should look like this, with a new geocoder control appearing on the map:
Notice what happens when you search for an address using the geocoding form you have created. The map flies to the location you specified and adds a marker at the matching location.
Sort store list by distance
Next, you will calculate the distance between the searched location and the stores, add the results to your GeoJSON data, and sort the store listings by distance from the searched point.
Listen for a geocoder result
Create an event listener that fires when the user selects a geocoder result. When the user selects a place from the list of returned locations, save the coordinates in a variable called searchResult
. Copy the code below and paste it after your map.addSource()
function, before the closing bracket (}
) of your map.on()
function.
geocoder.on('result', (event) => {
const searchResult = event.result.geometry;
// Code for the next step will go here
});
Find distance from all locations
Next you'll use Turf.js to find the distances between your new point and each of the restaurant locations. Turf.js can do a wide variety of spatial analysis functions, which you can read about in the Turf documentation. In this tutorial you will use the distance
method.
Within your geocoder.on('result', () => {...});
function, use a forEach
loop to iterate through all the store locations in your GeoJSON (remember, you stored these in the stores
variable earlier), define a new property for each object called distance
, and set the value of that property to the distance between the coordinates stored in the searchResult
and the coordinates of each store location. You will do this using the turf.distance()
method, which accepts three arguments: from, to, options
.
const options = { units: 'miles' };
for (const store of stores.features) {
store.properties.distance = turf.distance(
searchResult,
store.geometry,
options
);
}
// Code for the next step will go here
For each feature in your GeoJSON, a distance
property is applied or will be updated each time a new geocoder result is selected.