Cómo empezar con Azure Maps: Render API y Search API

Podrías pensar que Azure Maps sólo trata de mostrar mapas dentro de tu aplicación pero lo cierto es que es algo más. A lo largo de estos días me gustaría mostrarte cuáles son las capacidades que se ofrecen bajo este nombre y cómo empezar con ellas a través de algunos ejemplos. En este post te hablaré de las APIs más básicas: render y search.

Creación de la cuenta de Azure Maps

Como ocurre con otros servicios que proporciona la plataforma, Azure Maps se trata de un conjunto de APIs a las cuales tenemos acceso a través de una key proporcionada por la plataforma Microsoft Azure. Para dar de alta el servicio, accede al portal, haz clic en Create a resource y busca Azure Maps.

Create a resource – Azure Maps

La única información que tendrás que proporcionar será el nombre que quieres darle al servicio, la suscripción donde quieres desplegarlo, el resource group y como pricing tier sólo está disponible el modo Standard.

Create Azure Maps Account

Una vez desplegado ya tendrás disponible la Key que necesitas para poder realizar las llamadas a las diferentes APIs que ofrece el servicio.

Azure Maps – Keys

Render API

Azure Maps te ofrece el renderizado de mapas dentro de tu aplicación a través de su API Render. Además, el propio servicio proporciona un control en JavaScript que te facilita muchísimo el trabajo. Para crear un mapa básico lo único que debes insertar en tu código HTML es lo siguiente:

<!DOCTYPE html>
<html>

<head>
    <title>Azure Maps</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="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>
</body>

</html>

Como código HTML solamente nos basta con crear un div donde será alojado el mapa a mostrar. En el CSS añadiremos algunos estilos para que el mapa ocupe toda la pantalla.

html,
body {
    width: 100%;
    height: 100%;
    padding: 0;
    margin: 0;
}

#map {
    width: 100%;
    height: 100%;
}

Por último necesitamos algo de JavaScript para instanciar el mapa.

//Render map
var AzureMapsKey = "<your azure maps key>",
    map = new atlas.Map("map", {
        "subscription-key": AzureMapsKey
    });

Como ves, el código es bastante sencillo. Simplemente debes utilizar atlas.Map para crear un nuevo mapa y pasárle como parámetro el nombre del div donde debe renderizar el contenido y la key generada por la plataforma cuando diste de alta el servicio.

Si ejecutas el archivo html en el navegador, el resultado será el siguiente:

Azure Maps – Basic map

Como puedes comprobar, es súper básico y simplemente muestra un mapa general del mundo. Lo que seguro necesitarás será la posibilidad de realizar búsquedas de lugares, tu ubicación en el mapa, etcétera. Sin embargo, esta es la base en la que nos apoyaremos para mostrar los resultados de todas las APIs que veremos de aquí en adelante.

Search Service

Esta API nos permite hacer búsquedas de direcciones, lugares, empresas, etcétera. También permite hacer búsqueda inversa, proporcionando las coordenadas y devolviendo la dirección asociada a la misma. Para verlo con un ejemplo aprovecha el código anterior y añade el siguiente código JavaScript al archivo azure-maps-search.js

//Render map
var AzureMapsKey = "<your azure maps key>",
    map = new atlas.Map("map", {
        "subscription-key": AzureMapsKey
    });

//Search
var searchLayer = "search";
map.addPins([], {
    name: searchLayer,
    cluster: false,
    icon: "pin-red"
});

