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.
Before diving into the code, you’ll need to sign up on the
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})
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.
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