Category: DEV
En este tutorial veremos la configuración a realizar para crear un mapa interactivo con los módulos contribuidos Leaflet y GeoField de Drupal. Esto nos servirá para implementar un posicionamiento, dentro de nuestras entidades o algún recurso de nuestra web, sobre un mapa.
Esto nos puede ser útil en distintos casos de uso, siendo uno de los más comunes el caso de una empresa que tiene múltiples sedes, locales u oficinas y estas se desean mostrar sobre un mapa.
Por lo que voy a simular este caso, a modo de ejemplo, para crear un contenido el cual le implementaremos un nuevo campo localización, para poder mostrar este contenido a posteriori sobre un mapa.
Vamos a usar una instalación de Drupal 9 limpia con el perfil estándar instalado. Así como lando como nuestro entorno de despliegue en local.
Para empezar, descargaremos los módulos que necesitamos para la configuración de los campos a crear. Dentro de la comunidad de Drupal, existen varios módulos que nos permiten trabajar con la geolocalización. En nuestro caso vamos a usar los módulos Leaflet y Geofield.
$ composer require 'drupal/geofield:^1.36' 'drupal/leaflet:^2.1'
$ drush en leaflet leaflet_views leaflet_markercluster geofield
El módulo Leaflet, ya nos ofrece una integración con la librería de código abierto en js del mismo nombre leaflet. La cual nos ofrece la facilidad de incrustar mapas interactivos tanto en web como en dispositivos móviles. El módulo ya nos trae por defecto la carga de mapas a través de Open Street Map, proyecto colaborativo para crear mapas editables y libres.
Junto con Leaflet vienen dos módulos más, Leaflet Views para la integración de Leaflet con Views y Leaflet Markercluster, con la carga de la librería del mismo nombre, para la generación de marcadores de mapa personalizados y animados. Los cuales también hemos activado.
Por otra parte, con Geofield podremos añadir campos de tipo geolocalización a nuestro contenido.
Vamos ahora a crear un nuevo tipo de contenido llamado ‘Sede’, el cual, aparte del campo title y body por defecto, le vamos a añadir los campos ‘Imagen’ y ‘Localización’.
Nuestro campo Imagen va a ser una referencia a una entidad de tipo Media (del core de Drupal). Aquí cargaremos una imagen a mostrar de nuestra sede.
El campo ‘localización’ será una referencia a un campo de tipo Geofield generado por el módulo Geofield que hemos instalado anteriormente. Dejando la configuración que nos aparece por defecto.
Nuestra entidad Sede quedaría de la siguiente manera:
Para terminar vamos a cambiar el modo de visualización, para que las coordenadas introducidas en nuestro campo localización se muestren en un marcador sobre un mapa. Por lo que dentro de ‘Gestionar presentación’ en el campo de ‘localización’ cambiamos la opción por defecto ‘Raw output’ por ‘Leaflet map’. Dentro de las opciones de este formato podemos cambiar desde la fuente del mapa, el tamaño, el zoom,… E incluso estas opciones pueden aumentar con la instalación de distintos módulos. Para nuestras pruebas dejaremos la configuración por defecto.
También hemos añadido un nuevo tipo de visualización el cual hemos llamado ‘card position’. En el que solo mostramos la imagen y el body, esta visualización la utilizaremos después en la vista, para mostrarla en el popup que aparece al clicar un marcador.
Listo! Pues ya podemos empezar a crear tantas sedes como queramos, teniendo en cuenta que en nuestro campo localización aparecerán dos campos a rellenar, longitud y latitud de las coordenadas que queremos.
Una vez creado nuestro contenido sede, nos disponemos a crear nuestro mapa interactivo. Por lo que nos dirigimos a ‘Estructura’->’Vistas’ y creamos una nueva vista de tipo página en el que muestre los contenidos de tipo ‘Sede’.
Una vez creada esta página vamos a cambiar el formato para que sea de tipo ‘Leaflet Map’ en vez de ‘Lista sin formato’. Puede que esto nos de un error, ya que en el formato ‘Leaflet Map’ solo lo podemos ‘Mostrar’ como tipo de campos. Por lo que cambiaremos en ‘Formato’->’Mostrar’->’Campos’. Y dentro de los campos añadiremos uno nuevo. Este será nuestro campo ‘Localización’ de nuestro tipo de contenido sede.
Una vez añadido nuestro campo ‘Localización’ podemos volver a la configuración del formato ‘Leaflet Map’. Ahora sí podemos especificar que la fuente de nuestros datos sea nuestro campo ‘Localización’ en ‘Data Source’.
Dentro de la configuración podemos personalizar diversas opciones. Por ejemplo, hemos indicado que se agrupen los marcadores por localización, si estos están muy cerca uno del otro. También hemos indicado en ‘Description field’, que nuestro popup al clicar el marcador, será un ‘node entity via ajax’ con el ‘view mode’ ‘Card Position’ creado anteriormente. Otras configuraciones que podemos indicar son la altura del mapa, el tipo, control por gestos, tamaño del indicador o popup, …
Ahora si nos dirigimos a /listado-de-sedes
veremos que queda de la siguiente manera
Y cuando cliqueamos sobre un marcador veremos que le popup se muestra.
En la descripción del módulo de Leaflet, aparece un enlace a una Demo live. Esta demo live muestra algunas de las funcionalidades que podemos hacer con este módulo. Vamos a intentar replicar la funcionalidad en la cual vamos a tener un listado de sedes, y cuando pasemos el ratón sobre cualquier sede, esta pondrá el foco sobre la sede ubicada en el mapa.
Primero vamos a crear una nueva vista. Para ello nos dirigimos a nuestra vista de mapa ya creada. Y añadimos un nuevo display a nuestra vista de tipo ‘Adjunto’.
Esta vista va ser una ‘Lista sin formato’ y solo vamos a mostrar los nombres de las sedes (títulos). Vamos a incluir el ‘ID’ y reordenamos los campos para que ‘ID’ esté encima de ‘Título’. Ahora configuramos ‘Título’ para que se sobrescriban los resultados con un texto custom.
Aquí estamos preparando la estructura para el js, el cual necesita un ‘id’ para saber sobré que elemento del mapa estamos pasando
En la configuración del adjunto, vamos a adjuntarlo a nuestra vista ‘Map’ y la posición del mismo la configuramos en ‘Before’
Y ahora guardamos la vista y nos quedaría así:
Si volvemos a la página de Demos Live de Leaflet vemos que dice:
Inspect the following file to analize the js code interacting with the map markers
leaflet_map_interaction.js
Por lo que vamos a crear un módulo para que nuestra vista cargue este js modificado.
Creamos nuestro módulo custom module
incluyendo las dependencias al módulo leaflet en nuestro custom.info.yml
name: Custom Module
type: module
description: 'Provides functionality for Leaflet view'
package: Custom
core_version_requirement: ^9.2 || ^10
dependencies:
- drupal:leaflet
Creamos una carpeta js, en la cual vamos a añadir nuestro archivo lealet_map_interaction.js
con el siguiente código:
(function ($, Drupal) {
'use strict';
// This drives the interaction with the Geofield Leaflet Map.
Drupal.behaviors.geofieldMapLeafletMapInteraction = {
attach: function (context, settings) {
// React on geofieldMapInit event.
$(document).on('leaflet.map', function (e, settings, lMap, mapid) {
var map = lMap;
var markers = Drupal.Leaflet[mapid].markers;
$('.view-display-id-page_1 .views-field .field-content .marker-selector', context).each(function () {
$(this).hover(
function() {
$( this ).css("text-decoration", "underline");
var marker_id = $(this).data('marker-id');
setTimeout(function () {
if(markers[marker_id]) {
map.setView(markers[marker_id].getLatLng(), '15');
markers[marker_id].fire('click');
}
}, 500);
}, function() {
$( this ).css("text-decoration", "none");
setTimeout(function () {
map.closePopup();
}, 200);
}
);
});
$('.view-display-id-page_1', context).each(function () {
var timeoutId;
$(this).hover(
function() {
}, function() {
$( this ).css("text-decoration", "none");
timeoutId = setTimeout(function () {
map.closePopup();
//$('#' + 'leaflet-map--' + mapid + '--reset-control').click();
Drupal.Leaflet.prototype.map_reset(mapid);
}, 2000);
}
);
});
});
}
};
})(jQuery, Drupal);
En este caso hemos identificado el id del display de nuestro mapa, .view-display-id-page_1
y hemos cambiado las clases identificadoras en el js descargado del ‘Demo Live’.
El siguiente paso sería crear la librería, la cual va a mapear el archivo lealet_map_interaction.js
. Por lo que creamos un archivo custom_module.libraries.yml
y añadimos lo siguiente:
leaflet_map_interaction:
js:
js/leaflet_map_interaction.js: {}
dependencies:
- core/jquery
Por último adjuntamos la librería a nuestra vista. Por lo que dentro de nuestro archivo custom_module.module
implementamos el hook views_pre_render()
use Drupal\views\ViewExecutable;
/**
* Implements hook_views_pre_render().
*/
function custom_module_views_pre_render(ViewExecutable $view) {
if (isset($view) && ($view->storage->id() == 'listado_de_sedes')) {
$view->element['#attached']['library'][] = 'custom_module/leaflet_map_interaction';
}
}
Ahora sí ya estamos listos para instalar nuestro módulo
$drush en custom_module
Podemos volver a nuestra vista y si todo ha salido bien, podemos observar que al realizar el hover sobre una sede, este nos marca el punto en el mapa
Alrededor de Leaflet y geolocalización, hay un gran ecosistema de módulos que pueden darnos ese plus que necesitamos y añadir nuevas funcionalidades a lo que ya hemos visto. Por ejemplo con ‘Leaflet Mor Maps’, podemos añadir distitintos estilos de mapas, con ‘Geocoder’ podremos realizar Reversing Geocode y añadir nuevas funcionalidades tanto a nuestro campo o vista,… Por lo que podemos estirar las posibilidades que nos dan los mapas interactivos tanto como queramos.
¡Hasta la próxima!