[Flutter] Geofflutterfire 범위 내 좌표의 신 포장에 대한 소개만 획득

56882 단어 Fluttertech

무엇이 Geofflutterfire입니까?


여러분geoflutterfire이 신의 포장을 아십니까...
geoflutterfire를 사용하면 Firestore에서 범위 내의 좌표만 얻을 수 있다. 아래와 같다.(엔화 대체기준)
geoflutterfireデモ
이번에는 관련 geoflutterfire 일본어 보도를 거의 찾지 못했기 때문에 여기에 기록한다.
마지막으로 샘플 코드도 넣어주세요!!

geofflutterfire 사용법


https://pub.dev/packages/geoflutterfire
이 문서에 따르면 Geofflutterfire의 특징은 다음과 같다!
  • 지리적 위치(좌표)를 문자열로 저장
  • 구역 내의 좌표를 실시간으로 획득
  • 특정 위치에 가까운 데이터만 로드되므로 매우 큰 데이터 세트라도 가볍게 이동할 수 있습니다.
  • 구체적으로 어떻게 하는지 봅시다.

    전제 조건


    Firebase 연결 및 Firestore 사용 가능 상태
    https://firebase.google.com/docs/flutter/setup?hl=ja&platform=ios

    초기화


    import 'package:geoflutterfire/geoflutterfire.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    
    // Init firestore and geoFlutterFire
    final geo = Geoflutterfire();
    final _firestore = FirebaseFirestore.instance;
    

    지리적 정보 쓰기


    사용GeoFirePoint
    GeoFirePoint geoFirePoint = geo.point(latitude: 12.960632, longitude: 77.641603);
    

    GeoFirePoint는


    지리 정보를 잘 처리하는 반.세 개의 Getter가 있습니다.
  • geoFirePoint.hash: 9자 GeoHash의 문자열을 반환합니다.geohash에 관해서는 뒤에서 서술할 것이다.예:s1b8yu2nj
  • geoFirePoint.geoPoint: Firestore에서 사용된 GeoPoint를 반환합니다.GeoPoint (double latitude, double longitude)는 위도 경도를 가지고 있다.
  • geoFirePoint.data: Firestore에 저장할 데이터를 반환합니다.예: {geopopint:Instance of'GeoPoint', geohash:s1b8yu2nj}
  • GeoFirePoint Firestore에 추가
    _firestore
            .collection('shop')
            .add({'name': 'random name', 'position': geoFirePoint.data});
    
    실제로는 Firestore에 이렇게 저장되어 있어요.
    Firestore

    지리 정보 얻기


    어느 지점에서 50km 이내의 문서를 검색하다.Stream에서 값을 받습니다.
    // Create a geoFirePoint
    GeoFirePoint center = geo.point(latitude: 12.960632, longitude: 77.641603);
    
    // get the collection reference or query
    var collectionReference = _firestore.collection('shop');
    
    double radius = 50;
    String field = 'position';
    
    Stream<List<DocumentSnapshot>> stream = 
    		geo.collection(collectionRef: collectionReference)
    		.within(center: center, radius: radius, field: field);
    
    수신된 Stream을 모니터링합니다.
    stream.listen((List<DocumentSnapshot> documentList) {
            // doSomething()
          });
    

    Geohash 소개


    https://techblog.yahoo.co.jp/entry/20191210786752/
    Yahoo!선생님의 문장은 매우 이해하기 쉽다Geohash!
    일부분을 인용할 수 있도록 허락해 주십시오 Geohash.
    Geohash는 지도를 격자 모양으로 나누어 짧은 문자열로 구획을 표현할 수 있습니다.예를 들어 도쿄역 주변의 Geohash 6자리 숫자는'xn76ur'로 표시된다.
    인접한 구획은 비슷한 문자열로 표시할 수 있기 때문에 Geohash 구획 옆에 있는 구획을 간단하게 계산할 수 있다.
    간단히 설명Geohash
  • 좌표를 문자열로 표시
  • 비트가 클수록 정밀도가 높음
  • 더 많은 문자열이 일치하면 두 점이 더 가깝다는 것을 나타낸다.
  • 이런 특징이 있다.
    Geofflutterfire는 9자리 문자열로 되돌아오기 때문에 정밀도가 높습니다.
    Yahoo!のテックブログから引用
    ※Yahoo!Tec의 블로그 참조

    Geofflutterfire를 사용해 보십시오


    마지막으로 여기 샘플 코드를 올려주세요!
    https://github.com/naokiwakata/map_sample

    차리다


    Firebase 연결 및 Firestore 를 사용할 수 있습니다.
    https://firebase.google.com/docs/flutter/setup?hl=ja&platform=ios
    Firestore에서 GeoFluterPoint 추가

    GoogleMap 사용 가능
    https://zenn.dev/wakanao/articles/3820bcd67e4130
    사용 중인 라이브러리
    pubspec.yaml
    dependencies:
      google_maps_flutter: ^2.1.2
      geolocator: ^8.2.0
      firebase_core: ^1.13.1
      cloud_firestore: ^3.1.10
      geoflutterfire: ^3.0.3
    
    샘플 코드
    main.dart
    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:firebase_core/firebase_core.dart';
    import 'package:flutter/material.dart';
    import 'package:geoflutterfire/geoflutterfire.dart';
    import 'package:geolocator/geolocator.dart';
    import 'package:google_maps_flutter/google_maps_flutter.dart';
    import 'package:rxdart/rxdart.dart';
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      runApp(
        MaterialApp(
          title: 'Geo Flutter Fire example',
          home: MyApp(),
          debugShowCheckedModeBanner: true,
        ),
      );
    }
    
    class MyApp extends StatefulWidget {
      
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      GoogleMapController? _mapController;
      TextEditingController? _latitudeController, _longitudeController;
    
      // firestore init
      final radius = BehaviorSubject<double>.seeded(1.0);
      final _firestore = FirebaseFirestore.instance;
      final markers = <MarkerId, Marker>{};
    
      late Stream<List<DocumentSnapshot>> stream;
      late Geoflutterfire geo;
    
      double _value = 20.0;
      String _label = '';
      double _ratio = 0;
    
      double screenWidthKms = 600;
    
      
      void initState() {
        super.initState();
        _latitudeController = TextEditingController();
        _longitudeController = TextEditingController();
    
        geo = Geoflutterfire();
        GeoFirePoint center =
            geo.point(latitude: 43.0779575, longitude: 142.337819);
        stream = radius.switchMap(
          (rad) {
            final collectionReference = _firestore.collection('shop');
    
            return geo.collection(collectionRef: collectionReference).within(
                center: center, radius: rad, field: 'position', strictMode: true);
          },
        );
    
        Future(() async {
          //_mapControllerがinitializeされるのを待つ1秒
          await Future.delayed(const Duration(seconds: 1));
          final region = await _mapController?.getVisibleRegion();
          final distanceInMeters = Geolocator.distanceBetween(
              region!.northeast.latitude,
              region.northeast.longitude,
              region.southwest.latitude,
              region.northeast.longitude);
          screenWidthKms = distanceInMeters / 1000;
          print('画面の横幅の距離 $screenWidthKms km');
        });
      }
    
      
      void dispose() {
        _latitudeController?.dispose();
        _longitudeController?.dispose();
        radius.close();
        super.dispose();
      }
    
      
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Center(
                  child: Card(
                    elevation: 4,
                    margin: const EdgeInsets.symmetric(vertical: 8),
                    child: SizedBox(
                      height: 550,
                      child: Stack(
                        children: [
                          GoogleMap(
                            onMapCreated: _onMapCreated,
                            initialCameraPosition: const CameraPosition(
                              target: LatLng(43.0779575, 142.337819),
                              zoom: 6.5,
                            ),
                            markers: Set<Marker>.of(markers.values),
                          ),
                          Center(
                            child: Container(
                              width: MediaQuery.of(context).size.width * (_ratio),
                              height: MediaQuery.of(context).size.width * (_ratio),
                              decoration: BoxDecoration(
                                color: Colors.grey.withOpacity(0.5),
                                shape: BoxShape.circle,
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.only(top: 8.0),
                  child: Slider(
                    min: 1,
                    max: screenWidthKms / 2,
                    divisions: 10,
                    value: _value,
                    label: _label,
                    activeColor: Colors.blue,
                    inactiveColor: Colors.blue.withOpacity(0.2),
                    onChanged: (double value) {
                      setState(() {
                        _value = value;
                        _label = '${_value.toInt().toString()} kms';
                        _ratio = _value / (screenWidthKms / 2);
                        markers.clear();
                      });
                      radius.add(value);
                    },
                  ),
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    SizedBox(
                      width: 100,
                      child: TextField(
                        controller: _latitudeController,
                        keyboardType: TextInputType.number,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                          labelText: 'lat',
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(8),
                          ),
                        ),
                      ),
                    ),
                    SizedBox(
                      width: 100,
                      child: TextField(
                        controller: _longitudeController,
                        keyboardType: TextInputType.number,
                        decoration: InputDecoration(
                            labelText: 'lng',
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(8),
                            )),
                      ),
                    ),
                    MaterialButton(
                      color: Colors.blue,
                      onPressed: () {
                        final lat =
                            double.parse(_latitudeController?.text ?? '0.0');
                        final lng =
                            double.parse(_longitudeController?.text ?? '0.0');
                        _addPoint(lat, lng);
                      },
                      child: const Text(
                        'ADD',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        );
      }
    
      void _onMapCreated(GoogleMapController controller) async {
        setState(() {
          _mapController = controller;
          //start listening after map is created
          stream.listen((List<DocumentSnapshot> documentList) {
            _updateMarkers(documentList);
          });
        });
      }
    
      void _addPoint(double lat, double lng) {
        GeoFirePoint geoFirePoint = geo.point(latitude: lat, longitude: lng);
        print(geoFirePoint.hash);
        print(geoFirePoint.geoPoint);
        print(geoFirePoint.data);
        print(geoFirePoint);
        _firestore
            .collection('shop')
            .add({'name': 'random name', 'position': geoFirePoint.data}).then((_) {
          print('added ${geoFirePoint.hash} successfully');
        });
      }
    
      void _addMarker(double lat, double lng) {
        final id = MarkerId(lat.toString() + lng.toString());
        final _marker = Marker(
          markerId: id,
          position: LatLng(lat, lng),
          icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueViolet),
          infoWindow: InfoWindow(title: 'latLng', snippet: '$lat,$lng'),
        );
        setState(() {
          markers[id] = _marker;
        });
      }
    
      void _updateMarkers(List<DocumentSnapshot> documentList) {
        documentList.forEach((DocumentSnapshot document) {
          final data = document.data() as Map<String, dynamic>;
          final GeoPoint point = data['position']['geopoint'];
          _addMarker(point.latitude, point.longitude);
        });
      }
    }
    
    

    총결산


    Geofflutterfire에 대해 조금만 이해해 주시겠어요!맵과 Firebase를 사용할 때는 꼭 사용하세요!

    좋은 웹페이지 즐겨찾기