import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart'; import 'package:latlong2/latlong.dart'; class ClusteringPage extends StatefulWidget { static const String route = 'clusteringPage'; const ClusteringPage({super.key}); @override State createState() => _ClusteringPageState(); } class _ClusteringPageState extends State { final PopupController _popupController = PopupController(); late List markers; late int pointIndex; List points = [ const LatLng(37.90970, 58.39795), const LatLng(37.90491, 58.39742), ]; @override void initState() { pointIndex = 0; markers = [ Marker( alignment: Alignment.center, height: 30, width: 30, point: points[pointIndex], child: const Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), const Marker( alignment: Alignment.center, height: 30, width: 30, point: LatLng(49.8566, 3.3522), child: Icon(Icons.pin_drop), ), ]; super.initState(); } @override Widget build(BuildContext context) { return Scaffold( floatingActionButton: FloatingActionButton( onPressed: () { pointIndex++; if (pointIndex >= points.length) { pointIndex = 0; } setState(() { markers[0] = Marker( point: points[pointIndex], alignment: Alignment.center, height: 30, width: 30, child: const Icon(Icons.pin_drop), ); markers = List.from(markers); }); }, child: const Icon(Icons.refresh), ), body: PopupScope( popupController: _popupController, child: FlutterMap( options: MapOptions( initialCenter: points[0], initialZoom: 4.5, maxZoom: 45, onTap: (_, __) => _popupController.hideAllPopups(), // Hide popup when the map is tapped. ), children: [ TileLayer( urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: const ['a', 'b', 'c'], ), MarkerClusterLayerWidget( options: MarkerClusterLayerOptions( spiderfyCircleRadius: 80, spiderfySpiralDistanceMultiplier: 2, circleSpiralSwitchover: 12, maxClusterRadius: 120, rotate: true, size: const Size(40, 40), alignment: Alignment.center, padding: const EdgeInsets.all(50), maxZoom: 15, markers: markers, polygonOptions: const PolygonOptions( borderColor: Colors.blueAccent, color: Colors.black12, borderStrokeWidth: 3, ), popupOptions: PopupOptions( popupSnap: PopupSnap.markerTop, popupController: _popupController, popupBuilder: (_, marker) => Container( width: 200, height: 100, color: Colors.white, child: GestureDetector( onTap: () => debugPrint('Popup tap!'), child: const Text( 'Container popup for marker', ), ), ), ), 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), ), ), ); }, ), ), PolylineLayer( polylineCulling: true, polylines: [ Polyline( points: [ // const LatLng(51.5, -0.09), // const LatLng(49.8566, 3.3522), // const LatLng(49.8566, 1.3522), // const LatLng(47.8566, 1.3522), // const LatLng(47.8566, 5.3522), // const LatLng(44.8566, 5.3522), // const LatLng(49.8566, 12.3522), // const LatLng(49.8864, 13.4522), // const LatLng(49.8966, 13.6522), const LatLng(37.90970, 58.39795), const LatLng(37.90491, 58.39742) ], borderStrokeWidth: 6.6, color: Colors.red, borderColor: Colors.green, ), ], ), ], ), ), ); } }