Last active
September 23, 2023 18:01
-
-
Save hungtrn75/abe6fdff7c4f8c34859ff43c296c39f8 to your computer and use it in GitHub Desktop.
@mapbox/mapbox-gl-draw in Flutter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math'; | |
import 'package:collect_data/configs/constants/app_url.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:mapbox_gl/mapbox_gl.dart'; | |
class Pair<T1, T2> { | |
final T1 first; | |
final T2 second; | |
Pair(this.first, this.second); | |
} | |
enum Annotation { fill, circle, middleCircle } | |
class MapboxGLDrawPage extends StatefulWidget { | |
const MapboxGLDrawPage({Key? key}) : super(key: key); | |
@override | |
State<MapboxGLDrawPage> createState() => _MapboxGLDrawPageState(); | |
} | |
class _MapboxGLDrawPageState extends State<MapboxGLDrawPage> { | |
static const COLOR = "#ED7014"; | |
late MapboxMapController _mapController; | |
List<LatLng> markers = []; | |
List<Circle> _circles = []; | |
List<Circle> _middleCircles = []; | |
Fill? _fill; | |
int? _active; | |
void _onMapCreated(MapboxMapController controller) { | |
_mapController = controller; | |
_mapController.onFeatureDrag.add(_onFeatureDrag); | |
_mapController.onCircleTapped.add(_onCircleTapped); | |
} | |
@override | |
void dispose() { | |
_mapController.onFeatureDrag.remove(_onFeatureDrag); | |
_mapController.onCircleTapped.remove(_onCircleTapped); | |
super.dispose(); | |
} | |
Pair<Annotation, Circle?> isPrimaryCircle(dynamic id) { | |
final temp1 = _circles.where((element) => element.id == id); | |
if (temp1.isNotEmpty) { | |
return Pair(Annotation.circle, temp1.first); | |
} | |
final temp2 = _middleCircles.where((element) => element.id == id); | |
if (temp2.isNotEmpty) { | |
return Pair(Annotation.middleCircle, temp2.first); | |
} | |
return Pair(Annotation.fill, null); | |
} | |
void _onCircleTapped(Circle circle) { | |
final result = isPrimaryCircle(circle.id); | |
if (result.first == Annotation.circle) { | |
_active = _circles.indexOf(circle); | |
} else if (result.first == Annotation.middleCircle) { | |
final activeIndex = _middleCircles.indexOf(result.second!); | |
markers.insert(activeIndex + 1, result.second!.options.geometry!); | |
_active = activeIndex + 1; | |
} | |
_inject(); | |
} | |
void _onFeatureDrag(id, | |
{required current, | |
required delta, | |
required origin, | |
required point, | |
required eventType}) { | |
DragEventType type = eventType; | |
final result = isPrimaryCircle(id); | |
switch (type) { | |
case DragEventType.start: | |
if (result.first == Annotation.middleCircle) { | |
_mapController.updateCircle( | |
result.second!, | |
CircleOptions( | |
circleRadius: 8, | |
circleStrokeWidth: 3, | |
circleColor: COLOR, | |
circleStrokeColor: "#FFFFFF", | |
geometry: current, | |
), | |
); | |
} | |
break; | |
case DragEventType.drag: | |
break; | |
case DragEventType.end: | |
if (_fill?.id == id) { | |
markers = _fill?.options.geometry?.first ?? []; | |
} else if (result.first == Annotation.circle) { | |
markers = _circles.map((e) => e.options.geometry!).toList(); | |
} else { | |
final activeIndex = _middleCircles.indexOf(result.second!); | |
markers.insert(activeIndex + 1, result.second!.options.geometry!); | |
} | |
_inject(); | |
break; | |
} | |
} | |
void _onStyleLoadedCallback() {} | |
void _onMapClickCallback(Point<double> point, LatLng coordinates) { | |
debugPrint('_onMapClickCallback'); | |
markers.add(coordinates); | |
_inject(); | |
} | |
void _onDelete() { | |
if (_active != null) { | |
markers.removeAt(_active!); | |
_active = null; | |
} else { | |
markers = []; | |
} | |
_inject(); | |
} | |
void _inject() async { | |
await _mapController.clearCircles(); | |
await _mapController.clearFills(); | |
await _mapController.clearLines(); | |
if (markers.length > 2) { | |
_middleCircles = []; | |
for (var i = 0; i < markers.length; i++) { | |
final current = markers[i]; | |
final next = i + 1 < markers.length ? markers[i + 1] : markers.first; | |
final center = LatLng((current.latitude + next.latitude) / 2, | |
(current.longitude + next.longitude) / 2); | |
final temp = await _mapController.addCircle( | |
CircleOptions( | |
circleRadius: 5, | |
circleColor: COLOR, | |
geometry: center, | |
draggable: true), | |
); | |
_middleCircles.add(temp); | |
} | |
_fill = null; | |
_fill = await _mapController.addFill( | |
FillOptions( | |
fillColor: COLOR, | |
fillOpacity: 0.2, | |
geometry: [markers], | |
draggable: true, | |
), | |
); | |
} | |
if (markers.length > 1) { | |
await _mapController.addLine(LineOptions( | |
geometry: markers.length >2 ? [...markers, markers.first] : markers, | |
lineWidth: 2, | |
lineColor: COLOR, | |
lineOpacity: 0.4, | |
)); | |
} | |
_circles = []; | |
for (var i = 0; i < markers.length; i++) { | |
final marker = markers[i]; | |
final isActive = _active == i; | |
final temp = await _mapController.addCircle(CircleOptions( | |
circleRadius: isActive ? 8 : 6, | |
circleStrokeWidth: 3, | |
circleColor: COLOR, | |
circleStrokeColor: "#FFFFFF", | |
geometry: marker, | |
draggable: true, | |
)); | |
_circles.add(temp); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: MapboxMap( | |
accessToken: AppUrl.MAP_ACCESS_TOKEN, | |
trackCameraPosition: true, | |
onMapCreated: _onMapCreated, | |
onMapClick: _onMapClickCallback, | |
onStyleLoadedCallback: _onStyleLoadedCallback, | |
initialCameraPosition: const CameraPosition( | |
target: LatLng(20.9756361, 105.7893619), zoom: 16), | |
annotationOrder: const [ | |
AnnotationType.fill, | |
AnnotationType.line, | |
AnnotationType.symbol, | |
AnnotationType.circle, | |
], | |
annotationConsumeTapEvents: const [ | |
AnnotationType.fill, | |
AnnotationType.line, | |
AnnotationType.symbol, | |
AnnotationType.circle, | |
], | |
), | |
floatingActionButton: Column( | |
children: [ | |
FloatingActionButton( | |
onPressed: _onDelete, | |
child: const Icon(Icons.delete_outline), | |
), | |
], | |
mainAxisSize: MainAxisSize.min, | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment