Ultimamente me he estado pegando más de la cuenta con Leaflet, así que comparto aquí el problema encontrado, y la solución, por si le puede servir de ayuda a alguien.
Origen del problema: tenemos un objeto javascript L.Map de Leaflet, al que hemos añadido una serie de elementos vectoriales (objetos de tipo L.Layer).
Si queremos cambiar la capa, y mostrar otra distinta, reutilizando el objeto mapa existente, tenemos que seguir estos dos pasos:
a) Eliminar los objetos "Layer" previamente cargados. En este caso lo más comodo es haberlos agrupado previamente en un contenedor denominado "LayerGroup".
if(currentLayer){
if(currentLayer instanceof L.LayerGroup)
currentLayer.clearLayers();
map.removeLayer(currentLayer);
}
}
b) Añadir la nueva capa (objetos Layer) agrupada en un contenedor.
var lyrs = [];//array donde guardar las geometrias
var layerGroup = L.featureGroup(lyrs);
c) Cambiar el nivel de zoom del mapa, para que se nos muestra la nueva "capa" que vamos a añadir.
map.fitBounds(layerGroup.getBounds());
Y ¡ojo! Aquí empiezan a aparecer los problemas. Es muy posible que el nivel de zoom que se nos muestre sea siempre el máximo, y que el mapa (la capa de tiles con ortofoto, open street map, o lo que sea que hayamos querido cargar como capa de base) no aparezca centrado. ¿Cual es el motivo?
Si cambiamos nuestro código de cambio del nivel de zoom, por el siguiente:
var bounds = _layerGroup.getBounds();
var center = bounds.getCenter();
var zoomLevel = map.getBoundsZoom(bounds);
map.setView(center, zoomLevel, true);
Veremos que zoomLevel toma el valor 0.
ACTUALIZACIÓN: En este
bug reportado en la web del proyecto Leaflet se describe perfectamente el problema. No solo zoomLevel toma el valor 0, getSize() devuelve un objeto con valores w=0 y h=0.
En este punto es cuando entra en juego el método invalidateSize() del objeto map. Si lo hacemos así:
var layerGroup = L.featureGroup(lyrs);
map.invalidateSize();
map.fitBounds(layerGroup.getBounds());
Nuestro mapa se dibujará sin problemas, mostrando la capa que acabamos de añadir.
Moraleja: map.invalidateSize() recalcula los parámetros del objeto map,parámetros que pueden cambiar con un cambio del área de visualización del dispositivo (horizontal a vertical en móvil, cambio del tamaño del navegador en desktop, etc) o con el "bounds" de las geometrías cargadas. Así que es conveniente siempre llamar a map.invalidateSize() antes de cambiar el nivel de zoom, si pensamos que se ha producido un cambio en la inforamación de estado del mapa.