flutter_map icon indicating copy to clipboard operation
flutter_map copied to clipboard

Map warps to other side of the planet when map center hits antimeridian

Open corepuncher opened this issue 10 months ago • 9 comments

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

corepuncher avatar Jan 30 '25 02:01 corepuncher

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

josxha avatar Jan 30 '25 07:01 josxha

This will occur when camera constraints are set. The end of the fling jumps past the constraints.

JaffaKetchup avatar Jan 30 '25 07:01 JaffaKetchup

The workaround is probably to inset the constraints a bit from the edge? But we need to look into this.

JaffaKetchup avatar Jan 30 '25 09:01 JaffaKetchup

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.

corepuncher avatar Jan 31 '25 01:01 corepuncher

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?

monsieurtanuki avatar Feb 10 '25 10:02 monsieurtanuki

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?

JaffaKetchup avatar Feb 16 '25 16:02 JaffaKetchup

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).

corepuncher avatar Feb 20 '25 02:02 corepuncher

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).

JaffaKetchup avatar Mar 28 '25 10:03 JaffaKetchup

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.

monsieurtanuki avatar Mar 28 '25 12:03 monsieurtanuki