//HTML 5 geolocation and Azure Maps Search
var yourLocation;
function success(pos) {
    yourLocation = pos;
    
    $.ajax({
        url: 'https://atlas.microsoft.com/search/fuzzy/json',
        type: "GET",
        data: {
            'api-version': '1.0',
            'subscription-key': AzureMapsKey,
            'query': 'restaurant',
            'lat': pos.coords.latitude,
            'lon': pos.coords.longitude,
            'radius': '100000'
        }

    }).done(function (data) {
        var searchPins = data.results.map((poi) => {
            var poiPosition = [poi.position.lon, poi.position.lat];
            return new atlas.data.Feature(new atlas.data.Point(poiPosition), {
                name: poi.poi.name,
                address: poi.address.streetName + ", " + poi.address.streetNumber,
                position: poi.position.lat + ", " + poi.position.lon,
                phone: poi.poi.phone,
                categories: poi.poi.categories.toString()
            });
        });

        map.addPins(searchPins, {
            name: searchLayer
        });


        //Get all longitudes
        var lons = searchPins.map((pin) => { return pin.geometry.coordinates[0] });
        //Get all latitudes
        var lats = searchPins.map((pin) => { return pin.geometry.coordinates[1] });

        //the min longitude and latitude
        var swLon = Math.min.apply(null, lons);
        var swLat = Math.min.apply(null, lats);
        //the max longitude and latitude
        var neLon = Math.max.apply(null, lons);
        var neLat = Math.max.apply(null, lats);

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

    });

    // Add a popup to the map which will display some basic information about a search result on hover over a pin
    var popup = new atlas.Popup();
    map.addEventListener("mouseover", searchLayer, (e) => {
        var popupContentElement = document.createElement("div");
        // popupContentElement.style.padding = "5px";
        popupContentElement.className = "poi-content-box";

        var popupNameElement = document.createElement("div");
        popupNameElement.innerText = e.features[0].properties.name;
        popupNameElement.className = "poi-title-box";
        popupContentElement.appendChild(popupNameElement);

        var popupInfoBoxElement = document.createElement("div");
        popupInfoBoxElement.className = "poi-info-box font-segoeui";
        popupContentElement.appendChild(popupInfoBoxElement);


        var popupAddressElement = document.createElement("div");
        popupAddressElement.innerText = e.features[0].properties.address;
        popupAddressElement.className = "info location";
        popupInfoBoxElement.appendChild(popupAddressElement);

        var popupPositionElement = document.createElement("div");
        popupPositionElement.innerText = e.features[0].properties.phone;
        popupPositionElement.className = "info phone";
        popupInfoBoxElement.appendChild(popupPositionElement);

        var popupCategoriesElement = document.createElement("div");
        popupCategoriesElement.innerText = e.features[0].properties.categories;
        popupCategoriesElement.className = "info category";
        popupInfoBoxElement.appendChild(popupCategoriesElement);

        popup.setPopupOptions({
            position: e.features[0].geometry.coordinates,
            content: popupContentElement
        });

        popup.open(map);
    });

}

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

//Get your coordinates
navigator.geolocation.getCurrentPosition(success, error, { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 });

Repasando el mismo, podemos comentar las siguientes acciones:

  1. Se renderiza el mapa inicial.
  2. Se genera una nueva capa en el mapa llamada searchLayer donde se mostrarán los resultados de la búsqueda que se realice.
  3. Se hace uso de la geolocalización (navigator.getCurrentPosition) proporcionada por HTML 5 para ser capaces de recuperar las coordenadas del usuario.
  4. En la función success (cuando hemos sido capaces de recuperar las coordenadas del usuario correctamente) lo primero que hacemos es realizar una llamada a la API search con las coordenadas del usuario y la clave de Azure Maps para localizar los restaurantes más cercanos en un radio de 10 kilómetros.
  5. Por cada resultado se genera un objeto de tipo Point donde se guardan los valores que me interesan del resultado (puedes comprobar los campos que tienes disponibles realizando la llamada del search directamente desde el navegador).
  6. Añado los pins que he generado a la capa searchLayer.
  7. Con el objetivo de centrar el mapa donde estan los resultados, recupero todas las longitudes y todas las latitudes de los resultados que he obtenido y obtengo los mínimos y los máximos para establecerlos como los límites de mi mapa, con map.setCameraBound.
  8. Para finalizar, creo un pop up para que cada vez que pase el ratón por alguno de los pins se me muestre información relativa al restaurante como el nombre, la dirección, el teléfono y las categorías a las que está asociado.

Si ejecutas de nuevo la página, primeramente te pedirá acceso a tu ubicación y te mostrará los restaurantes cercanos a donde te encuentras:

Azure Maps – Search API

También puedes probar con distintas ubicaciones simulando tus coordenadas.

El ejemplo completo está disponible en GitHub.

¡Saludos!