Saltar al contenido →

MapKit JS. Guía de integración de Apple Maps en la web. Parte I

Otra de las novedades que nos ha traído la WWDC 2018 es el salto de los mapas de Apple a la web. Desde el día de la Keynote los desarrolladores tenemos a nuestra disposición MapKit JS, el framework de desarrollo web para los mapas.

A lo largo de esta guía, y sin que sirva de precedente, daremos un descanso a Xcode y a nuestro querido Swift y nos adentraremos en JavaScript y HTML.

Para ilustrar el artículo vamos a desarrollar una web que tendrá…

  • Una ruta turística por Madrid
  • Una carga masiva (bulk) de pins o annotations
  • Una carga más ligera de pins
  • Buscador de lugares
  • Calculador de rutas

Pues vamos a empezar.

Obtener una clave MapKit JS

Si prefieres no leer esta parte puedes ver la sesión de la WWDC 2018 donde hablaban de cómo generar el identificador y clave.

Lo primero que necesitamos es un token JWT para poder usar el mapa en nuestra página HTML. Este proceso lo podemos dividir en tres pasos

  1. Crear el Identificador de App
  2. Generar el archivo con la clave
  3. Crear un token JWT a partir del archivo anterior

Nota importante: necesitamos una cuenta de pago de desarrollador de Apple para poder realizar esta integración.

Identificador de la App

Vamos a la sección Certificates, Identifiers & Profiles que podemos encontrar en la página de nuestra cuenta de desarrolladores de Apple. Pulsamos en la opción Maps IDs de la sección Identifiers y pinchamos en el botón con la imagen (+) de la esquina superior derecha.

Completamos el formulario, mención especial al identificador de app, que debe empezar por maps. y continuar con DNS inverso (esto último es una recomendación).

Revisamos los datos y pulsamos en el botón Register.

Generar Archivo con la clave (P8)

Con el identificador de App creado ya podemos generar el archivo de clave. Esto lo hacemos desde la sección Keys. Allí pulsamos en el botón con la imagen (+) y rellenamos el formulario, sin olvidarnos de acceder a la opción Configure donde seleccionamos el identificador de App de la sección anterior.

Tras confirmar los datos ya podemos descargar el archivo con el contenido que hemos generado. Este archivo sólo se puede descargar una vez y no debe compartirse con nadie. También es importante saber que aquí podemos consultar el valor de la Key ID que luego necesitaremos para generar el token.

Generar el token JWT

Con el archivo P8 que hemos descargado en el punto anterior ya estamos en disposición de generar el token JWT. Para ello necesitamos una librería que cumpla con este estándar de seguridad. En su página puedes elegir entre las muchas existentes para los diferentes lenguajes de programación.

Pero para que no tengas que pelearte con la generación del token hemos tenemos listo un script python que generar los token para MapKit JS. Sólo teneís que visitar este repositorio de GitHub y allí encontraréis el script.

Configura y personaliza el mapa

Incluir una mapa en una página HTML sólo requiere por nuestra parte declarar una etiqueta DIV donde mostrar el mapa, importar el framework de MapKit JS y por último inicializar el mapa.

Vamos a ver un poco más en detalle cada uno de estos pasos

1. La capa DIV: Tenemos que indicar en que parte de la página web vamos a mostrar el mapa. Esto lo hacemos con una etiqueta DIV a la que proporcionamos un atributo ID que nos servirá para referenciar la capa más tarde. En el ejemplo le hemos añadido el atributo style para hacer que la capa ocupe toda la ventana del navegador.

2. Importar el Framework: Necesitamos decirle al motor JavaScript del navegador dónde están las funciones y estructuras que maneja el mapa. Apple lo tiene alojado en su propio CDN así que no necesitamos descargarlo en local.

3. Inicializar el mapa: El último paso, y aquí es donde pasamos el token JWT para que el servidor de Apple nos verifique como usuarios válidos del framework.

Ahora vamos a configurar el aspecto que tendrá nuestro mapa. Hay que decir que la cantidad de parámetros con los que podemos configurar el mapa es muy grande, desde el color de tinte, el tipo de mapa, lenguaje, posición del usuario… Todas las opciones se pueden consultar en la documentación de la clase mapkit.MapConstructorOptions.

Por último creamos una clase mapkit.Map a la que pasamos el nombre de la etiqueta DIV donde pintará el mapa y los parámetros de configuración.

Pero además de parametrizar el mapa también podemos suscribirnos a sus evento. Aquí tenéis una lista con todos los eventos que emite un objeto mapkit.Map

