This post will walk you through creating a ride-a-request application using TomTom Maps API. This application will allow users to input multiple pick-up and drop-off locations, calculate the optimal route, and display it on a map. We’ll cover everything from obtaining the API key to rendering the optimized route on a map.
Step 1: Setting Up TomTom API
Before diving into the code, you’ll need to sign up on the TomTom Developer Portal and obtain an API key. This key will allow you to access TomTom’s services such as routing, geocoding, and maps.
Step 2: Implementing the Ride Request Functionality
The core of the application involves collecting addresses, converting them to coordinates, and calculating the optimal route. Here’s how you can do it:
def ride_request(request):
if request.method == 'POST':
form = RideForm(request.POST)
if form.is_valid():
ride = form.save(commit=False)
# Get coordinates for the pickup and drop locations
pickup_coords = get_coordinates(ride.pickup_address)
pickup_coords_1 = get_coordinates(ride.pickup_address_1)
pickup_coords_2 = get_coordinates(ride.pickup_address_2)
drop_coords = get_coordinates(ride.drop_address)
# Ensure all coordinates are available
if all([pickup_coords, pickup_coords_1, pickup_coords_2, drop_coords]):
# Set the coordinates
ride.pickup_latitude, ride.pickup_longitude = pickup_coords
ride.pickup_latitude_1, ride.pickup_longitude_1 = pickup_coords_1
ride.pickup_latitude_2, ride.pickup_longitude_2 = pickup_coords_2
ride.drop_latitude, ride.drop_longitude = drop_coords
# Save the ride and redirect to the success page
try:
ride.save()
return redirect('success_page', pickup_lon=ride.pickup_longitude, pickup_lat=ride.pickup_latitude,
pickup_lon_1=ride.pickup_longitude_1, pickup_lat_1=ride.pickup_latitude_1,
pickup_lon_2=ride.pickup_longitude_2, pickup_lat_2=ride.pickup_lat_2,
drop_lon=ride.drop_longitude, drop_lat=ride.drop_latitude)
except IntegrityError as e:
messages.error(request, f'IntegrityError: {str(e)}')
else:
messages.error(request, 'Error getting coordinates. Please try again.')
else:
form = RideForm()
return render(request, 'maps/ride_request.html', {'form': form})
In this snippet, the application accepts user input for multiple addresses, converts these addresses into coordinates using the get_coordinates function, and saves the data for later use.
def get_coordinates(address):
"""
Get coordinates (latitude, longitude) for a given address using TomTom Geocoding API.
"""
api_key = 'YOUR_TOMTOM_API_KEY'
base_url = 'https://api.tomtom.com/search/2/geocode/{address}.json'
# Prepare the URL with the address and API key
url = base_url.format(address=address)
params = {'key': api_key}
# Make the request to TomTom Geocoding API
response = requests.get(url, params=params)
data = response.json()
# Check if the request was successful
if response.status_code == 200 and data.get('results'):
# Extract coordinates from the response
result = data['results'][0]
if 'position' in result:
coordinates = result['position']
return coordinates.get('lat'), coordinates.get('lon')
else:
print(
f"Error getting coordinates for {address}: 'position' key not found in the response.")
return None
else:
# Handle errors or return a default value
print(
f"Error getting coordinates for {address}: {data.get('message')}")
return None
Step 3: Calculating the Optimized Route
Once you have the coordinates, the next step is to calculate the optimized route. TomTom’s Waypoint Optimization API helps in determining the most efficient path between multiple points.
def get_optimized_route(*pickup_coords, drop_coords):
api_key = 'YOUR_TOMTOM_API_KEY'
# Prepare the payload for the API
payload = {
'waypoints': [{'point': {'latitude': lat, 'longitude': lon}} for lon, lat in pickup_coords],
'options': {'travelMode': 'car'},
}
# Add the drop location to the waypoints
payload['waypoints'].append({'point': {'latitude': drop_coords[1], 'longitude': drop_coords[0]}})
# API request
response = requests.post(f'https://api.tomtom.com/routing/waypointoptimization/1',
params={'key': api_key},
json=payload)
if response.status_code == 200:
data = response.json()
if 'optimizedOrder' in data:
# Extract the optimized route
return [get_route_geometry(pickup_coords[i], pickup_coords[j])
for i, j in zip(data['optimizedOrder'], data['optimizedOrder'][1:])]
return None
This function sends a request to the TomTom API, receives the optimized order of waypoints, and then calculates the route geometry.
Step 4: Rendering the Map and Route
Finally, after obtaining the optimized route data, it’s time to render the map on your success_page.html.
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ride Request - Success</title>
<link rel="stylesheet" href="{% static 'maps/css/styles.css' %}">
<!-- Include TomTom Map SDK -->
<link rel="stylesheet" type="text/css"
href="https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.25.0/maps/maps.css" />
<script type="text/javascript"
src="https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.25.0/maps/maps-web.min.js"></script>
</head>
<body>
<div class="container">
<div class="map-container" id="dynamic-map"></div>
</div>
<!-- Map Initialization Script -->
<script type="text/javascript">
var map;
var pickup_lon = {{ pickup_lon }};
var pickup_lat = {{ pickup_lat }};
var pickup_lon_1 = {{ pickup_lon_1 }};
var pickup_lat_1 = {{ pickup_lat_1 }};
var pickup_lon_2 = {{ pickup_lon_2 }};
var pickup_lat_2 = {{ pickup_lat_2 }};
var drop_lon = {{ drop_lon }};
var drop_lat = {{ drop_lat }};
var routeGeometry = {{ route_data.route_geometry| safe }};
var geomatryCoordinates = routeGeometry.geometry.coordinates;
const API_KEY = 'YOUR_TOMTOM_API_KEY';
function initMap() {
//let center = [(pickup_lat + drop_lat) / 2, (pickup_lon + drop_lon) / 2];
let center = [pickup_lon, pickup_lat];
console.log('center:', center)
map = tt.map({
key: API_KEY,
container: 'dynamic-map',
//stylesVisibility: {
// trafficIncidents: true
//},
center: center,
bearing: 0,
maxZoom: 21,
minZoom: 1,
pitch: 60,
zoom: 12,
//style: `https://api.tomtom.com/style/1/style/*?map=2/basic_street-satellite&poi=2/poi_dynamic-satellite&key=${API_KEY}`
});
map.addControl(new tt.FullscreenControl());
map.addControl(new tt.NavigationControl());
map.on('load', () => {
console.log('Map loaded successfully!');
// Add markers for all pickup locations and drop location
var pickupMarker = new tt.Marker({ color: 'green' }).setLngLat([pickup_lon, pickup_lat]).addTo(map);
var pickupMarker1 = new tt.Marker({ color: 'blue' }).setLngLat([pickup_lon_1, pickup_lat_1]).addTo(map);
var pickupMarker2 = new tt.Marker({ color: 'orange' }).setLngLat([pickup_lon_2, pickup_lat_2]).addTo(map);
var dropMarker = new tt.Marker({ color: 'red' }).setLngLat([drop_lon, drop_lat]).addTo(map);
try {
// Iterate through each set of coordinates and add route layer
geomatryCoordinates.forEach((coordinates, index) => {
var routeGeometry = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: coordinates,
},
};
// Check if the routeGeometry is a valid GeoJSON object
if (isValidGeoJSON(routeGeometry)) {
map.addLayer({
'id': `route-${index}`,
'type': 'line',
'source': {
'type': 'geojson',
'data': routeGeometry,
},
'layout': {
'line-join': 'round',
'line-cap': 'round',
},
'paint': {
'line-color': '#3887be',
'line-width': 8,
'line-opacity': 0.8,
},
});
console.log(`Route layer ${index} added successfully!`);
} else {
console.error(`Invalid GeoJSON format for route ${index}. Creating a simple LineString.`);
// Attempt to create a LineString GeoJSON
var simpleRouteGeometry = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: coordinates,
},
};
map.addLayer({
'id': `route-${index}`,
'type': 'line',
'source': {
'type': 'geojson',
'data': simpleRouteGeometry,
},
'layout': {
'line-join': 'round',
'line-cap': 'round',
},
'paint': {
'line-color': '#3887be',
'line-width': 8,
'line-opacity': 0.8,
},
});
console.log(`Route layer ${index} added successfully with new GeoJSON.`);
}
});
} catch (error) {
console.error('Error handling GeoJSON:', error);
}
function isValidGeoJSON(data) {
return typeof data === 'object' && data !== null && data.type === 'Feature';
}
initMap(); // Call the initMap function
</script>
</body>
</html>
This HTML code initializes the TomTom map, places markers on the pickup and drop-off points, and draws the route between them.
Result: Ride Request Form & Success Map
Note: The code provided above is a simplified example to demonstrate the basic functionality of requesting a ride and calculating routes using TomTom’s API. The actual implementation may differ and include additional features or variations based on specific requirements. For more detailed information and advanced usage, please refer to the official TomTom Developer Documentation.
Top comments (0)