I have a leaflet map on an HTML page. When the page is scrolled so that any part of the map is outside of the viewport and I click the zoom buttons, the map jumps so that it's completely visible in the viewport. If the whole map doesn't fit, then the top of the map becomes aligned with the top of the viewport and the bottom just hangs off the end.
This is annoying, because then the zoom button which the user just pressed is no longer under the cursor and they have to go find it again.
I have tried both the built-in zoom bar and a custom one where I use map.setZoom()
and the behaviour is consistent. However, the sample maps on https://leafletjs.com don't do this, so I'm at a loss.
My map is quite simple:
var home = {center: L.LatLng(51.499725, -0.124695), zoom: 11};
var mymap = L.map('map').setView(home.center, home.zoom);
This question sounds similar to what I'm seeing, but is more complex than my situation. And anyway, there's no solution.
Edit: Here is the html and CSS, but it couldn't be more basic.
map.html
<div class="container mx-sm-3">
<div class="row">
<div class="col">
<div id="map"></div>
</div>
</div>
</div>
map.css
#map {
height: 570px;
width: 700px;
}
The culprit is this line of code:
this._map.getContainer().focus();
The rationale behind that? The map container must have the focus so that keyboard events are routed through it. Clicking on a zoom button would set the focus on the button itself, and make the map misbehave under some circumstances.
But a side effect of focus is that focusing a HTML element will make the user agent (web browser) to scroll it into view, since it is assumed that the user will want to see the focused element before doing any keyboard input into it.
Armed with this knowledge, I'll rephrase your question in two different ways:
I do not need the map element to be focused at all. How do I prevent Leaflet from focusing the map after clicking on the zoom buttons?
By making the _refocusOnMap()
private method of L.Control
do nothing.
This can be done the quick&dirty way by monkey-patching it:
L.Control.prototype._refocusOnMap = function _refocusOnMap() {};
Remember to monkey-patch before instantiating the map. The "clean" would be to create subclasses of L.Control
and/or L.Control.Zoom
, based on this. If you have your own zoom controls, you can also provide a custom _refocusOnMap
method instead of relying on the one provided by the parent class.
I would like the keyboard controls to keep working, but I do not want to scroll the whole map into view after pressing the zoom buttons. Can the map be focused but skipping the "scroll into view" business?
Yes, with caveats.
The focus
method of HTMLElements
accepts an options
parameter which can hold a preventScroll
option.
So you could monkey-patch _refocusOnMap()
in the following way:
L.Control.prototype._refocusOnMap = function _refocusOnMap(ev) {
// if map exists and event is not a keyboard event
if (this._map && ev && ev.screenX > 0 && ev.screenY > 0) {
this._map.getContainer().focus({ preventScroll: true });
}
};
Be aware, however, that support for preventScroll
is not present in all browsers.
Another approach would be to preventDefault
either the focus
or focusin
events on the map, with something like:
L.DomEvent.on(map.getContainer(), 'focus', L.DomEvent.preventDefault)
However, due to inconsistencies between web browsers, this might not only stop the scroll but the focusing, or might have no effect at all, depending on which web browser is being used.
this._map.getContainer().focus = ()=>{}
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