TomTom’s Snap to Roads API matches GPS coordinates to detailed road information to determine the most probable routes. This tutorial teaches you to create a React app that reconstructs driver journeys using Snap to Roads.
Using the Snap to Roads API with React
TomTom’s Snap to Roads API uses GPS data to reconstruct driver journeys. The API matches location data with road network information to determine the most probable route.
The Snap to Roads API also takes other factors into account, such as what type of vehicle is being driven, speed limits, lanes, and the amount of time it has previously taken the driver to reach various locations. These factors are sent as parameters by the REST API.
You can also record multiple point coordinates along the driver’s journey. Then, we can take these point coordinates and send them to the API, which takes the coordinates and returns relevant information about the coordinate routes. The API’s response can also include more descriptive details on the road traveled, such as names, types of roads, speed restrictions, class of road, etc.
Snap to Roads allows for smooth visualization of relevant information in ride-hailing services and on-demand delivery applications. It’s also useful for route tracking in fleet logistics and insurance applications. You can use it for information about road attributes, such as speed limit, elevation, and road ownership.
In this article, we’ll build a demo in which we’ll input two location coordinates, send this information to the Snap to Roads API, and draw the returned routes on our TomTom maps. This will provide a helpful visual representation of the new routes and how to use them.
Getting Started
There are many ways to spin up a React application, but it’s advisable to use the Create React App (CRA) library.
Let’s jump straight to the code. To create a React app using Create React App, make sure you currently have Node.js installed. You can check to see if you have Node.js installed by typing the following into your terminal:
node -v
If Node.js is installed, that command should return the current version. If not, go to the Node.js website and download the latest version.
Next, go into the terminal/command prompt and initiate your app using the name.
npx create-react-app snap-to-road
Navigate into your project folder:
cd snap-to-road
You can now start the project:
npm start
You need to be able to send API requests with your endpoints, so you need an API key from TomTom maps. Sign in to TomTom, generate an API key, and edit it to enable the Snap to Roads API:
Installation
Before you can use TomTom in your app, you’ll have to install the TomTom package and axios:
npm install @tomtom-international/web-sdk-maps -save
Axios will allow us to make API requests to the Snap to Roads API:
npm i axios
Adding the TomTom Map
Now, let’s go into the component where we will create the map:
import "./styles.css";
import "@tomtom-international/web-sdk-maps/dist/maps.css";
import * as ttmaps from "@tomtom-international/web-sdk-maps";
import { useState, useEffect, useRef } from "react";
export default function App() {
const mapElement = useRef();
const [mapZoom, setMapZoom] = useState(17);
const [map, setMap] = useState({});
useEffect(() => {
let map = ttmaps.map({
key: "{{TOMTOM_API_KEY}}",
container: mapElement.current,
center: [12.3, 32.992578],
zoom: mapZoom
});
setMap(map);
return () => map.remove();
}, []);
return (
<div className="App">
<div ref={mapElement} className="mapDiv"></div>
</div>
);
}
This imports the TomTom library and displays it in the DOM using React’s useRef.
Next, import the TomTom library and default CSS styles into App.js. You’ll also import useState and useEffect.
You need to add certain values, like the map zoom value and the map itself using useState. Then, you can initialize the map with useEffect and display it with mapElement.
Using the Snap to Roads API
Now, let’s say we’re moving from point A (4.6104, 52.3757) to point B (4.6140, 52.3834). As we send these coordinates to the API, we also send two parameters: fields and key (our API key). The fields object contains the specific information you need from the API endpoint. For this example, this appears as follows:
{
projectedPoints {
type,
geometry {
type,
coordinates
},
properties {
routeIndex
}
}, route {
type,
geometry {
type,
coordinates
},
properties {
id,
speedRestrictions {
maximumSpeed {
value,
unit
}
}
}
}
}
You can also find more nested fields sample objects in our documentation.
Let’s get back to the code. Within the component, import axios and create a getSnapFunction that makes a request to the API.
import axios from "axios"
const getSnapFunction = () => {
axios.get("https://api.tomtom.com/snap-to-roads/1/snap-to-roads?points=4.6104,52.3757;4.6140,52.393&fields={projectedPoints{type,geometry{type,coordinates},properties{routeIndex}},route{type,geometry{type,coordinates},properties{id,speedRestrictions{maximumSpeed{value,unit}}}}}&key=8h504Wc4AXL6OPndqhrtKf70AovVBL3V").then((res) =>
{
console.log(res.data)
res.data.route.forEach(
(item) => {
map.addLayer({
id: Math.random().toString(),
type: "line",
source: {
type: "geojson",
data: {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "LineString",
properties: {},
coordinates: item.geometry.coordinates
}
}
]
}
},
layout: {
"line-cap": "round",
"line-join": "round"
},
paint: {
"line-color": "#ff0000",
"line-width": 2
}
});
}
)
map.setCenter([parseFloat(4.6104), parseFloat(52.3757)]);
}).catch((err) => console.log(err))
}
This returns the reconstructed route. Then, it loops this response through the route array.
Next, we used map.addLayer to draw each property of the array on the map. It now forms the full route, taking you from the takeoff point to the destination.
Finally, map.setCenter enables us to center the map on the route. Here’s the final map:
We’ve just covered the Synchronous Snap to Roads API. However, there’s also an Asynchronous Snap to Roads API, where users make a POST request and get back a batch ID. While making this request, we will send the several coordinate points and the query property within the body.
axios.post('https://api.tomtom.com/snap-to-roads/batch/1?key={TOMTOM_API_KEY}', {
{
batchItems: [
{
query: "/snap-to-roads?fields={projectedPoints{type,geometry{type,coordinates},properties{routeIndex}},route{type,geometry{type,coordinates},properties{id,speedRestrictions{maximumSpeed{value,unit}},address{roadName,roadNumbers,municipality,countryName,countryCode,countrySubdivision},elementType,traveledDistance,privateRoad,partOfTunnel,frc,formOfWay,roadUse,laneInfo{numberOfLanes},heightInfo{height,chainage},trafficSign{signType,chainage},trafficLight}},distances{total,ferry,privateRoad,publicRoad,road,offRoad}}&vehicleType=PassengerCar&measurementSystem=imperial",
post: {
points: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.4389141359581,
51.78057462411982
]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.439257458711324,
51.78057794294989
]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.43963296797358,
51.78064100067553
]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.44012113001449,
51.780690783028064
]
}
}
]
}
},
{
"query": "/snap-to-roads?fields={projectedPoints{type,geometry{type,coordinates},properties{routeIndex}},route{type,geometry{type,coordinates},properties{id,speedRestrictions{maximumSpeed{value,unit}},address{roadName,roadNumbers,municipality,countryName,countryCode,countrySubdivision},elementType,traveledDistance,privateRoad,partOfTunnel,frc,formOfWay,roadUse,laneInfo{numberOfLanes},heightInfo{height,chainage},trafficSign{signType,chainage},trafficLight}},distances{total,ferry,privateRoad,publicRoad,road,offRoad}}&vehicleType=PassengerCar&measurementSystem=metric",
post: {
points: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.4389141359581,
51.78057462411982
]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.439257458711324,
51.78057794294989
]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.4389141359581,
51.78057462411982
]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.439257458711324,
51.78057794294989
]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.43963296797358,
51.78064100067553
]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
19.44012113001449,
51.780690783028064
]
}
}
]
}
}
]
}
})
The response will contain a batch ID:
{
"batchId": "16178e70-8331-459f-abc8-251e708f5edb"
}
We now take this batch ID and send another request to another endpoint, checking the status of our Snap API request:
axios.get('https://api.tomtom.com/snap-to-roads/batch/1/c435cae3-c8f2-4d76-b08b-304529c967eb/status?key={TOMTOM_KEY}').then((res) => console.log(res.data)).catch((err) => console.log(err)
If it’s ready, it will return Completed.
{
"state": "Completed",
"statistics": {
"totalCount": 2,
"successes": 2
}
}
As the processing of batch data may take some time to complete, it is important to check the status before attempting to obtain the route data. Attempting to download route data before processing has completed will result in an error.
Once the process is complete, you can get the route data by sending a GET request to the download endpoint. This sends a response with the route data. The route data will take the shape of the query property in the body of the POST request we sent earlier.
axios.get('https://api.tomtom.com/snap-to-roads/batch/1/c435cae3-c8f2-4d76-b08b-304529c967eb?key={TOMTOM_KEY}').then((res) => console.log(res.data)).catch((err) => console.log(err)
Conclusion
Now that you know how to use TomTom’s Snap to Roads API to retrieve relevant information about a set of route coordinates, and display the route on a map in our React app, you can start using this API in your own applications. For example, you could use this API to create a fleet logistics application that analyzes delivery drivers’ routes and speed. You can use this to determine how fast delivery orders are fulfilled.
Synchronous Snap to Roads is best for analyzing single trips. If you need to analyze batches of trips in one call, try Asynchronous Snap to Roads.
To learn more about each endpoint of this API, explore the following resources:
- Synchronous Snap to Roads
Asynchronous Snap to Roads:
Submission: Send an HTTPS POST request that responds with a unique job ID
Status: Check the status of a submitted job
Download: Download the results of your submission
Visit the TomTom Developer Portal to learn more about TomTom Maps.