From 48511fad7bdd94eb0d94efb92f39c2e55713c441 Mon Sep 17 00:00:00 2001 From: Dewmal Date: Sat, 25 Apr 2020 12:37:15 +0530 Subject: [PATCH] Map clustering --- lib/page/screen/case_details_map_screen.dart | 209 +++++++++++-------- pubspec.lock | 23 +- pubspec.yaml | 4 +- 3 files changed, 140 insertions(+), 96 deletions(-) diff --git a/lib/page/screen/case_details_map_screen.dart b/lib/page/screen/case_details_map_screen.dart index caf4341..05f82a1 100644 --- a/lib/page/screen/case_details_map_screen.dart +++ b/lib/page/screen/case_details_map_screen.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:async/async.dart'; +import 'package:clustering_google_maps/clustering_google_maps.dart'; import 'package:geolocator/geolocator.dart'; import 'package:intl/intl.dart'; @@ -23,6 +24,7 @@ class CaseListMapDetailScreen extends StatefulWidget { } class _CaseListMapDetailScreenState extends State { + ClusteringHelper clusteringHelper; static const MethodChannel _channel = MethodChannel('location'); ReportedCase selectedCase; @@ -31,56 +33,77 @@ class _CaseListMapDetailScreenState extends State { double pinPillPosition = -1000; List locationMarkers = []; + List mapMakerList = []; + Map caseListMapWithId = Map(); - Future _fetchCases(BitmapDescriptor mapIcon) async { + Future _fetchCases() async { List _cases = []; int id = await ApiClient().getLastCaseId(); if (id == -1) { return _cases; } + for (int i = id; i > 0; i--) { ReportedCase reportedCase = await ApiClient().getCase(i, forceUpdate: false); if (reportedCase != null && reportedCase.locations != null) { Location l = reportedCase.locations[0]; + var latLan = LatLngAndGeohash(LatLng(l.latitude, l.longitude)); setState(() { - locationMarkers.add( - Marker( - icon: mapIcon, - alpha: 0.5, - markerId: MarkerId("${l.date.millisecondsSinceEpoch}"), - position: LatLng(l.latitude, l.longitude), - onTap: () { - setState(() { - selectedCase = reportedCase; - pinPillPosition = MediaQuery.of(context).size.height / 10; - }); - }), - ); + caseListMapWithId[latLan.geohash] = reportedCase; + mapMakerList.add(latLan); }); } + + setState(() { + clusteringHelper = ClusteringHelper.forMemory( + list: mapMakerList, + bitmapAssetPathForSingleMarker: "assets/images/suspected_icon.png", + updateMarkers: (Set markers) { + setState(() { + locationMarkers = markers.map((marker) { + int count = int.parse(marker.infoWindow.title); + if (count == 1) { + LatLng l = marker.position; + ReportedCase reportedCase = caseListMapWithId[ + "${LatLngAndGeohash(LatLng(l.latitude, l.longitude)).geohash}"]; + return Marker( + icon: marker.icon, + alpha: 0.5, + markerId: marker.markerId, + position: LatLng(l.latitude, l.longitude), + onTap: () { + setState(() { + selectedCase = reportedCase; + pinPillPosition = + MediaQuery.of(context).size.height / 10; + }); + }); + } + return Marker( + icon: marker.icon, + markerId: marker.markerId, + position: marker.position, + onTap: () { + setState(() { + pinPillPosition = -MediaQuery.of(context).size.height; + }); + }); + ; + }).toList(); + }); + }, + aggregationSetup: AggregationSetup(markerSize: 150)); + }); } + print("Cases found Retreived: ${_cases.length}"); } @override void initState() { super.initState(); - - BitmapDescriptor.fromAssetImage( - ImageConfiguration(devicePixelRatio: 0.1, size: Size(0.5, 0.5)), - "assets/images/user_icon.png") - .then((userIcon) { - BitmapDescriptor.fromAssetImage( - ImageConfiguration(devicePixelRatio: 0.1, size: Size(0.5, 0.5)), - "assets/images/suspected_icon.png") - .then((suspectIcon) { - _fetchCases(suspectIcon); -// getLocationUpdate().then((List locations) { -// -// }); - }); - }); + _fetchCases(); } @override @@ -100,65 +123,77 @@ class _CaseListMapDetailScreenState extends State { Widget getMapView() { return Scaffold( - body: Stack( - children: [ - GoogleMap( - mapType: MapType.terrain, - markers: getMapEntries(), - initialCameraPosition: CameraPosition( - target: _currentLocation != null - ? LatLng( - _currentLocation.latitude, _currentLocation.longitude) - : LatLng(6.9271, 79.8612), - zoom: 12, + body: clusteringHelper != null + ? Stack( + children: [ + GoogleMap( + mapType: MapType.terrain, + markers: getMapEntries(), + initialCameraPosition: CameraPosition( + target: _currentLocation != null + ? LatLng(_currentLocation.latitude, + _currentLocation.longitude) + : LatLng(6.9271, 79.8612), + zoom: 12, + ), + mapToolbarEnabled: true, + myLocationButtonEnabled: true, + myLocationEnabled: true, + onMapCreated: (GoogleMapController controller) async { + _controller.complete(controller); + clusteringHelper.mapController = controller; + clusteringHelper.updateMap(); + }, + onCameraMove: (position) { + clusteringHelper.onCameraMove(position, forceUpdate: true); + }, + onCameraIdle: clusteringHelper.onMapIdle, + onTap: (LatLng location) { + setState(() { + pinPillPosition = -MediaQuery.of(context).size.height; + }); + }, + ), + AnimatedPositioned( + bottom: pinPillPosition, + right: 0, + left: 0, + duration: Duration(milliseconds: 300), + child: Align( + alignment: Alignment.bottomCenter, + child: Container( + margin: EdgeInsets.all(4), + width: MediaQuery.of(context).size.width * 7 / 8, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(16)), + boxShadow: [ + BoxShadow( + blurRadius: 20, + offset: Offset.zero, + color: Colors.grey.withOpacity(0.5)) + ]), + child: selectedCase != null + ? Padding( + padding: const EdgeInsets.all(8.0), + child: CaseItemMapInfo(selectedCase, () { + print("Click Card"); + setState(() { + pinPillPosition = + -MediaQuery.of(context).size.height; + }); + }), + ) + : Container(), + )), + ) + ], + ) + : Container( + child: Center( + child: Text("Loading..."), + ), ), - mapToolbarEnabled: true, - myLocationButtonEnabled: true, - myLocationEnabled: true, - onMapCreated: (GoogleMapController controller) { - _controller.complete(controller); - }, - onTap: (LatLng location) { - setState(() { - pinPillPosition = -MediaQuery.of(context).size.height; - }); - }, - ), - AnimatedPositioned( - bottom: pinPillPosition, - right: 0, - left: 0, - duration: Duration(milliseconds: 300), - child: Align( - alignment: Alignment.bottomCenter, - child: Container( - margin: EdgeInsets.all(4), - width: MediaQuery.of(context).size.width * 7 / 8, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(16)), - boxShadow: [ - BoxShadow( - blurRadius: 20, - offset: Offset.zero, - color: Colors.grey.withOpacity(0.5)) - ]), - child: selectedCase != null - ? Padding( - padding: const EdgeInsets.all(8.0), - child: CaseItemMapInfo(selectedCase, () { - print("Click Card"); - setState(() { - pinPillPosition = - -MediaQuery.of(context).size.height; - }); - }), - ) - : Container(), - )), - ) - ], - ), ); } diff --git a/pubspec.lock b/pubspec.lock index 8fddca8..7f89355 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,6 +57,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + clustering_google_maps: + dependency: "direct main" + description: + name: clustering_google_maps + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2" collection: dependency: transitive description: @@ -186,13 +193,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.7" flutter_test: dependency: "direct dev" description: flutter @@ -203,6 +203,13 @@ packages: description: flutter source: sdk version: "0.0.0" + geohash: + dependency: transitive + description: + name: geohash + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" geolocator: dependency: "direct main" description: @@ -237,7 +244,7 @@ packages: name: google_maps_flutter url: "https://pub.dartlang.org" source: hosted - version: "0.5.26+4" + version: "0.5.21+3" html: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fa9b500..2d75527 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: share: ^0.6.3+6 firebase_messaging: ^6.0.13 firebase_remote_config: ^0.3.0+3 - google_maps_flutter: ^0.5.24+1 + google_maps_flutter: ^0.5.21+3 shared_preferences: ^0.5.6+3 url_launcher: ^5.4.2 http: ^0.12.0+4 @@ -45,6 +45,8 @@ dependencies: auto_size_text: ^2.1.0 flutter_html: ^0.11.1 + clustering_google_maps: ^0.1.2 + flutter_localizations: sdk: flutter