Azure Maps – Calcula rutas con Route API y conoce el tráfico con Traffic API

Una vez que ya sabes cómo empezar con Azure Maps y cómo funcionan las APIs Render y Search lo siguiente que necesitas saber es cómo calcular rutas entre dos puntos, además del tráfico en la zona. Para este post voy a utilizar el ejemplo que te mostré en el artículo anterior, por lo que te recomiendo que le eches un vistazo si todavía no lo has hecho.

Route Service

Una vez que tienes los puntos de interés reflejados en el mapa, lo interesante es poder interactuar con ellos de alguna forma. Route API se encarga del cálculo de rutas en diferentes medios de transporte (coche, camión, bicicleta o andando). Además, puedes añadir ciertas restricciones a la hora de calcular la ruta.

En el post anterior te enseñé cómo mostrar información de cada uno de los puntos de interés, simplemente pasando el ratón por encima por cada uno de ellos.

Azure Maps - Popup en los puntos de interés

Azure Maps – Search API

En este caso, lo que me interesa es que cuando haga clic en uno de los pins calcule la ruta a seguir desde mi localización y me la muestre en el mapa. Para ello, he creado un nuevo archivo HTML (map-route-and-traffic.html) que hace uso del Javascript anterior, para poder geolocalizarme y mostrar los puntos de interés, además de añadir una sección para mostrar información sobre la ruta devuelta por la API Route.

<!DOCTYPE html>
<html>

<head>
    <title>Azure Maps - Route</title>
    <link rel="stylesheet" href="https://atlas.microsoft.com/sdk/css/atlas.min.css?api-version=1.0" type="text/css" />
    <link rel="stylesheet" href="css/style.css" type="text/css" />
    <script src="https://atlas.microsoft.com/sdk/js/atlas.min.js?api-version=1.0"></script>
</head>

<body>
    <div id="routeInfo">
        <h2>Route Information</h2>
        <ul>
            <li>
                <label>Departure Time:</label>
                <label id="departureTime"></label>
            </li>
            <li>
                <label>Arrival Time:</label>
                <label id="arrivalTime"></label>
            </li>
            <li>
                <label>Distance:</label>
                <label id="lengthInKm"></label>
            </li>
            <li>
                <label>Travel Time:</label>
                <label id="travelTimeInSeconds"></label>
            </li>
            <li>
                <label>Traffic Delay:</label>
                <label id="trafficDelayInSeconds"></label>
            </li>
        </ul>
    </div>
    <div id="map"></div>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
        crossorigin="anonymous"></script>
    <script src="js/azure-maps-search.js"></script>
    <script src="js/azure-maps-route.js"></script>
</body>

</html>

Por otro lado, he creado un nuevo archivo JavaScript llamado azure-maps-route.js que controla el evento clic en cualquiera de los pins de la capa searchLayer. Lo primero que necesito es crear los objetos de tipo Point con el inicio y el fin de la ruta: startPoint y destinationPoint. Con ello, creo los pins que mostraré en el mapa (startPin y destinationPin) y centro el mismo utilizando las coordenadas de origen y de destino, utilizando el método map.setCameraBounds. Añado los pins al mapa con la configuración generada en las lineas anteriores.