Nombre del evento Descripción
region-change-start La región visible del mapa va a cambiar
region-change-end Se ha producido un cambio en la región visible del mapa
scroll-start El usuario ha iniciado una operación de scroll sobre el mapa
scroll-end La operación de scroll ha terminado
zoom-start El usuario ha iniciado una operación de *zoom* en el mapa
zoom-end La operación de zoom ha terminado
map-type-change El tipo de mapa ha cambiado (Imagen satélite, estándar, híbrido)

Buscar lugares y añadir Pins (Annotations)

Ahora podemos ver el mapa en nuestra página web y comprobamos que es idéntico a los mapas de Apple en iOS y macOS. Pero ver un mapa no es muy divertido. ¿Sabéis lo que sí que es divertido? Buscar lugares.

¡Pues manos a la obra! En nuestra web de ejemplo tenemon un input text donde escribiremos la dirección que queremos situar en el mapa.

Vamos a estar atentos para cuando el usuario pulse la tecla ENTER, momento en el que buscaremos sobre el mapa la dirección que haya escrito en el campo de texto.

En el script anterior comprobamos que la tecla pulsada se corresponde con el ENTER (código 13) y si es así obtenemos la dirección escrita por el usuario. Seguimos los siguientes puntos o indicaciones para entender qué hemos hecho.

  1. Las búsquedas en MapKit JS recaen en la clase mapkit.Search.
  2. Usamos la función search a la que le pasamos como parámetro la dirección indicada por el usuario y la función donde obtendremos los resultados (se parece a los closures, ¿verdad?… la programación funcional también existe en Javascript)
  3. Si no hay errores procedemos a recuperar el contenido de la propiedad places del resultado. Esto no es más que un array con todas las localizaciones encontradas por MapKit. Pertenecen a la estructura place que contiene propiedades como la localización del lugar o su dirección en un formato legible para los usuarios, entre otras. Pero el mapa no puede mostrar places, los mapas sólo pueden mostrar annotations, así que con la función map convertimos todos esos place en mapkit.MarkerAnnotation
  4. Mostrar los resultados en el mapa es lo más sencillo. Con pasar el array de mapkit.Annotation a la función showItem del mapa es suficiente.

Por cierto, además de direcciones también podemos buscar nombres propios de lugares como por ejemplo Apple Puerta del Sol o Apple HQ

Cluster de Annotations

Mostrar un Annotation es divertido ¿Pero qué es más divertido aún? Poner más de 700 annotations en el mapa. MapKit JS permite añadir esa cantidad de annotations sin problema. Pero para el usuario quizá sea mejor agrupar los ‘annotations’ cercanos e ir mostrándolos según vaya haciendo zoom. Estamos hablando del clustering de annotations.

Así que ahora vamos a añadir los puntos de interés turístico de la ciudad de Madrid. El catálogo lo ha creado la oficina de Esmadrid, encargada de gestionar todo el turismo de la ciudad y cuyos datos están publicados en la plataforma Open Data del Ayuntamiento de Madrid.

Si los añadimos tal y como lo hemos hecho antes veremos las 700 annotations al mismo tiempo, y nos damos cuenta de que no nos enteramos de nada, sólo vemos un mar de colores sobre la patalla, cosa que no es muy funcional ni útil.

Apple nos da una solución a este problema y es mediante la creación de clusters de annotations. Esto no es más que agrupar las annotations que coincidan en determinados parámetros bajo una única. Las propiedades por las que se agrupan son:

  • clusteringIdentifier Un String que indica el grupo al que pertenece el annotation.
  • collisionMode La forma en la que se resuelve si dos annotation están muy cerca el uno del otro. Están establecidos en la enumeración mapkit.Annotation.CollisionMode.

Así que si a las mapkit.MarkerAnnotation los creamos igual que en el punto anterior, pero les añadimos estas propiedades tendremo un mapa como el que se ve a continuación. El label que tiene los cluster es el número de annotation que agrupan.

Annotations con imágenes

¿Podría haber algo más divertido que añadir 700 pins a un mapa? Sí, añadir un pin con una imagen personalizada.

En el framework nos encontramos con la clase mapkit.ImageAnnotation, un tipo de annotation igual que los mapkit.MakerAnnotation que hemos estado usando hasta ahora pero al que le podemos asignar una imagen para que la muestre en lugar del ballon que tienen por defecto.

He dicho que se le asigna una imagen, pero esto no es del todo cierto, tenemos que asignarle 3 versiones de la misma imagen. A los desarrolladores iOS esto les sonará mucho, y sí, lo que vamos a asignar es la misma imagen con 3 tamaños distintos para que MapKit muestre una u otra dependiendo de la resolución y tipo de dispositivo en el que se ha cargado el mapa.

En este caso vamos a usarlas para indicar los puntos de interes de la ruta Madrid de los Austrias de nuestra web de ejemplo.

