• Optimization
  • Navigation
  • Tracking
  • Maps
  • Places

Mapview Circle Annotation

Introduction

This example shows how to add Circle annotations in MapView

  • Add Circle annotations from a set of Latlng
  • Set Circle annotation opacity, color, radius
  • Set Circle annotation stroke width, stroke color
Android snapshotiOS snapshot

For all code examples, refer to Flutter Maps SDK Code Examples

PlaceCirclePage view source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:nb_maps_flutter/nb_maps_flutter.dart';

import 'page.dart';

class PlaceCirclePage extends ExamplePage {
 PlaceCirclePage() : super(const Icon(Icons.check_circle), 'Place circle');

 @override
 Widget build(BuildContext context) {
   return const PlaceCircleBody();
 }
}

class PlaceCircleBody extends StatefulWidget {
 const PlaceCircleBody();

 @override
 State<StatefulWidget> createState() => PlaceCircleBodyState();
}

class PlaceCircleBodyState extends State<PlaceCircleBody> {
 PlaceCircleBodyState();

 static final LatLng center = const LatLng(-33.86711, 151.1947171);

 NextbillionMapController? controller;
 int _circleCount = 0;
 Circle? _selectedCircle;

 void _onMapCreated(NextbillionMapController controller) {
   this.controller = controller;
   controller.onCircleTapped.add(_onCircleTapped);
 }

 @override
 void dispose() {
   controller?.onCircleTapped.remove(_onCircleTapped);
   super.dispose();
 }

 void _onCircleTapped(Circle circle) {
   if (_selectedCircle != null) {
     _updateSelectedCircle(
       const CircleOptions(circleRadius: 60),
     );
   }
   setState(() {
     _selectedCircle = circle;
   });
   _updateSelectedCircle(
     CircleOptions(
       circleRadius: 30,
     ),
   );
 }

 void _updateSelectedCircle(CircleOptions changes) {
   controller!.updateCircle(_selectedCircle!, changes);
 }

 void _add() {
   controller!.addCircle(
     CircleOptions(
         geometry: LatLng(
           center.latitude + sin(_circleCount * pi / 6.0) / 20.0,
           center.longitude + cos(_circleCount * pi / 6.0) / 20.0,
         ),
         circleColor: "#FF0000"),
   );
   setState(() {
     _circleCount += 1;
   });
 }

 void _remove() {
   controller!.removeCircle(_selectedCircle!);
   setState(() {
     _selectedCircle = null;
     _circleCount -= 1;
   });
 }

 void _changePosition() {
   final LatLng current = _selectedCircle!.options.geometry!;
   final Offset offset = Offset(
     center.latitude - current.latitude,
     center.longitude - current.longitude,
   );
   _updateSelectedCircle(
     CircleOptions(
       geometry: LatLng(
         center.latitude + offset.dy,
         center.longitude + offset.dx,
       ),
     ),
   );
 }

 void _changeDraggable() {
   bool? draggable = _selectedCircle!.options.draggable;
   if (draggable == null) {
     // default value
     draggable = false;
   }
   _updateSelectedCircle(
     CircleOptions(
       draggable: !draggable,
     ),
   );
 }

 void _getLatLng() async {
   LatLng latLng = await controller!.getCircleLatLng(_selectedCircle!);
   ScaffoldMessenger.of(context).showSnackBar(
     SnackBar(
       content: Text(latLng.toString()),
     ),
   );
 }

 void _changeCircleStrokeOpacity() {
   double? current = _selectedCircle!.options.circleStrokeOpacity;
   if (current == null) {
     // default value
     current = 1.0;
   }

   _updateSelectedCircle(
     CircleOptions(circleStrokeOpacity: current < 0.1 ? 1.0 : current * 0.75),
   );
 }

 void _changeCircleStrokeWidth() {
   double? current = _selectedCircle!.options.circleStrokeWidth;
   if (current == null) {
     // default value
     current = 0;
   }
   _updateSelectedCircle(
       CircleOptions(circleStrokeWidth: current == 0 ? 5.0 : 0));
 }

 Future<void> _changeCircleStrokeColor() async {
   String? current = _selectedCircle!.options.circleStrokeColor;
   if (current == null) {
     // default value
     current = "#FFFFFF";
   }

   _updateSelectedCircle(
     CircleOptions(
         circleStrokeColor: current == "#FFFFFF" ? "#FF0000" : "#FFFFFF"),
   );
 }

 Future<void> _changeCircleOpacity() async {
   double? current = _selectedCircle!.options.circleOpacity;
   if (current == null) {
     // default value
     current = 1.0;
   }

   _updateSelectedCircle(
     CircleOptions(circleOpacity: current < 0.1 ? 1.0 : current * 0.75),
   );
 }

 Future<void> _changeCircleRadius() async {
   double? current = _selectedCircle!.options.circleRadius;
   if (current == null) {
     // default value
     current = 0;
   }
   _updateSelectedCircle(
     CircleOptions(circleRadius: current == 120.0 ? 30.0 : current + 30.0),
   );
 }

