flutter_map
flutter_map copied to clipboard
Map warps to other side of the planet when map center hits antimeridian
What is the bug?
When I pan my map west to -180, instead of stopping like a wall, it flips around to the other side of the globe.
Is there a way to put the "wall" behavior back? I enjoyed that natural blocking behavior actually.
How can we reproduce it?
Unless it's something in my code specifically, just pan/fling westward beyond -180 and see what happens.
If you cannot reproduce, I'll give more info on my setup for troubleshooting.
Do you have a potential solution?
No response
Platforms
All
Severity
Minimum: Allows normal functioning
I'm not able to reproduce this with a normal pan gesture but with a fling gesture.
https://github.com/user-attachments/assets/03426840-d2aa-415d-981e-bc833e4550a7
This will occur when camera constraints are set. The end of the fling jumps past the constraints.
The workaround is probably to inset the constraints a bit from the edge? But we need to look into this.
This will occur when camera constraints are set. The end of the fling jumps past the constraints.
I have no camera constraints set myself.
I see what is happening though.
Since the behavior around the international dateline has changed, my old logic no longer works.
Before: Panning map to -180 would simply stop there. I never had to deal with it. Now: Panning across -180 flips the longitude to a positive value.
Old Logic: If map centerpoint goes EAST of -40 (or WEST of -180), I move the map to longitude -40 (or -180).
if (newLat > globals.maxNorthBound) newLat = globals.maxNorthBound;
if (newLat < globals.maxSouthBound) newLat = globals.maxSouthBound;
if (newLon < globals.maxWestBound) newLon = globals.maxWestBound;
if (newLon > globals.maxEastBound) newLon = globals.maxEastBound;
if (newLat != position.center.latitude || newLon != position.center.longitude) {
mapState.move(LatLng(newLat, newLon), position.zoom);
}
But now, the map is allowed to move west of -180, to 180. My old logic sees 180 as > -40, so my logic below warps the map all the way to the other side of my domain to the east side (-40).
Any way to have a flag that puts the "barrier" at -180 back? If not, I'll have to think about how to mitigate. Perhaps if the fling stops anywhere between -180 and "a ways west" of there, snap back to -180, otherwise if they are over the Atlantic Ocean, snap back to -40, or something like that.
Using camera constraints would probably be optimal but I could never get it too "not" thrown an exceptions when changing device orientation, which many times causes it to go out of bounds.
I've managed to reproduce the issue, only with camera constraints and fling gestures.
There are several points to address:
- a "standard" constraint wouldn't be enough, as we'll always end up with longitudes between -180 and 180
- the fling gesture would need to be stopped
We can disable the fling gesture "going too far" with this additional test in void _handleFlingAnimation(), before sending the "move the map" instruction to the controller:
if ((_mapCenterStart.longitude < 0 && newCenter.longitude > 0) ||
(_mapCenterStart.longitude > 0 && newCenter.longitude < 0)) {
return;
}
How should we set the "not beyond -180, not beyond +180" barrier parameter?
I've also managed to reproduce a similar issue which occurs on flinging without a camera constraint. It bumps up against the edge rather than continuing the fling, then requires another gesture to break past it. I'm not sure if that changes things?
I've also managed to reproduce a similar issue which occurs on flinging without a camera constraint. It bumps up against the edge rather than continuing the fling, then requires another gesture to break past it. I'm not sure if that changes things?
That is interesting, as my map flings past 180 (also without camera constraint).
Looking to fix this bug where flinging up against a camera constraint set to cover (90, -180) to (-90, 180) will teleport to the other side of the world.
@monsieurtanuki's code above needs a little adjustment.
&& (newCenter.longitude - _mapCenterStart.longitude).abs() > 180
Otherwise, we cannot fling across the meridian either.
One difficulty is that it actually makes potentially more sense to apply this in moveRaw, or otherwise we need to change the way camera constraints are applied. This is because, otherwise, the camera will still suddenly jump at some point, when the MapCamera.constrain function finds an appropriate bbox at the end of the fling using new coordinates, causing a jump. If we apply that code just after the constraining instead, it avoids the problem. We could potentially also avoid it just by stopping the fling early if we meet these conditions, but then smooth sliding up and down the anti-meridian stops, and it still sometimes seems to jump.
Additionally, I'm not sure how to properly integrate it with the camera constraints. I think a sensible idea is that if the camera is constrained as I said above, then moving across the anti-meridian is forbidden. I can stop the movement, I'm just not sure the best way to do that dependent on the constraints.
This also reveals a bigger issue with LatLngBounds. We cannot define a constraint across the anti-meridian. This is in the same way we cannot define a line or polygon across the anti-meridian (see #2061).
Generally speaking, a list of LatLng should include a policy about what to do with -180/180 crossing and half a world distance apart. That would make sense also for a couple of LatLng, e.g. regarding comparison.