본문 바로가기
개발/Flutter

Google map clustering

by dev_caleb 2022. 1. 26.
728x90

정말 멋진 Googlemap clustering library를 발견했다.. 

 

https://pub.dev/packages/google_maps_cluster_manager

 

google_maps_cluster_manager | Flutter Package

Simple Flutter clustering library for Google Maps based on Geohash.

pub.dev

아래는 multiple group 예시가 있어서 내 맛에 맞게 살짝 변경했는데 너무 마음에 든다..ㅠㅠ

 

 

import 'dart:async';
import 'dart:ui';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:matjipmemo/constants/material_color.dart';

import 'tools/place.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Cluster Manager Demo',
      home: MapSample(),
    );
  }
}

// Clustering maps

class MapSample extends StatefulWidget {
  @override
  State<MapSample> createState() => MapSampleState();
}

double latitude= 35.1856036;
double longitude = 129.0838361;
class MapSampleState extends State<MapSample> {
   ClusterManager _manager;
   ClusterManager _manager2;


  Completer<GoogleMapController> _controller = Completer();

  Set<Marker> markers = Set();
  Set<Marker> markers2 = Set();

  final CameraPosition _initialCameraPosition =
  CameraPosition(target: LatLng(latitude, longitude), zoom: 12.0);

  List<Place> items = [
    for (int i = 0; i < 10; i++)
      Place(
          name: 'Restaurant $i',
          isClosed: i % 2 == 0,
          latLng: LatLng(latitude - i * 0.001, longitude + i * 0.001)),
    for (int i = 0; i < 10; i++)
      Place(
          name: 'Bar $i',
          latLng: LatLng(latitude + i * 0.01, longitude - i * 0.01)),
    for (int i = 0; i < 10; i++)
      Place(
          name: 'Hotel $i',
          latLng: LatLng(latitude - i * 0.1, longitude - i * 0.01)),
  ];

  List<Place> items2 = [
    for (int i = 0; i < 10; i++)
      Place(
          name: 'Place $i',
          latLng: LatLng(latitude + i * 0.001, longitude + i * 0.001)),
    for (int i = 0; i < 10; i++)
      Place(
          name: 'Test $i',
          latLng: LatLng(latitude + i * 0.1, longitude + i * 0.1)),
    for (int i = 0; i < 10; i++)
      Place(
          name: 'Test2 $i',
          latLng: LatLng(latitude + i * 1, longitude + i * 1)),
  ];

  @override
  void initState() {
    _manager = ClusterManager<Place>(items, _updateMarkers,
        markerBuilder: _getMarkerBuilder(maincolor));

    _manager2 = ClusterManager<Place>(items2, _updateMarkers2,
        markerBuilder: _getMarkerBuilder(Colors.blue));
    super.initState();
  }

  void _updateMarkers(Set<Marker> markers) {
    setState(() {
      this.markers = markers;
    });
  }

  void _updateMarkers2(Set<Marker> markers) {
    setState(() {
      this.markers2 = markers;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: GoogleMap(

          mapType: MapType.normal,
          initialCameraPosition: _initialCameraPosition,
          markers: markers..addAll(markers2),
          onMapCreated: (GoogleMapController controller) {
            _controller.complete(controller);
            _manager.setMapId(controller.mapId);
            _manager2.setMapId(controller.mapId);
          },
          onCameraMove: (position) {
            _manager.onCameraMove(position);
            _manager2.onCameraMove(position);
          },
          onCameraIdle: () {
            _manager.updateMap();
            _manager2.updateMap();
          },
        onTap: (latlng){
          print("클릭 ${latlng.longitude}, ${latlng.latitude}");
        },
        myLocationEnabled: true,
        tiltGesturesEnabled: false,
        rotateGesturesEnabled: false,
        zoomControlsEnabled: false,
        mapToolbarEnabled: false,
        compassEnabled: false,
        liteModeEnabled: false,
      ),

      /*floatingActionButton: FloatingActionButton(
        onPressed: () {
          _manager.setItems(<Place>[
            for (int i = 0; i < 30; i++)
              Place(
                  name: 'New Place ${DateTime.now()} $i',
                  latLng: LatLng(latitude + i * 0.01, longitude))
          ]);
        },
        child: Icon(Icons.update),
      ),*/
    );
  }

  Future<Marker> Function(Cluster<Place>) _getMarkerBuilder(Color color) =>
          (cluster) async {
        return Marker(
          markerId: MarkerId(cluster.getId()),
          position: cluster.location,
          onTap: () {
            print("click!");
            if(!cluster.isMultiple){print("싱글!");}else{print("멀티!");}
            print('---- $cluster');
            cluster.items.forEach((p) => print(p));
          },
          icon: await _getMarkerBitmap(//cluster.isMultiple ?
          180 //:150
              , color,
              text:  cluster.count.toString(), clustercount: cluster.count ),
        );
      };

  Future<BitmapDescriptor> _getMarkerBitmap(int size, Color color,
      {String text, @required int clustercount}) async {
    if (kIsWeb) size = (size / 2).floor();

    final PictureRecorder pictureRecorder = PictureRecorder();
    final Canvas canvas = Canvas(pictureRecorder);
    final Paint paint1 = Paint()..color = color;
    final Paint paint2 = Paint()..color = Colors.white;
    if(clustercount>1){
    canvas.drawCircle(Offset(size / 2, size / 2), size / 3.0, paint1);
    canvas.drawCircle(Offset(size / 2, size / 2), size / 3.3, paint2);
    canvas.drawCircle(Offset(size / 2, size / 2), size / 4.4, paint1);}else{
      canvas.drawCircle(Offset(size / 2, size / 2), size / 4.5, paint1);
      canvas.drawCircle(Offset(size / 2, size / 2), size / 4.9, paint2);
      canvas.drawCircle(Offset(size / 2, size / 2), size / 6.5, paint1);
    }

    if (text != null) {
      TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
      if(clustercount>1){
      painter.text = TextSpan(
        text: text,
        style: TextStyle(
            fontSize: size / 4,
            color: Colors.white,
            fontWeight: FontWeight.normal),
      );
      painter.layout();
      painter.paint(
        canvas,
        Offset(size / 2 - painter.width / 2, size / 2 - painter.height / 2   + 0),
      );}else {
        painter.text = TextSpan(
          text: text,
          style: TextStyle(
              fontSize: size / 4,
              color: Colors.black87,
              fontWeight: FontWeight.bold),
        );
        painter.layout();
        painter.paint(
          canvas,
          Offset(size / 2 - painter.width / 2, size - painter.height),
        );
      }

    }

    final img = await pictureRecorder.endRecording().toImage(size, size);
    final data = await img.toByteData(format: ImageByteFormat.png);

    return BitmapDescriptor.fromBytes(data.buffer.asUint8List());
  }
}
728x90