From 716dd6e70a38cf6b1ac8e855c96b0f79907e8ae7 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 29 Jul 2025 10:50:18 +0330 Subject: [PATCH] feat : Cluster Map --- packages/core/lib/core.dart | 1 + packages/core/pubspec.lock | 64 +++++++++++++++---- packages/core/pubspec.yaml | 5 +- .../pages/inspection_map/logic.dart | 46 ++++++++++--- .../pages/inspection_map/view.dart | 56 ++++++++-------- packages/inspection/pubspec.lock | 64 +++++++++++++++---- pubspec.lock | 64 +++++++++++++++---- 7 files changed, 225 insertions(+), 75 deletions(-) diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index ce05d09..86caf03 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -36,6 +36,7 @@ export 'package:pretty_dio_logger/pretty_dio_logger.dart'; export 'package:rasadyar_core/presentation/common/common.dart'; export 'package:rasadyar_core/presentation/utils/utils.dart'; export 'package:rasadyar_core/presentation/widget/widget.dart'; +export 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart'; //models export 'data/model/model.dart'; diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index ec15459..9eea597 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.3.0" + animated_stack_widget: + dependency: transitive + description: + name: animated_stack_widget + sha256: ce4788dd158768c9d4388354b6fb72600b78e041a37afc4c279c63ecafcb9408 + url: "https://pub.dev" + source: hosted + version: "0.0.4" archive: dependency: transitive description: @@ -217,14 +225,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - dart_polylabel2: - dependency: transitive - description: - name: dart_polylabel2 - sha256: "7eeab15ce72894e4bdba6a8765712231fc81be0bd95247de4ad9966abc57adc6" - url: "https://pub.dev" - source: hosted - version: "1.0.0" dart_style: dependency: transitive description: @@ -391,18 +391,34 @@ packages: dependency: "direct main" description: name: flutter_map - sha256: df33e784b09fae857c6261a5521dd42bd4d3342cb6200884bb70730638af5fd5 + sha256: "2ecb34619a4be19df6f40c2f8dce1591675b4eff7a6857bd8f533706977385da" url: "https://pub.dev" source: hosted - version: "8.2.1" + version: "7.0.2" flutter_map_animations: dependency: "direct main" description: name: flutter_map_animations - sha256: bf583863561861aaaf4854ae7ed8940d79bea7d32918bf7a85d309b25235a09e + sha256: "08233f89919049a3601e785d32e9d1d9e1faac6578190150f1d7495fc1050d36" url: "https://pub.dev" source: hosted - version: "0.9.0" + version: "0.8.0" + flutter_map_marker_cluster: + dependency: "direct main" + description: + name: flutter_map_marker_cluster + sha256: "2c1fb4d7a2105c4bbeb89be215320507f4b71b2036df4341fab9d2aa677d3ae9" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + flutter_map_marker_popup: + dependency: transitive + description: + name: flutter_map_marker_popup + sha256: a7540538114b5d1627ab67b498273d66bc36090385412ae49ef215af4a2861c5 + url: "https://pub.dev" + source: hosted + version: "7.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -957,6 +973,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -1133,6 +1157,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.9.1" + polylabel: + dependency: transitive + description: + name: polylabel + sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" pool: dependency: transitive description: @@ -1165,6 +1197,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + provider: + dependency: transitive + description: + name: provider + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + url: "https://pub.dev" + source: hosted + version: "6.1.5" pub_semver: dependency: transitive description: diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index e064032..f87b92b 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -68,8 +68,9 @@ dependencies: android_intent_plus: ^5.3.0 #Map - flutter_map: ^8.2.1 - flutter_map_animations: ^0.9.0 + flutter_map: ^7.0.0 + flutter_map_animations: ^0.8.0 + flutter_map_marker_cluster: ^1.4.0 #location latlong2: ^0.9.1 geolocator: ^14.0.2 diff --git a/packages/inspection/lib/presentation/pages/inspection_map/logic.dart b/packages/inspection/lib/presentation/pages/inspection_map/logic.dart index f1dfd8c..ede317b 100644 --- a/packages/inspection/lib/presentation/pages/inspection_map/logic.dart +++ b/packages/inspection/lib/presentation/pages/inspection_map/logic.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; @@ -11,12 +12,12 @@ import '../filter/view.dart'; class InspectionMapLogic extends GetxController with GetTickerProviderStateMixin { final BaseLogic baseLogic = Get.find(); - + final distance = Distance(); Rx currentLocation = LatLng(34.798315281272544, 48.51479142983491).obs; Rx>> allPoultryLocation = Resource>.loading().obs; - RxList markers = [].obs; + RxList markers = [].obs; Timer? _debounceTimer; RxBool isLoading = false.obs; @@ -25,6 +26,7 @@ class InspectionMapLogic extends GetxController with GetTickerProviderStateMixin RxInt filterIndex = 0.obs; RxInt showIndex = 0.obs; bool showSlideHint = true; + RxInt currentZoom = 15.obs; late Rx slidController; @@ -114,17 +116,28 @@ class InspectionMapLogic extends GetxController with GetTickerProviderStateMixin isLoading.value = false; } - void debouncedUpdateVisibleMarkers({required LatLng center}) { + void debouncedUpdateVisibleMarkers({required LatLng center, required double zoom}) { _debounceTimer?.cancel(); _debounceTimer = Timer(const Duration(milliseconds: 300), () { + var raduis = getVisibleRadiusKm( + zoom: zoom, + screenWidthPx: Get.width.toDouble(), + latitude: center.latitude, + ); final filtered = filterNearbyMarkers( allPoultryLocation.value.data ?? [], center.latitude, center.longitude, - 10000, // Radius in meters + raduis * 1000, // Radius in meters + ); + markers.assignAll( + filtered.map( + (e) => Marker( + point: LatLng(e.lat ?? 0, e.long ?? 0), + child: Icon(Icons.location_on, color: Colors.red), + ), + ), ); - - markers.addAll(filtered); }); } @@ -135,11 +148,10 @@ class InspectionMapLogic extends GetxController with GetTickerProviderStateMixin double radiusInMeters, ) { final center = LatLng(centerLat, centerLng); - final distance = Distance(); return allMarkers.where((marker) { - var tmp =LatLng(marker.lat ?? 0, marker.long ?? 0); - return distance(center,tmp ) <= radiusInMeters; + var tmp = LatLng(marker.lat ?? 0, marker.long ?? 0); + return distance(center, tmp) <= radiusInMeters; }).toList(); } @@ -155,7 +167,11 @@ class InspectionMapLogic extends GetxController with GetTickerProviderStateMixin isLoading.value = true; allPoultryLocation.value = Resource>.loading(); await safeCall( - call: () => inspectionRepository.getNearbyLocation(), + call: () => inspectionRepository.getNearbyLocation( + centerLat: currentLocation.value.latitude, + centerLng: currentLocation.value.longitude, + radius: 15, // Radius in K meters + ), onSuccess: (result) { if (result != null) { allPoultryLocation.value = Resource>.success(result); @@ -170,4 +186,14 @@ class InspectionMapLogic extends GetxController with GetTickerProviderStateMixin }, ); } + + double getVisibleRadiusKm({ + required double zoom, + required double screenWidthPx, + required double latitude, + }) { + double metersPerPixel = 156543.03392 * cos(latitude * pi / 180) / pow(2, zoom); + double visibleWidthInMeters = metersPerPixel * screenWidthPx; + return (visibleWidthInMeters / 2) / 1000; // radius in KM + } } diff --git a/packages/inspection/lib/presentation/pages/inspection_map/view.dart b/packages/inspection/lib/presentation/pages/inspection_map/view.dart index 9645419..1d3734f 100644 --- a/packages/inspection/lib/presentation/pages/inspection_map/view.dart +++ b/packages/inspection/lib/presentation/pages/inspection_map/view.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_inspection/presentation/pages/filter/view.dart'; import 'package:rasadyar_inspection/presentation/routes/app_routes.dart'; import 'package:rasadyar_inspection/presentation/widget/base_page/view.dart'; import 'package:rasadyar_inspection/presentation/widget/custom_chips.dart'; @@ -39,40 +38,44 @@ class InspectionMapPage extends GetView { mapController: controller.animatedMapController.mapController, options: MapOptions( initialCenter: currentLocation.value, - initialZoom: 18, + interactionOptions: const InteractionOptions( + flags: InteractiveFlag.all & ~InteractiveFlag.rotate, + ), + initialZoom: 15, onPositionChanged: (camera, hasGesture) { - controller.debouncedUpdateVisibleMarkers(center: camera.center); + controller.debouncedUpdateVisibleMarkers(center: camera.center,zoom: camera.zoom); }, ), + children: [ TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', userAgentPackageName: 'ir.mnpc.rasadyar', ), - ObxValue((markers) { - return MarkerLayer( - markers: markers - .map( - (e) => markerWidget( - marker: LatLng(e.lat??0, e.long??0), - onTap: () { - Get.bottomSheet( - selectedLocationWidget2( - showHint: false, - sliderController: controller.slidController.value, - trigger: () {}, - toggle: () {}, - ), - isScrollControlled: true, - enableDrag: true, - backgroundColor: Colors.transparent, - ); - }, + MarkerClusterLayerWidget( + options: MarkerClusterLayerOptions( + maxClusterRadius: 80, + size: const Size(40, 40), + alignment: Alignment.center, + padding: const EdgeInsets.all(50), + maxZoom: 15, + markers: controller.markers, + builder: (context, markers) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Colors.blue, + ), + child: Center( + child: Text( + markers.length.toString(), + style: const TextStyle(color: Colors.white), ), - ) - .toList(), - ); - }, controller.markers), + ), + ); + }, + ), + ), ], ); }, controller.currentLocation), @@ -521,7 +524,6 @@ Widget cardWithLabel({ ); } - Widget selectedLocationWidget({ required bool showHint, required SlidableController sliderController, diff --git a/packages/inspection/pubspec.lock b/packages/inspection/pubspec.lock index b52d807..dda8513 100644 --- a/packages/inspection/pubspec.lock +++ b/packages/inspection/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.3.0" + animated_stack_widget: + dependency: transitive + description: + name: animated_stack_widget + sha256: ce4788dd158768c9d4388354b6fb72600b78e041a37afc4c279c63ecafcb9408 + url: "https://pub.dev" + source: hosted + version: "0.0.4" archive: dependency: transitive description: @@ -233,14 +241,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - dart_polylabel2: - dependency: transitive - description: - name: dart_polylabel2 - sha256: "7eeab15ce72894e4bdba6a8765712231fc81be0bd95247de4ad9966abc57adc6" - url: "https://pub.dev" - source: hosted - version: "1.0.0" dart_style: dependency: transitive description: @@ -407,18 +407,34 @@ packages: dependency: transitive description: name: flutter_map - sha256: df33e784b09fae857c6261a5521dd42bd4d3342cb6200884bb70730638af5fd5 + sha256: "2ecb34619a4be19df6f40c2f8dce1591675b4eff7a6857bd8f533706977385da" url: "https://pub.dev" source: hosted - version: "8.2.1" + version: "7.0.2" flutter_map_animations: dependency: transitive description: name: flutter_map_animations - sha256: bf583863561861aaaf4854ae7ed8940d79bea7d32918bf7a85d309b25235a09e + sha256: "08233f89919049a3601e785d32e9d1d9e1faac6578190150f1d7495fc1050d36" url: "https://pub.dev" source: hosted - version: "0.9.0" + version: "0.8.0" + flutter_map_marker_cluster: + dependency: transitive + description: + name: flutter_map_marker_cluster + sha256: "2c1fb4d7a2105c4bbeb89be215320507f4b71b2036df4341fab9d2aa677d3ae9" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + flutter_map_marker_popup: + dependency: transitive + description: + name: flutter_map_marker_popup + sha256: a7540538114b5d1627ab67b498273d66bc36090385412ae49ef215af4a2861c5 + url: "https://pub.dev" + source: hosted + version: "7.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -973,6 +989,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" node_preamble: dependency: transitive description: @@ -1157,6 +1181,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.9.1" + polylabel: + dependency: transitive + description: + name: polylabel + sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" pool: dependency: transitive description: @@ -1189,6 +1221,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + provider: + dependency: transitive + description: + name: provider + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + url: "https://pub.dev" + source: hosted + version: "6.1.5" pub_semver: dependency: transitive description: diff --git a/pubspec.lock b/pubspec.lock index e64ee24..b93bb67 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.3.0" + animated_stack_widget: + dependency: transitive + description: + name: animated_stack_widget + sha256: ce4788dd158768c9d4388354b6fb72600b78e041a37afc4c279c63ecafcb9408 + url: "https://pub.dev" + source: hosted + version: "0.0.4" archive: dependency: transitive description: @@ -233,14 +241,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - dart_polylabel2: - dependency: transitive - description: - name: dart_polylabel2 - sha256: "7eeab15ce72894e4bdba6a8765712231fc81be0bd95247de4ad9966abc57adc6" - url: "https://pub.dev" - source: hosted - version: "1.0.0" dart_style: dependency: transitive description: @@ -415,18 +415,34 @@ packages: dependency: transitive description: name: flutter_map - sha256: df33e784b09fae857c6261a5521dd42bd4d3342cb6200884bb70730638af5fd5 + sha256: "2ecb34619a4be19df6f40c2f8dce1591675b4eff7a6857bd8f533706977385da" url: "https://pub.dev" source: hosted - version: "8.2.1" + version: "7.0.2" flutter_map_animations: dependency: transitive description: name: flutter_map_animations - sha256: bf583863561861aaaf4854ae7ed8940d79bea7d32918bf7a85d309b25235a09e + sha256: "08233f89919049a3601e785d32e9d1d9e1faac6578190150f1d7495fc1050d36" url: "https://pub.dev" source: hosted - version: "0.9.0" + version: "0.8.0" + flutter_map_marker_cluster: + dependency: transitive + description: + name: flutter_map_marker_cluster + sha256: "2c1fb4d7a2105c4bbeb89be215320507f4b71b2036df4341fab9d2aa677d3ae9" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + flutter_map_marker_popup: + dependency: transitive + description: + name: flutter_map_marker_popup + sha256: a7540538114b5d1627ab67b498273d66bc36090385412ae49ef215af4a2861c5 + url: "https://pub.dev" + source: hosted + version: "7.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -981,6 +997,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -1157,6 +1181,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.9.1" + polylabel: + dependency: transitive + description: + name: polylabel + sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" pool: dependency: transitive description: @@ -1189,6 +1221,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + provider: + dependency: transitive + description: + name: provider + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + url: "https://pub.dev" + source: hosted + version: "6.1.5" pub_semver: dependency: transitive description: