From 9a920b5047184d3af54654c0cde64794f26410e5 Mon Sep 17 00:00:00 2001 From: Hugo Heneault Date: Tue, 4 Jan 2022 19:25:45 +0100 Subject: [PATCH 1/7] Added MapController.pointToLatLng() to get LatLng of given screen point Ref #496, ref #607, ref #981, ref #1010 --- example/lib/main.dart | 2 + example/lib/pages/point_to_latlng.dart | 70 ++++++++++++++++++++++++++ example/lib/widgets/drawer.dart | 3 ++ lib/flutter_map.dart | 2 + lib/src/map/map.dart | 13 +++++ 5 files changed, 90 insertions(+) create mode 100644 example/lib/pages/point_to_latlng.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 40945013b..961652307 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_map_example/pages/epsg4326_crs.dart'; import 'package:flutter_map_example/pages/map_inside_listview.dart'; import 'package:flutter_map_example/pages/network_tile_provider.dart'; +import 'package:flutter_map_example/pages/point_to_latlng.dart'; import './pages/animated_map_controller.dart'; import './pages/circle.dart'; @@ -82,6 +83,7 @@ class MyApp extends StatelessWidget { ResetTileLayerPage.route: (context) => const ResetTileLayerPage(), EPSG4326Page.route: (context) => const EPSG4326Page(), MaxBoundsPage.route: (context) => const MaxBoundsPage(), + PointToLatLngPage.route: (context) => const PointToLatLngPage(), }, ); } diff --git a/example/lib/pages/point_to_latlng.dart b/example/lib/pages/point_to_latlng.dart new file mode 100644 index 000000000..3e4e6c156 --- /dev/null +++ b/example/lib/pages/point_to_latlng.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:latlong2/latlong.dart'; + +import '../widgets/drawer.dart'; + +class PointToLatLngPage extends StatefulWidget { + static const String route = 'point_to_latlng'; + + @override + PointToLatlngPage createState() { + return PointToLatlngPage(); + } +} + +class PointToLatlngPage extends State { + late final MapController mapController; + final pointX = 100.0; + final pointY = 100.0; + final pointSize = 20.0; + late final mapEventSubscription; + + @override + void initState() { + super.initState(); + mapController = MapController(); + + mapEventSubscription = mapController.mapEventStream.listen(onMapEvent); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('PointToLatlng')), + drawer: buildDrawer(context, PointToLatLngPage.route), + body: Stack( + children: [ + FlutterMap( + mapController: mapController, + options: MapOptions( + center: LatLng(51.5, -0.09), + zoom: 5.0, + maxZoom: 5.0, + minZoom: 3.0, + ), + layers: [ + TileLayerOptions( + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c']), + ], + ), + Positioned( + top: pointY, + left: pointX, + child: Container( + color: Colors.red, width: pointSize, height: pointSize)) + ], + ), + ); + } + + void onMapEvent(MapEvent mapEvent) { + if (mapEvent is MapEventMove) { + final latLng = mapController.pointToLatLng(CustomPoint(pointX, pointY)); + + print('top left of square is hovering $latLng'); + } + } +} diff --git a/example/lib/widgets/drawer.dart b/example/lib/widgets/drawer.dart index 58811e249..be7c38e74 100644 --- a/example/lib/widgets/drawer.dart +++ b/example/lib/widgets/drawer.dart @@ -3,6 +3,7 @@ import 'package:flutter_map_example/pages/epsg4326_crs.dart'; import 'package:flutter_map_example/pages/map_inside_listview.dart'; import 'package:flutter_map_example/pages/marker_rotate.dart'; import 'package:flutter_map_example/pages/network_tile_provider.dart'; +import 'package:flutter_map_example/pages/point_to_latlng.dart'; import '../pages/animated_map_controller.dart'; import '../pages/circle.dart'; @@ -250,6 +251,8 @@ Drawer buildDrawer(BuildContext context, String currentRoute) { ), _buildMenuItem(context, const Text('Map inside listview'), MapInsideListViewPage.route, currentRoute), + _buildMenuItem(context, const Text('Point to LatLng'), + PointToLatLngPage.route, currentRoute), ], ), ); diff --git a/lib/flutter_map.dart b/lib/flutter_map.dart index 9eac6fbfe..4e2b579c8 100644 --- a/lib/flutter_map.dart +++ b/lib/flutter_map.dart @@ -148,6 +148,8 @@ abstract class MapController { set state(MapState state); void dispose(); + LatLng? pointToLatLng(CustomPoint point); + factory MapController() => MapControllerImpl(); } diff --git a/lib/src/map/map.dart b/lib/src/map/map.dart index eab51a8e7..c5659c2a9 100644 --- a/lib/src/map/map.dart +++ b/lib/src/map/map.dart @@ -78,6 +78,19 @@ class MapControllerImpl implements MapController { return _state.rotate(degree, id: id, source: MapEventSource.mapController); } + @override + LatLng? pointToLatLng(CustomPoint localPoint) { + final width = _state.size.x; + final height = _state.size.y; + + var localPointCenterDistance = + CustomPoint((width / 2) - localPoint.x, (height / 2) - localPoint.y); + var mapCenter = _state.options.crs.latLngToPoint(_state.center, _state.zoom); + + var point = mapCenter - localPointCenterDistance; + return _state.options.crs.pointToLatLng(point, _state.zoom); + } + @override Stream get mapEventStream => _mapEventSink.stream; } From 457cb61b638385ae379bc4294121914f9a7ce3d6 Mon Sep 17 00:00:00 2001 From: Hugo Heneault Date: Tue, 4 Jan 2022 19:36:30 +0100 Subject: [PATCH 2/7] Better pointToLatLng example --- example/lib/pages/point_to_latlng.dart | 52 ++++++++++++++++++-------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/example/lib/pages/point_to_latlng.dart b/example/lib/pages/point_to_latlng.dart index 3e4e6c156..c1ad0d420 100644 --- a/example/lib/pages/point_to_latlng.dart +++ b/example/lib/pages/point_to_latlng.dart @@ -20,12 +20,16 @@ class PointToLatlngPage extends State { final pointSize = 20.0; late final mapEventSubscription; + LatLng? latLng; + @override void initState() { super.initState(); mapController = MapController(); mapEventSubscription = mapController.mapEventStream.listen(onMapEvent); + + mapController.onReady.then((_) => _updatePointLatLng()); } @override @@ -35,21 +39,31 @@ class PointToLatlngPage extends State { drawer: buildDrawer(context, PointToLatLngPage.route), body: Stack( children: [ - FlutterMap( - mapController: mapController, - options: MapOptions( - center: LatLng(51.5, -0.09), - zoom: 5.0, - maxZoom: 5.0, - minZoom: 3.0, + Container( + child: FlutterMap( + mapController: mapController, + options: MapOptions( + center: LatLng(51.5, -0.09), + zoom: 5.0, + maxZoom: 5.0, + minZoom: 3.0, + ), + layers: [ + TileLayerOptions( + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c']), + ], ), - layers: [ - TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), - ], ), + Container( + color: Colors.white, + height: 60, + child: Center( + child: Text( + 'top left of square is hovering ${latLng?.latitude},${latLng?.longitude}', + textAlign: TextAlign.center, + ))), Positioned( top: pointY, left: pointX, @@ -62,9 +76,15 @@ class PointToLatlngPage extends State { void onMapEvent(MapEvent mapEvent) { if (mapEvent is MapEventMove) { - final latLng = mapController.pointToLatLng(CustomPoint(pointX, pointY)); - - print('top left of square is hovering $latLng'); + _updatePointLatLng(); } } + + void _updatePointLatLng() { + final latLng = mapController.pointToLatLng(CustomPoint(pointX, pointY)); + + setState(() { + this.latLng = latLng; + }); + } } From 258bf2b440beec8354f8d3c8bc8f3c4d47b47206 Mon Sep 17 00:00:00 2001 From: Hugo Heneault Date: Tue, 4 Jan 2022 20:53:42 +0100 Subject: [PATCH 3/7] dartfmt --- lib/src/map/map.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/map/map.dart b/lib/src/map/map.dart index c5659c2a9..dd30ca6a2 100644 --- a/lib/src/map/map.dart +++ b/lib/src/map/map.dart @@ -84,8 +84,9 @@ class MapControllerImpl implements MapController { final height = _state.size.y; var localPointCenterDistance = - CustomPoint((width / 2) - localPoint.x, (height / 2) - localPoint.y); - var mapCenter = _state.options.crs.latLngToPoint(_state.center, _state.zoom); + CustomPoint((width / 2) - localPoint.x, (height / 2) - localPoint.y); + var mapCenter = + _state.options.crs.latLngToPoint(_state.center, _state.zoom); var point = mapCenter - localPointCenterDistance; return _state.options.crs.pointToLatLng(point, _state.zoom); From d2ddde2397127fa1e674b987c1ca7f244d2c7ea0 Mon Sep 17 00:00:00 2001 From: Hugo Heneault Date: Wed, 12 Jan 2022 11:44:45 +0100 Subject: [PATCH 4/7] Fix zoom breaking pointToLatLng() --- lib/src/map/map.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/src/map/map.dart b/lib/src/map/map.dart index dd30ca6a2..c742338ed 100644 --- a/lib/src/map/map.dart +++ b/lib/src/map/map.dart @@ -80,8 +80,12 @@ class MapControllerImpl implements MapController { @override LatLng? pointToLatLng(CustomPoint localPoint) { - final width = _state.size.x; - final height = _state.size.y; + if (_state.originalSize == null) { + return null; + } + + final width = _state.originalSize!.x; + final height = _state.originalSize!.y; var localPointCenterDistance = CustomPoint((width / 2) - localPoint.x, (height / 2) - localPoint.y); From 1734ed55ec9c142ea4476f7afffd1224eea19439 Mon Sep 17 00:00:00 2001 From: Hugo Heneault Date: Thu, 13 Jan 2022 07:52:11 +0100 Subject: [PATCH 5/7] Updated example to help fix the rotation issue --- example/lib/pages/point_to_latlng.dart | 100 +++++++++++++++++++------ 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/example/lib/pages/point_to_latlng.dart b/example/lib/pages/point_to_latlng.dart index c1ad0d420..72be96b19 100644 --- a/example/lib/pages/point_to_latlng.dart +++ b/example/lib/pages/point_to_latlng.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; @@ -15,10 +17,9 @@ class PointToLatLngPage extends StatefulWidget { class PointToLatlngPage extends State { late final MapController mapController; - final pointX = 100.0; - final pointY = 100.0; - final pointSize = 20.0; - late final mapEventSubscription; + late final StreamSubscription mapEventSubscription; + final pointSize = 40.0; + final pointY = 200.0; LatLng? latLng; @@ -27,15 +28,32 @@ class PointToLatlngPage extends State { super.initState(); mapController = MapController(); - mapEventSubscription = mapController.mapEventStream.listen(onMapEvent); + mapEventSubscription = mapController.mapEventStream + .listen((mapEvent) => onMapEvent(mapEvent, context)); - mapController.onReady.then((_) => _updatePointLatLng()); + Future.delayed(Duration.zero, () { + mapController.onReady.then((_) => _updatePointLatLng(context)); + }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('PointToLatlng')), + floatingActionButton: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FloatingActionButton( + child: Icon(Icons.rotate_right), + onPressed: () => mapController.rotate(60.0), + ), + SizedBox(height: 15), + FloatingActionButton( + child: Icon(Icons.cancel), + onPressed: () => mapController.rotate(0.0), + ), + ], + ), drawer: buildDrawer(context, PointToLatLngPage.route), body: Stack( children: [ @@ -45,14 +63,28 @@ class PointToLatlngPage extends State { options: MapOptions( center: LatLng(51.5, -0.09), zoom: 5.0, - maxZoom: 5.0, minZoom: 3.0, ), - layers: [ - TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + children: [ + TileLayerWidget( + options: TileLayerOptions( + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'])), + if (latLng != null) + MarkerLayerWidget( + options: MarkerLayerOptions( + markers: [ + Marker( + width: pointSize, + height: pointSize, + point: latLng!, + builder: (ctx) => Container( + child: FlutterLogo(), + ), + ) + ], + )) ], ), ), @@ -60,31 +92,51 @@ class PointToLatlngPage extends State { color: Colors.white, height: 60, child: Center( - child: Text( - 'top left of square is hovering ${latLng?.latitude},${latLng?.longitude}', - textAlign: TextAlign.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'flutter logo (${latLng?.latitude.toStringAsPrecision(4)},${latLng?.longitude.toStringAsPrecision(4)})', + textAlign: TextAlign.center, + ), + Text( + 'should be in target center, but try to rotate', + textAlign: TextAlign.center, + ), + ], ))), Positioned( - top: pointY, - left: pointX, - child: Container( - color: Colors.red, width: pointSize, height: pointSize)) + top: pointY - pointSize / 2, + left: _getPointX(context) - pointSize / 2, + child: Icon(Icons.crop_free, size: pointSize)) ], ), ); } - void onMapEvent(MapEvent mapEvent) { - if (mapEvent is MapEventMove) { - _updatePointLatLng(); - } + void onMapEvent(MapEvent mapEvent, BuildContext context) { + // if (mapEvent is MapEventMove) { + _updatePointLatLng(context); + // } } - void _updatePointLatLng() { + void _updatePointLatLng(context) { + final pointX = _getPointX(context); + final latLng = mapController.pointToLatLng(CustomPoint(pointX, pointY)); setState(() { this.latLng = latLng; }); } + + double _getPointX(BuildContext context) { + return MediaQuery.of(context).size.width / 2; + } + + @override + void dispose() { + super.dispose(); + mapEventSubscription.cancel(); + } } From 0dad777336928d4c1fe350d206e0ea0fb2b0169d Mon Sep 17 00:00:00 2001 From: Hugo Heneault Date: Wed, 18 May 2022 07:17:41 +0200 Subject: [PATCH 6/7] Rebased on latest --- example/lib/pages/point_to_latlng.dart | 66 +++++++++++++------------- lib/flutter_map.dart | 1 + lib/src/map/map.dart | 6 +-- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/example/lib/pages/point_to_latlng.dart b/example/lib/pages/point_to_latlng.dart index 72be96b19..ccc97516f 100644 --- a/example/lib/pages/point_to_latlng.dart +++ b/example/lib/pages/point_to_latlng.dart @@ -9,6 +9,8 @@ import '../widgets/drawer.dart'; class PointToLatLngPage extends StatefulWidget { static const String route = 'point_to_latlng'; + const PointToLatLngPage({Key? key}) : super(key: key); + @override PointToLatlngPage createState() { return PointToLatlngPage(); @@ -39,17 +41,17 @@ class PointToLatlngPage extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text('PointToLatlng')), + appBar: AppBar(title: const Text('PointToLatlng')), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ FloatingActionButton( - child: Icon(Icons.rotate_right), + child: const Icon(Icons.rotate_right), onPressed: () => mapController.rotate(60.0), ), - SizedBox(height: 15), + const SizedBox(height: 15), FloatingActionButton( - child: Icon(Icons.cancel), + child: const Icon(Icons.cancel), onPressed: () => mapController.rotate(0.0), ), ], @@ -57,36 +59,32 @@ class PointToLatlngPage extends State { drawer: buildDrawer(context, PointToLatLngPage.route), body: Stack( children: [ - Container( - child: FlutterMap( - mapController: mapController, - options: MapOptions( - center: LatLng(51.5, -0.09), - zoom: 5.0, - minZoom: 3.0, - ), - children: [ - TileLayerWidget( - options: TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c'])), - if (latLng != null) - MarkerLayerWidget( - options: MarkerLayerOptions( - markers: [ - Marker( - width: pointSize, - height: pointSize, - point: latLng!, - builder: (ctx) => Container( - child: FlutterLogo(), - ), - ) - ], - )) - ], + FlutterMap( + mapController: mapController, + options: MapOptions( + center: LatLng(51.5, -0.09), + zoom: 5.0, + minZoom: 3.0, ), + children: [ + TileLayerWidget( + options: TileLayerOptions( + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'])), + if (latLng != null) + MarkerLayerWidget( + options: MarkerLayerOptions( + markers: [ + Marker( + width: pointSize, + height: pointSize, + point: latLng!, + builder: (ctx) => const FlutterLogo(), + ) + ], + )) + ], ), Container( color: Colors.white, @@ -99,7 +97,7 @@ class PointToLatlngPage extends State { 'flutter logo (${latLng?.latitude.toStringAsPrecision(4)},${latLng?.longitude.toStringAsPrecision(4)})', textAlign: TextAlign.center, ), - Text( + const Text( 'should be in target center, but try to rotate', textAlign: TextAlign.center, ), diff --git a/lib/flutter_map.dart b/lib/flutter_map.dart index 4e2b579c8..ace11ee65 100644 --- a/lib/flutter_map.dart +++ b/lib/flutter_map.dart @@ -5,6 +5,7 @@ import 'dart:math'; import 'package:flutter/widgets.dart'; import 'package:flutter_map/src/core/center_zoom.dart'; +import 'package:flutter_map/src/core/point.dart'; import 'package:flutter_map/src/geo/crs/crs.dart'; import 'package:flutter_map/src/geo/latlng_bounds.dart'; import 'package:flutter_map/src/gestures/interactive_flag.dart'; diff --git a/lib/src/map/map.dart b/lib/src/map/map.dart index c742338ed..336d74a25 100644 --- a/lib/src/map/map.dart +++ b/lib/src/map/map.dart @@ -87,12 +87,12 @@ class MapControllerImpl implements MapController { final width = _state.originalSize!.x; final height = _state.originalSize!.y; - var localPointCenterDistance = + final localPointCenterDistance = CustomPoint((width / 2) - localPoint.x, (height / 2) - localPoint.y); - var mapCenter = + final mapCenter = _state.options.crs.latLngToPoint(_state.center, _state.zoom); - var point = mapCenter - localPointCenterDistance; + final point = mapCenter - localPointCenterDistance; return _state.options.crs.pointToLatLng(point, _state.zoom); } From c228f78ecbd6e3ccff4d703e0cf3110e428f8a7d Mon Sep 17 00:00:00 2001 From: Hugo Heneault Date: Fri, 20 May 2022 09:27:19 +0200 Subject: [PATCH 7/7] Fix pointToLatLng with rotation Co-authored-by: Polo and ibrierley Update lib/src/map/map.dart Update lib/src/map/map.dart Fix trailing lines --- example/lib/pages/point_to_latlng.dart | 6 ------ lib/src/map/map.dart | 20 +++++++++++++++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/example/lib/pages/point_to_latlng.dart b/example/lib/pages/point_to_latlng.dart index ccc97516f..e6b7f787a 100644 --- a/example/lib/pages/point_to_latlng.dart +++ b/example/lib/pages/point_to_latlng.dart @@ -97,10 +97,6 @@ class PointToLatlngPage extends State { 'flutter logo (${latLng?.latitude.toStringAsPrecision(4)},${latLng?.longitude.toStringAsPrecision(4)})', textAlign: TextAlign.center, ), - const Text( - 'should be in target center, but try to rotate', - textAlign: TextAlign.center, - ), ], ))), Positioned( @@ -113,9 +109,7 @@ class PointToLatlngPage extends State { } void onMapEvent(MapEvent mapEvent, BuildContext context) { - // if (mapEvent is MapEventMove) { _updatePointLatLng(context); - // } } void _updatePointLatLng(context) { diff --git a/lib/src/map/map.dart b/lib/src/map/map.dart index 336d74a25..0b434ef67 100644 --- a/lib/src/map/map.dart +++ b/lib/src/map/map.dart @@ -92,10 +92,28 @@ class MapControllerImpl implements MapController { final mapCenter = _state.options.crs.latLngToPoint(_state.center, _state.zoom); - final point = mapCenter - localPointCenterDistance; + var point = mapCenter - localPointCenterDistance; + + if (_state.rotation != 0.0) { + point = rotatePoint(mapCenter, point); + } + return _state.options.crs.pointToLatLng(point, _state.zoom); } + CustomPoint rotatePoint( + CustomPoint mapCenter, CustomPoint point) { + final m = Matrix4.identity() + ..translate(mapCenter.x.toDouble(), mapCenter.y.toDouble()) + ..rotateZ(-_state.rotationRad) + ..translate(-mapCenter.x.toDouble(), -mapCenter.y.toDouble()); + + final tp = MatrixUtils.transformPoint( + m, Offset(point.x.toDouble(), point.y.toDouble())); + + return CustomPoint(tp.dx, tp.dy); + } + @override Stream get mapEventStream => _mapEventSink.stream; }