 Future<void> _changeCircleColor() async {
   String? current = _selectedCircle!.options.circleColor;
   if (current == null) {
     // default value
     current = "#FF0000";
   }

   _updateSelectedCircle(
     CircleOptions(circleColor: "#FFFF00"),
   );
 }

 Future<void> _changeCircleBlur() async {
   double? current = _selectedCircle!.options.circleBlur;
   if (current == null) {
     // default value
     current = 0;
   }
   _updateSelectedCircle(
     CircleOptions(circleBlur: current == 0.75 ? 0 : 0.75),
   );
 }

 @override
 Widget build(BuildContext context) {
   return Column(
     mainAxisAlignment: MainAxisAlignment.spaceEvenly,
     crossAxisAlignment: CrossAxisAlignment.stretch,
     children: <Widget>[
       Center(
         child: SizedBox(
           width: 300.0,
           height: 200.0,
           child: NBMap(
             onMapCreated: _onMapCreated,
             initialCameraPosition: const CameraPosition(
               target: LatLng(-33.852, 151.211),
               zoom: 11.0,
             ),
           ),
         ),
       ),
       Expanded(
         child: SingleChildScrollView(
           child: Row(
             mainAxisAlignment: MainAxisAlignment.spaceEvenly,
             children: <Widget>[
               Row(
                 children: <Widget>[
                   Column(
                     children: <Widget>[
                       TextButton(
                         child: const Text('add'),
                         onPressed: (_circleCount == 12) ? null : _add,
                       ),
                       TextButton(
                         child: const Text('remove'),
                         onPressed: (_selectedCircle == null) ? null : _remove,
                       ),
                     ],
                   ),
                   Column(
                     children: <Widget>[
                       TextButton(
                         child: const Text('change circle-opacity'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changeCircleOpacity,
                       ),
                       TextButton(
                         child: const Text('change circle-radius'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changeCircleRadius,
                       ),
                       TextButton(
                         child: const Text('change circle-color'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changeCircleColor,
                       ),
                       TextButton(
                         child: const Text('change circle-blur'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changeCircleBlur,
                       ),
                       TextButton(
                         child: const Text('change circle-stroke-width'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changeCircleStrokeWidth,
                       ),
                       TextButton(
                         child: const Text('change circle-stroke-color'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changeCircleStrokeColor,
                       ),
                       TextButton(
                         child: const Text('change circle-stroke-opacity'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changeCircleStrokeOpacity,
                       ),
                       TextButton(
                         child: const Text('change position'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changePosition,
                       ),
                       TextButton(
                         child: const Text('toggle draggable'),
                         onPressed: (_selectedCircle == null)
                             ? null
                             : _changeDraggable,
                       ),
                       TextButton(
                         child: const Text('get current LatLng'),
                         onPressed:
                             (_selectedCircle == null) ? null : _getLatLng,
                       ),
                     ],
                   ),
                 ],
               )
             ],
           ),
         ),
       ),
     ],
   );
 }
}

Code summary

The above code snippet displays nbMap with various functionalities related to circles. The user can interact with the map, add and remove circles, change circle properties (such as opacity, radius, color, blur, and stroke), move circles, and toggle the circle's draggable state. It utilizes the nb_maps_flutter package for map-related functionalities.

PlaceCirclePage Class: extends the ExamplePage class and represents a page in the app that demonstrates circle-related functionalities. The page is associated with an icon (check_circle icon) and a title ('Place circle'). The build method returns a PlaceCircleBody widget.

PlaceCircleBody Class: is a StatefulWidget class representing the main body of the PlaceCirclePage. It manages the state of the PlaceCirclePage and contains the map and various buttons for interacting with circles.

PlaceCircleBodyState Class: is the state class for the PlaceCircleBody widget. It handles the interactions with the map, such as adding circles, updating circle properties, and removing circles. Some key methods include:

  • _onMapCreated: A callback method called when the map is created. It sets the map controller and adds a listener for circle taps.
  • _onCircleTapped: A method called when a circle on the map is tapped. It changes the properties of the selected circle, making it larger and updates its appearance. The previously selected circle, if any, is reverted to its original size and appearance.
  • _updateSelectedCircle: A method to update the properties of the selected circle.
  • _add: A method to add a new circle to the map. It calculates the position of the circle based on the current _circleCount and the center of the map.
  • _remove: A method to remove the selected circle from the map.
  • _changePosition: A method to change the position of the selected circle on the map.
  • _changeDraggable: A method to toggle the draggable property of the selected circle.
  • _getLatLng: A method to retrieve the latitude and longitude of the selected circle and display it using a SnackBar. Methods to change various circle properties like opacity, radius, color, blur, stroke width, and stroke color.

build Method: The build method returns a Column widget containing a map (NBMap) and a set of buttons for interacting with the circles. The buttons include 'add', 'remove', 'change circle-opacity', 'change circle-radius', 'change circle-color', 'change circle-blur', 'change circle-stroke-width', 'change circle-stroke-color', 'change circle-stroke-opacity', 'change position', 'toggle draggable', and 'get current LatLng'. The map displays circles, and when a circle is tapped, it becomes selected, and its properties can be modified using the buttons.