Geo Location atau posisi suatu titik di dalam permukaan bumi banyak digunakan pada aplikasi-aplikasi pada khusunya aplikasi berbasis mobile. Flutter memiliki plugin untuk menangani lokasi secara realtime dan dapat diatur untuk mengoptimalkan performa dan baterai.
Daftar Isi
Map Flutter
Flutter memudahkan pengembang dalam membuat aplikasi mobile yang menggunakan posisi berbasis GPS secara realtime hanya dengan beberapa baris kode saja.
— Geo Location Flutter: Aku Peta, Aku Peta
Konsep Lokasi Bumi (Geo Location)
Konsep lokasi di bumi berbeda dengan konsep lokasi di atas kertas. Bumi adalah bola 3D, sedangkan kertas adalah bangun datar 2D. Rumus yang melibatkan titik di atas kertas 2D berbeda dengan rumus yang melibatkan titik pada ruang bola 3D.
Sebagai contoh, rumus untuk menghitung jarak 2 titik di atas kertas adalah √(xb-xa)2+(yb-ya)2
, sedangkan rumus untuk menghitung jarak 2 titik pada permukaan bola 3D tidak sesederhana itu (baca: https://en.wikipedia.org/wiki/Haversine_formula).
Untuk menentukan lokasi suatu titik [C]/[E] berada di dalam atau di dalam suatu batas (lingkaran), dibutuhkan informasi: titik pusat [A], jari-jari/radius batas (lingkaran) [AD] dan titik yang dicari itu sendiri [C]/[E].
Apabila jari-jari tidak diketahui, maka harus diketahui salah satu titik yang ditentukan sebagai batas [B]. Kemudian, jari-jari didapat dari jarak [AB].
Apabila jarak suatu titik dengan titik pusat [AC]/[AE] lebih kecil atau sama dengan dari jari-jari [AB]/[AD], maka titik tersebut berada di dalam suatu batas (lingkaran). Apabila jarak suatu titik dengan titik pusat [AC]/[AE] lebih besar dari jari-jari [AB]/[AD], maka titik tersebut berada di dalam suatu batas (lingkaran).
Kelas Lokasi di Bumi (GeoLocation)
//filename: ./library/geolocationpoint.dart
import 'package:geolocator/geolocator.dart';
import 'package:location/location.dart';
class GeoLocation{
GeoPoint userlocation = new GeoPoint.createZeroPoint();
GeoPoint centerlocation = new GeoPoint.createZeroPoint();
GeoPoint outerlocation = new GeoPoint.createNullPoint();
double radiuscentermeters = 0.0;
bool isInRange = false;
//constructor
GeoLocation({required this.userlocation});
GeoLocation.createZeroUserPoint()
{
this.userlocation = new GeoPoint.createZeroPoint();
}
GeoLocation.createUserPoint(double lat, double long)
{
setPointUser(lat, long);
}
GeoLocation.createUserPointLocationData(LocationData loc)
{
setPointUser(loc.latitude!, loc.longitude!);
}
GeoLocation.fromJson(Map<String, dynamic> json)
{
setPointUser(json['latitude'], json['longitude']);
}
//setter
void setPointUserLocationData(LocationData loc)
{
setPointUser(loc.latitude!, loc.longitude!);
}
void setPointUser(double lat, double long)
{
userlocation.setPoint(lat, long);
this._calculateRadiusMetersAndInRange();
}
void setPointOuterLocationData(LocationData loc)
{
setPointOuter(loc.latitude!, loc.longitude!);
}
void setPointOuter(double lat, double long)
{
outerlocation.setPoint(lat, long);
this._calculateRadiusMetersAndInRange();
}
void setPointCenterLocationData(LocationData loc)
{
setPointCenter(loc.latitude!, loc.longitude!);
}
void setPointCenter(double lat, double long)
{
centerlocation.setPoint(lat, long);
this._calculateRadiusMetersAndInRange();
}
set setRadius(double radiusmeters)
{
this.radiuscentermeters = radiusmeters;
_calculateInRange();
}
//measure
double distanceUserFromCenter()
{
return centerlocation.distanceWith(userlocation);
}
double distanceOuterFromCenter()
{
return centerlocation.distanceWith(outerlocation);
}
double distanceUserFromOuter()
{
double radius = this.distanceUserFromCenter() - this.distanceOuterFromCenter();
return radius < 0 ? -radius : radius;
}
//calculation
void _calculateRadiusMetersAndInRange()
{
if (this.radiuscentermeters == 0.0)
this._calculateRadiusMeters();
_calculateInRange();
}
void _calculateRadiusMeters()
{
if (this.outerlocation.latitude != null && this.outerlocation.longitude != null)
this.radiuscentermeters = this.distanceOuterFromCenter();
}
void _calculateInRange()
{
this.isInRange = this.radiuscentermeters >= this.distanceUserFromCenter();
}
}
class GeoPoint{
double? latitude;
double? longitude;
GeoPoint({required this.latitude, required this.longitude});
GeoPoint.createNullPoint()
{
this.latitude = null;
this.longitude = null;
}
GeoPoint.createZeroPoint()
{
this.latitude = 0.0;
this.longitude = 0.0;
}
void setPoint(double lat, double long)
{
this.latitude = lat;
this.longitude = long;
}
double distanceWith(GeoPoint otherpoint)
{
return GeolocatorPlatform.instance.distanceBetween(this.latitude!, this.longitude!, otherpoint.latitude!, otherpoint.longitude!);
}
}
Konstanta
Konstanta ini dipakai untuk latitude dan longitude pada saat uji coba.
//filename: ./utils/const.dart
final double dummyCenterLatitude = -7.8002;
final double dummyCenterLongitude = 110.3914;
Kelas Layanan Lokasi (LocationService)
Kelas ini akan memberikan informasi lokasi (latitude dan longitude) alat pengguna. Terdapat dua alternatif yang dapat digunakan. Pada uji coba ini digunakan alternatif 1.
//filename: ./service/location_service.dart
import 'dart:async';
import '../library/geolocationpoint.dart';
import 'package:location/location.dart';
class LocationService {
//alternatif 1: dinamis, otomatis berubah ketika posisi berubah
//inisialisasi memulai mengaktifkan service lokasi
LocationService() {
Location location = Location();
location.requestPermission().then((granted) {
if (granted == PermissionStatus.granted) {
location.onLocationChanged.listen((dataLokasi) {
_locationController.add(GeoLocation.createUserPointLocationData(dataLokasi));
});
}
});
}
//update lokasi (lewat stream)
StreamController<GeoLocation> _locationController = StreamController<GeoLocation>();
Stream<GeoLocation> get locationStream => _locationController.stream;
//alternatif 2: statis, hanya menampilkan ketika getLocation dipanggil
Future<GeoLocation?> getLocation() async {
Location location = Location();
GeoLocation? _currentLocation;
try {
var userLocation = await location.getLocation();
_currentLocation = GeoLocation.createUserPointLocationData(userLocation);
} on Exception catch (e) {
print('Gagal ambil lokasi: ${e.toString()}');
}
return _currentLocation;
}
}
Kelas Utama
//filename: ./main.dart
import './library/geolocationpoint.dart';
import './view/home_view.dart';
import 'package:akupeta/service/location_service.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamProvider<GeoLocation>(
//data awal: titik (0, 0)
initialData: GeoLocation.createZeroUserPoint(),
//baca lokasi pada saat pertama kali
create: (context) => LocationService().locationStream,
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeView(),
),
);
}
}
Kelas Tampilan
Radius dan titik pusat dapat diganti dengan data yang diambil dari basis data atau melalui mekanisme lain.
//filename: ./view/home_view.dart
import '../library/geolocationpoint.dart';
import 'package:akupeta/utils/const.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HomeView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _HomeViewPageState();
}
}
class _HomeViewPageState extends State<HomeView> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: _buildInputDataBody(context),
);
}
Widget _buildInputDataBody(BuildContext context) {
var userLocation = Provider.of<GeoLocation>(context);
userLocation.radiuscentermeters = 1000; //100 meters
userLocation.setPointCenter(dummyCenterLatitude, dummyCenterLongitude);
return Container(
color: Colors.white,
padding: EdgeInsets.all(12.0),
child: ListView(children: <Widget>[
Text(
'Lokasi',
textScaleFactor: 1.2,
style: TextStyle(
fontWeight: FontWeight.w700, color: Colors.blueAccent),
),
SizedBox(width: 15),
Text(
'Latitude \t\t\t\t: ${userLocation.userlocation.latitude} '
'\nLongitude \t: ${userLocation.userlocation.longitude}'
'\nIn Range? \t: ${userLocation.isInRange}',
textScaleFactor: 1,
style: TextStyle(color: Colors.blueAccent)),
]
))
;
}
}
Pelatihan Mobile Programming with Flutter hari keempat (13/8/2021) sebagai bagian dari penggunaan dana hibah PKKM tahun anggaran 2021 dengan mentor Faizal Rahman (https://pdsi.unisayogya.ac.id/unisa-yogyakarta-menerima-bantuan-pemerintah-pkkm-tahun-anggaran-2021/) [bst]
One reply on “Geo Location Flutter: Aku Peta, Aku Peta”
terimakasih bapak, ilmunya sangat bermanfaat