Skip to content
26 changes: 22 additions & 4 deletions lib/src/gestures/map_interactive_viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>
late double _lastRotation;
late double _lastScale;
late Offset _lastFocalLocal;
late Offset _prevFocalLocal;
late LatLng _mapCenterStart;
late double _mapZoomStart;
late Offset _focalStartLocal;
Expand Down Expand Up @@ -543,7 +544,8 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>

_mapZoomStart = _camera.zoom;
_mapCenterStart = _camera.center;
_focalStartLocal = _lastFocalLocal = details.localFocalPoint;
_focalStartLocal =
_lastFocalLocal = _prevFocalLocal = details.localFocalPoint;
_focalStartLatLng = _camera.offsetToCrs(_focalStartLocal);

_dragStarted = false;
Expand Down Expand Up @@ -571,6 +573,7 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>

_lastRotation = currentRotation;
_lastScale = details.scale;
_prevFocalLocal = _lastFocalLocal;
_lastFocalLocal = details.localFocalPoint;
}

Expand Down Expand Up @@ -793,13 +796,28 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>
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<Offset>(
begin: flingOffset,
end: flingOffset - direction * distance,
end: flingOffset + direction * distance,
).animate(_flingController);

_flingController
Expand Down