diff --git a/lib/src/gestures/map_interactive_viewer.dart b/lib/src/gestures/map_interactive_viewer.dart index 67bff82fa..665e943c4 100644 --- a/lib/src/gestures/map_interactive_viewer.dart +++ b/lib/src/gestures/map_interactive_viewer.dart @@ -78,6 +78,7 @@ class MapInteractiveViewerState extends State late double _lastRotation; late double _lastScale; late Offset _lastFocalLocal; + late Offset _prevFocalLocal; late LatLng _mapCenterStart; late double _mapZoomStart; late Offset _focalStartLocal; @@ -543,7 +544,8 @@ class MapInteractiveViewerState extends State _mapZoomStart = _camera.zoom; _mapCenterStart = _camera.center; - _focalStartLocal = _lastFocalLocal = details.localFocalPoint; + _focalStartLocal = + _lastFocalLocal = _prevFocalLocal = details.localFocalPoint; _focalStartLatLng = _camera.offsetToCrs(_focalStartLocal); _dragStarted = false; @@ -571,6 +573,7 @@ class MapInteractiveViewerState extends State _lastRotation = currentRotation; _lastScale = details.scale; + _prevFocalLocal = _lastFocalLocal; _lastFocalLocal = details.localFocalPoint; } @@ -793,13 +796,28 @@ class MapInteractiveViewerState extends State return; } - final direction = details.velocity.pixelsPerSecond / magnitude; + // Use the tracked offset to determine direction instead of the velocity + // direction, which can be incorrect on web when the pointer leaves the + // window. Use the final segment direction to correctly handle curved + // gestures where the user changes direction during the drag. + final flingOffset = _focalStartLocal - _lastFocalLocal; + final finalSegment = _prevFocalLocal - _lastFocalLocal; + final finalSegmentDistance = finalSegment.distance; + + // Use final segment direction if available, otherwise fall back to overall + // direction for edge cases where the final segment has no movement. + final Offset direction; + if (finalSegmentDistance > 0) { + direction = finalSegment / finalSegmentDistance; + } else { + final flingDistance = flingOffset.distance; + direction = flingOffset / flingDistance; + } final distance = (Offset.zero & _camera.nonRotatedSize).shortestSide; - final flingOffset = _focalStartLocal - _lastFocalLocal; _flingAnimation = Tween( begin: flingOffset, - end: flingOffset - direction * distance, + end: flingOffset + direction * distance, ).animate(_flingController); _flingController