Map shaking after setMaxBounds and setMinZoom
See original GitHub issueChecklist
- I’ve looked at the documentation to make sure the behavior isn’t documented and expected.
- I’m sure this is an issue with Leaflet, not with my app or other dependencies (Angular, Cordova, React, etc.).
- I’ve searched through the current issues to make sure this hasn’t been reported yet.
- I agree to follow the Code of Conduct that this project adheres to.
Steps to reproduce
- Create a map.
- Set its maximum borders and minimum zoom to those currently visible on the screen.
const map = L.map('map').setView([50.450036, 30.5241361], 13)
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution:
'© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map)
map.setMaxBounds(map.getBounds()).setMinZoom(map.getZoom())
Expected behavior
The map is limited by the maximum borders and the minimum zoom without any unexpected behavior.
Current behavior
Map is limited by the maximum borders and the minimum zoom, but the map is moving (shaking). I have looked at these issues: #1946, #2107, #2011, #2081, #1866, #2187. But it seems that there is no solution to my problem there, so I don’t think it’s a duplicate to any of previous issues. If it is, could you please help me to resolve this issue? Thank you!
Minimal example reproducing the issue
https://jsfiddle.net/fd3mertj/1/
Environment
- Leaflet version: 1.8.0, 1.9.1
- Browser (with version): Mozilla 105.0.1 (64 bit), Opera 90.0.4480.84
- OS/Platform (with version): Windows 10 laptop
Issue Analytics
- State:
- Created a year ago
- Comments:13 (6 by maintainers)
Top GitHub Comments
This seems to be an intermittent problem, but I can repeat it. It takes a bit of adjusting the screen to figure out a screen size that does reproduce the issue – and even then it can seemingly fix itself without intervention.
We have
Map._panInsideMaxBounds
set up as amoveend
event listener, and at certain screen / view sizes it seems to infinitely re-trigger itself.We are supposed to break out of this recursion in Map.panInsideBounds by checking if a recalculated center is identical to the current center:
https://github.com/Leaflet/Leaflet/blob/4372a9fcadce23d23a21370439179c09d1118ab3/src/map/Map.js#L503-L514
But our centers do not match up. Here are the
center
andnewCenter
values I’ve logged across many ticks of this recursive loop:Taking a look at
Map._limitCenter
, here are logged values forcenterPoint
,viewHalf
,viewBounds.min
,viewBounds.max
,offset
:I believe this might be related to floating point precision between the map bounds and its projected center. Each new projected center throws the bounds off slightly, leading to a different projected center.
I think we already have code that’s attempting to fix this in
Map._limitCenter
for sub-pixel offsets:https://github.com/Leaflet/Leaflet/blob/4372a9fcadce23d23a21370439179c09d1118ab3/src/map/Map.js#L1545-L1550
I’d propose expanding that to ignore up to 1px offsets, as we seem to be seeing here.
I’ll put a PR together with that proposal, if nobody objects?
@rjackson great analysis! Please submit a PR of course.