paint-brush
Creating a Ride-a-request Application Using TomTom Maps APIby@girishamudala
103 reads

Creating a Ride-a-request Application Using TomTom Maps API

by Girish AmudalaAugust 26th, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

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.
featured image - Creating a Ride-a-request Application Using TomTom Maps API
Girish Amudala HackerNoon profile picture

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})

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


Ride Request Form

Multiple locations with markers & optimized route


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.