map.addEventListener("click", searchLayer, (e) => {

    var
        startPoint = new atlas.data.Point([yourLocation.coords.longitude, yourLocation.coords.latitude]),
        coords = JSON.parse("[" + e.features[0].properties.position + "]"),
        destinationPoint = new atlas.data.Point([coords[1], coords[0]]),
        startPin = new atlas.data.Feature(startPoint, {
            title: "Your location",
            icon: "pin-round-blue"
        }),
        destinationPin = new atlas.data.Feature(destinationPoint, {
            title: e.features[0].properties.name,
            icon: "pin-blue"
        });

    // Fit the map window to the bounding box defined by the start and destination points
    var swLon = Math.min(startPoint.coordinates[0], destinationPoint.coordinates[0]),
        swLat = Math.min(startPoint.coordinates[1], destinationPoint.coordinates[1]),
        neLon = Math.max(startPoint.coordinates[0], destinationPoint.coordinates[0]),
        neLat = Math.max(startPoint.coordinates[1], destinationPoint.coordinates[1]);

    map.setCameraBounds({
        bounds: [swLon, swLat, neLon, neLat],
        padding: 50
    });

    // Add pins to the map for the start and end point of the route
    map.addPins([startPin, destinationPin], {
        name: "route-pins",
        textFont: "SegoeUi-Regular",
        textOffset: [0, -20]
    });

Para mostrar la ruta, creamos una nueva capa llamada routes, a la que podemos ajustarle el color, el ancho de la línea que traza el camino, etcétera.

   //Get directions
    var routeLayer = "routes";
    map.addLinestrings([], {
        name: routeLayer,
        color: "#2272B9",
        width: 5,
        cap: "round",
        join: "round",
        before: "labels"
    });

Por último, realizamos la llamada al servicio donde le pasamos como parámetros las coordenadas de inicio y de destino separadas por dos puntos:

  //Get the directions calling /route/directions
    $.ajax({
        url: 'https://atlas.microsoft.com/route/directions/json',
        type: 'GET',
        data: {
            'api-version': '1.0',
            'subscription-key': AzureMapsKey,
            'query': startPoint.coordinates[1] + ',' + startPoint.coordinates[0] + ':' + destinationPoint.coordinates[1] + ',' + destinationPoint.coordinates[0]
        }
    }).done(function (result) {
        var route = result.routes[0];

        //Route info      
        $("#departureTime").text(new Date(route.summary.departureTime).toLocaleTimeString());
        $("#arrivalTime").text(new Date(route.summary.arrivalTime).toLocaleTimeString());
        $("#lengthInKm").text((Math.round((route.summary.lengthInMeters / 1000) * 100 / 100)) + ' kilometers');
        $("#trafficDelayInSeconds").text((Math.round((route.summary.trafficDelayInSeconds / 60) * 100) / 100) + ' minutes');
        $("#travelTimeInSeconds").text((Math.round((route.summary.travelTimeInSeconds / 60) * 100) / 100) + ' minutes');
        $("#routeInfo").show();

        var routeCoordinates = [];
        for (var leg of route.legs) {
            var legCoordinates = leg.points.map((point) => [point.longitude, point.latitude]);
            routeCoordinates = routeCoordinates.concat(legCoordinates);
        }

        var routeLinestring = new atlas.data.LineString(routeCoordinates);
        map.addLinestrings([new atlas.data.Feature(routeLinestring)], { name: routeLayer });        

    }).fail(function () {
        //error
        console.warn('ERROR(' + err.code + '): ' + err.message);
    });
});

Cuando la llamada es satisfactoria, en el apartado done se muestra el resumen de la ruta devuelta, utilizando los valores de result.routes[0].summary, y se recopilan las coordenadas que dibujarán la línea de ruta que mostraremos en el mapa. Añadimos la línea al mapa a través de map.addLinestring.

El resultado será el siguiente:

Azure Maps – Route API

Traffic Service

La API Traffic está pensada para aquellas aplicaciones que requieran conocer el tráfico. El servicio proporciona tanto tráfico como accidentes que hayan podido ocurrir. En el ejemplo anterior añade el siguiente código después de map.addLinestrings:

  // Add Traffic Flow to the Map
        map.setTraffic({
            flow: "relative"
        });

En este ejemplo se ha configurado el flujo a relative, que es la velocidad de la carretera en relación a cuando no hay tráfico. También se puede establecer como absoluterelative-delay, que muestra la velocidad relativa en la que difiere cuando no hay tráfico.

En este caso, además de la ruta dibujada en el apartado anterior, se mostrarán líneas de diferentes colores en cada una de las carreteras que se muestren en el mapa. Los colores dependerán del flujo actual de tráfico en cada una de ellas.

Azure Maps – Route API and Traffic API

En my GitHub tienes el ejemplo completo.

¡Saludos!