Skip to content

Commit bc82bc4

Browse files
fix: 2022 - no fling beyond the antimeridian if constrained
New file: * `antimeridian.dart`: Testing if we can fling beyond the world. We can't, due to the constraint. Impacted files: * `camera_constraint.dart` * `main.dart`: added new `AntimeridianPage` page. * `map_interactive_viewer.dart` * `menu_drawer.dart`
1 parent 89a82f4 commit bc82bc4

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

example/lib/main.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_map_example/pages/abort_obsolete_requests.dart';
33
import 'package:flutter_map_example/pages/animated_map_controller.dart';
4+
import 'package:flutter_map_example/pages/antimeridian.dart';
45
import 'package:flutter_map_example/pages/bundled_offline_map.dart';
56
import 'package:flutter_map_example/pages/circle.dart';
67
import 'package:flutter_map_example/pages/debouncing_tile_update_transformer.dart';
@@ -55,6 +56,7 @@ class MyApp extends StatelessWidget {
5556
AbortObsoleteRequestsPage.route: (context) =>
5657
const AbortObsoleteRequestsPage(),
5758
PolylinePage.route: (context) => const PolylinePage(),
59+
AntimeridianPage.route: (context) => const AntimeridianPage(),
5860
SingleWorldPolysPage.route: (context) => const SingleWorldPolysPage(),
5961
PolylinePerfStressPage.route: (context) =>
6062
const PolylinePerfStressPage(),
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_map/flutter_map.dart';
3+
import 'package:flutter_map_example/misc/tile_providers.dart';
4+
import 'package:flutter_map_example/widgets/drawer/menu_drawer.dart';
5+
import 'package:latlong2/latlong.dart';
6+
7+
/// Testing if we can fling beyond the world. We can't, due to the constraint.
8+
class AntimeridianPage extends StatelessWidget {
9+
static const String route = '/antimeridian';
10+
11+
const AntimeridianPage({super.key});
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return Scaffold(
16+
appBar: AppBar(title: const Text('Antimeridian')),
17+
drawer: const MenuDrawer(AntimeridianPage.route),
18+
body: FlutterMap(
19+
options: MapOptions(
20+
initialZoom: 2,
21+
cameraConstraint: CameraConstraint.contain(
22+
bounds: LatLngBounds(
23+
const LatLng(90, -180),
24+
const LatLng(-90, 180),
25+
),
26+
),
27+
),
28+
children: [
29+
openStreetMapTileLayer,
30+
],
31+
),
32+
);
33+
}
34+
}

example/lib/widgets/drawer/menu_drawer.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:flutter/gestures.dart';
55
import 'package:flutter/material.dart';
66
import 'package:flutter_map_example/pages/abort_obsolete_requests.dart';
77
import 'package:flutter_map_example/pages/animated_map_controller.dart';
8+
import 'package:flutter_map_example/pages/antimeridian.dart';
89
import 'package:flutter_map_example/pages/bundled_offline_map.dart';
910
import 'package:flutter_map_example/pages/circle.dart';
1011
import 'package:flutter_map_example/pages/debouncing_tile_update_transformer.dart';
@@ -147,6 +148,11 @@ class MenuDrawer extends StatelessWidget {
147148
routeName: PolylinePage.route,
148149
currentRoute: currentRoute,
149150
),
151+
MenuItemWidget(
152+
caption: 'Antimeridian test',
153+
routeName: AntimeridianPage.route,
154+
currentRoute: currentRoute,
155+
),
150156
MenuItemWidget(
151157
caption: 'Circle Layer',
152158
routeName: CirclePage.route,

lib/src/gestures/map_interactive_viewer.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>
114114

115115
late var _keyboardPanAnimationPrevZoom = _camera.zoom; // to detect changes
116116
late double _keyboardPanAnimationMaxVelocity;
117+
117118
double _keyboardPanAnimationMaxVelocityCalculator(double zoom) =>
118119
_interactionOptions.keyboardOptions.maxPanVelocity?.call(zoom) ??
119120
5 * math.log(0.15 * zoom + 1) + 1;
@@ -124,7 +125,9 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>
124125

125126
// Shortcuts
126127
MapCamera get _camera => widget.controller.camera;
128+
127129
MapOptions get _options => widget.controller.options;
130+
128131
InteractionOptions get _interactionOptions => _options.interactionOptions;
129132

130133
@override
@@ -965,12 +968,15 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>
965968
newCenter = _camera.unprojectAtZoom(bestCenterPoint);
966969
}
967970

968-
widget.controller.moveRaw(
971+
final moved = widget.controller.moveRaw(
969972
newCenter,
970973
_camera.zoom,
971974
hasGesture: true,
972975
source: MapEventSource.flingAnimationController,
973976
);
977+
if (!moved) {
978+
_closeFlingAnimationController(MapEventSource.flingAnimationController);
979+
}
974980
}
975981

976982
void _resetDoubleTapHold() {

lib/src/map/camera/camera_constraint.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,18 @@ class ContainCamera extends CameraConstraint {
142142
centerPix.dy.clamp(topOkCenter, botOkCenter),
143143
);
144144

145-
if (newCenterPix == centerPix) return camera;
145+
if (newCenterPix == centerPix) {
146+
return camera;
147+
}
148+
149+
// Special case when the world is the limit: we want to stop at
150+
// antimeridian lines.
151+
// The standard test cannot work, as we'll always be in [-180,180].
152+
// If the center changed, that means that the clamp did have an action.
153+
// Therefore we went beyond the world.
154+
if (bounds.west == -180 && bounds.east == 180) {
155+
return null;
156+
}
146157

147158
return camera.withPosition(
148159
center: camera.unprojectAtZoom(newCenterPix, testZoom),

0 commit comments

Comments
 (0)