I have a Leaflet map which is used for location-sharing. When a user shares their location, a marker displaying their location is added to the map for all other users to see. It auto-fits the map to display all the markers whenever one is added, moved or deleted. I've also added a custom control that can toggle the auto-fit behavior on and off. This all works fine, but I would also like to make the map smart enough to automatically turn off the auto-fit behavior if the user pans or zooms the map.
This turns out to be pretty difficult because I can't find a good way to distinguish whether or not a pan/zoom operation is initiated by the user or by an auto-fit. I was initially listening for the panstart and zoomstart events, but these are also triggered by the auto-fit. I figured that I could set a flag to tell it not to turn off auto-fit when the zoom/pan is caused by auto-fitting. I check this flag first before turning off auto-fit in response to panstart and zoomstart, then clear it when panend and zoomend are received.
This appears to work fine until an auto-fit occurs which does not result in a pan or zoom. Let's suppose that we have a large auto-fitted cluster of markers, and one of the ones in the middle is removed. Since the bound box is unchanged, no pan or zoom is triggered, and therefore the flag telling it not to turn off auto-fit never gets cleared. The next time the user pans or zooms the map, it doesn't turn off auto-fit like it should because it thinks it's still in the middle of an auto-fit operation.
How do I make it so that I can reliably turn off auto-fitting when the user pans or zooms the map directly, but leave it on when it is panned or zoomed by other means?
Here is the relevant code:
var markers = []; // Map markers are stored in this array.
var autoFit = true; // Whether auto-fit is turned on
var lockAutoFit = false; // Temporarily lock auto-fit if true
var map; // Leaflet map object
function initMap() {
// Leaflet map initialized here
map.on('movestart zoomstart', function() {
if (!lockAutoFit) {
autoFit = false;
}
});
map.on('moveend zoomend', function() {
lockAutoFit = false;
});
}
function toggleAutoFit() {
autoFit = !autoFit;
if (autoFit) {
lockAutoFit = true;
fitMap();
}
}
function addOrUpdateMarker(marker, coords) {
lockAutoFit = true;
// do the marker update here
fitMap();
}
function removeMarker(marker) {
lockAutoFit = true;
// remove the marker here
fitMap();
}
// Pans and zooms the map so that all markers fit in the map view.
// Invoked whenever a marker is added, moved or deleted, or when
// the user turns on auto-fit.
function fitMap() {
if (!autoFit || !markers.length) {
return;
}
map.fitBounds(new L.featureGroup(markers).getBounds());
}
I ended up setting a flag around my fitBounds
and setView
calls e.g.:
isProgramaticZoom = true
map.fitBounds(new L.featureGroup(markers).getBounds());
isProgramaticZoom = false
Then the code to turn off auto-fit:
map.on('zoomstart', function() {
if (!isProgramaticZoom) {
//turn off auto-fit
}
})
map.on('dragstart', function() {
//turn off auto-fit
})
Unfortunately, still not ideal but should do the trick
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With