Lo primero que hacemos es crear un objeto Coordinate que indica la posición que ocupará la Annotation en el mapa. En el paso 2 creamos las opciones del mapkit.ImageAnnotation y es aquí donde establecemos la propiedad url, que contiene tres propiedades llamadas 1, 2, y 3. A cada una de ellas le asignamos una URL que apunta a la imagen que queremos mostrar para cada resolución.

Los tamaños de las imágenes van en aumento, siendo la de menor tamaño asignada a la propiedad 1y la mayor a la propiedad 3.

Para terminar tenemos que indicar el tamaño de las imágenes, mediante un objeto de la clase Size que tiene como propiedades widthy height. La unidad de medida son pixels y pondremos el tamaño de la imagen de menor resolución.

No es obligatorio especificar las tres opciones de imagen, si sólo queremos o podemos usar una basta con establecer la propiedad 1 con la URL a la imagen.

Eventos de Annotations

Estaría muy bien poder realizar alguna acción cuando el usuario pulse sobre alguna de las annotations de nuestro mapa. Y al igual que el mapa tiene eventos las annotations también los tienen, así que ahora vamos a ver como realizar una acción determinada cuando el usuario pulse sobre una en nuestro mapa.

Hay que decir que el proceso de creación no varía en nada, lo único que tenemos que hacer es registrar el evento al que va a responder y el tipo de evento.

Evento Descripción
select El usuario pincha o toca sobre el annotation
deselect El annotation deja de estar seleccionado
drag-start El usuario comienza a arrastrar el annotation
dragging Se está procediendo a arrastrar
drag-end El usuario ha terminado de arrastrar el annotation

Esto se hace mediante la función addEventListener de la clase mapkit.Annotation (de la que heredan mapkit.MarkerAnnotation y mapkit.ImageAnnotation). Dicha función recibe tres parámetros:

  1. Un String con el nombre del evento al que queremos responder
  2. La función callback donde procesaremos el evento
  3. Un objeto que hará las veces de this dentro de la función callback

Vamos a ver todo esto en un ejemplo, haremos que las mapkit.ImageAnnotation que creamos en el punto anterior respondan al evento click. Cuando el usuario pulse sobre alguna de ellas mostraremos una ventana con información del lugar seleccionado.

Si miramos el código vemos que desde un documento JSON cargamos una array de objetos con datos de lugares de interés. Con la función map convertimos los venue en mapkit.ImageAnnotation y le indicamos que queremos registrar un evento (llamando a la función addEventListener), que el evento que nos interesa es select, que la función que va a responder al evento se llama austriasAnnotationSelected y que a esa función le vamos a pasar como objeto this el venue que estamos procesando.

Cuando el usuario pulsa en el mapkit.ImageAnnotation se dispara el evento y se invoca la función austriasAnnotationSelected.

Si nos fijamos la función tiene un parámetro declarado, pero ese parámetro es de tipo Event, que no es al que hace referencia el objeto this que usamos en, por ejemplo, el paso 1 donde creamos una mapkit.Coordinate que se corresponde con el venue que el usuario ha seleccionado y que sí es el objeto al que hace referencia this

Así que cuando pulsemos sobre una de las Annotations veremos algo como esto.

Eliminar annotations

No hemos parado de añadir annotations a nuestro mapa, y si no lo remediamos al final cubriremos toda la superficie terrestre de pines.

Es buena idea que al inicio de cada operación limpiemos el mapa de Annotations anteriores.

Con estas dos líneas lo podemos hacer. El objecto map que representa nuestra mapa tiene una propiedad annotations que tiene todas las annotations que hay en el mapa. Basta con pasar ese array a la función removeAnnotations para que desaparezcan del mapa.

Pruebas en local

Puedes usar el sitio web que acompaña al artículo y que puedes visitar en esta dirección o si lo prefieres puedes hacerlo en tu equipo local.

Sólo tiene que descargar el código desde este repositorio de GitHub y una vez descomprimido abrir la app Terminal, situarte en el directorio raíz de la web y ejecutar el siguiente comando:

php -S 0.0.0.0:9090

Ahora ya puedes acceder desde tu navegador, o desde cualquier ordenador de tu red a la dirección

http://localhost:9090/index.html

Conclusión

En una próxima entrega veremos como establecer rutas y sacarle mucho más partido. Esto es solo el comienzo. Pero lo importante es que hemos aprendido otra manera de presentar los mapas de Apple, esta vez en la web, con la ventaja de que nuestros usuarios verán los mismos mapas sin importar si lo hacen desde un Mac, un iPhone, un iPad o una navegador web en otro sistema.

Y recordad, no todo es Swift u Objective-C.

Publicado en MapKit JS

Los comentarios están cerrados.