Mapview Circle Annotation

Introduction

This example shows how to add Circle annotations in MapView

  1. Add Circle annotations from a set of Latlng
  2. Set Circle annotation opacity, color, radius
  3. Set Circle annotation stroke width, stroke color
Android snapshot iOS snapshot

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

PlaceCirclePage view source

1import 'dart:async';
2import 'dart:math';
3
4import 'package:flutter/material.dart';
5import 'package:nb_maps_flutter/nb_maps_flutter.dart';
6
7import 'page.dart';
8
9class PlaceCirclePage extends ExamplePage {
10 PlaceCirclePage() : super(const Icon(Icons.check_circle), 'Place circle');
11
12 
13 Widget build(BuildContext context) {
14   return const PlaceCircleBody();
15 }
16}
17
18class PlaceCircleBody extends StatefulWidget {
19 const PlaceCircleBody();
20
21 
22 State<StatefulWidget> createState() => PlaceCircleBodyState();
23}
24
25class PlaceCircleBodyState extends State<PlaceCircleBody> {
26 PlaceCircleBodyState();
27
28 static final LatLng center = const LatLng(-33.86711, 151.1947171);
29
30 NextbillionMapController? controller;
31 int _circleCount = 0;
32 Circle? _selectedCircle;
33
34 void _onMapCreated(NextbillionMapController controller) {
35   this.controller = controller;
36   controller.onCircleTapped.add(_onCircleTapped);
37 }
38
39 
40 void dispose() {
41   controller?.onCircleTapped.remove(_onCircleTapped);
42   super.dispose();
43 }
44
45 void _onCircleTapped(Circle circle) {
46   if (_selectedCircle != null) {
47     _updateSelectedCircle(
48       const CircleOptions(circleRadius: 60),
49     );
50   }
51   setState(() {
52     _selectedCircle = circle;
53   });
54   _updateSelectedCircle(
55     CircleOptions(
56       circleRadius: 30,
57     ),
58   );
59 }
60
61 void _updateSelectedCircle(CircleOptions changes) {
62   controller!.updateCircle(_selectedCircle!, changes);
63 }
64
65 void _add() {
66   controller!.addCircle(
67     CircleOptions(
68         geometry: LatLng(
69           center.latitude + sin(_circleCount * pi / 6.0) / 20.0,
70           center.longitude + cos(_circleCount * pi / 6.0) / 20.0,
71         ),
72         circleColor: "#FF0000"),
73   );
74   setState(() {
75     _circleCount += 1;
76   });
77 }
78
79 void _remove() {
80   controller!.removeCircle(_selectedCircle!);
81   setState(() {
82     _selectedCircle = null;
83     _circleCount -= 1;
84   });
85 }
86
87 void _changePosition() {
88   final LatLng current = _selectedCircle!.options.geometry!;
89   final Offset offset = Offset(
90     center.latitude - current.latitude,
91     center.longitude - current.longitude,
92   );
93   _updateSelectedCircle(
94     CircleOptions(
95       geometry: LatLng(
96         center.latitude + offset.dy,
97         center.longitude + offset.dx,
98       ),
99     ),
100   );
101 }
102
103 void _changeDraggable() {
104   bool? draggable = _selectedCircle!.options.draggable;
105   if (draggable == null) {
106     // default value
107     draggable = false;
108   }
109   _updateSelectedCircle(
110     CircleOptions(
111       draggable: !draggable,
112     ),
113   );
114 }
115
116 void _getLatLng() async {
117   LatLng latLng = await controller!.getCircleLatLng(_selectedCircle!);
118   ScaffoldMessenger.of(context).showSnackBar(
119     SnackBar(
120       content: Text(latLng.toString()),
121     ),
122   );
123 }
124
125 void _changeCircleStrokeOpacity() {
126   double? current = _selectedCircle!.options.circleStrokeOpacity;
127   if (current == null) {
128     // default value
129     current = 1.0;
130   }
131
132   _updateSelectedCircle(
133     CircleOptions(circleStrokeOpacity: current < 0.1 ? 1.0 : current * 0.75),
134   );
135 }
136
137 void _changeCircleStrokeWidth() {
138   double? current = _selectedCircle!.options.circleStrokeWidth;
139   if (current == null) {
140     // default value
141     current = 0;
142   }
143   _updateSelectedCircle(
144       CircleOptions(circleStrokeWidth: current == 0 ? 5.0 : 0));
145 }
146
147 Future<void> _changeCircleStrokeColor() async {
148   String? current = _selectedCircle!.options.circleStrokeColor;
149   if (current == null) {
150     // default value
151     current = "#FFFFFF";
152   }
153
154   _updateSelectedCircle(
155     CircleOptions(
156         circleStrokeColor: current == "#FFFFFF" ? "#FF0000" : "#FFFFFF"),
157   );
158 }
159
160 Future<void> _changeCircleOpacity() async {
161   double? current = _selectedCircle!.options.circleOpacity;
162   if (current == null) {
163     // default value
164     current = 1.0;
165   }
166
167   _updateSelectedCircle(
168     CircleOptions(circleOpacity: current < 0.1 ? 1.0 : current * 0.75),
169   );
170 }
171
172 Future<void> _changeCircleRadius() async {
173   double? current = _selectedCircle!.options.circleRadius;
174   if (current == null) {
175     // default value
176     current = 0;
177   }
178   _updateSelectedCircle(
179     CircleOptions(circleRadius: current == 120.0 ? 30.0 : current + 30.0),
180   );
181 }
182
183 Future<void> _changeCircleColor() async {
184   String? current = _selectedCircle!.options.circleColor;
185   if (current == null) {
186     // default value
187     current = "#FF0000";
188   }
189
190   _updateSelectedCircle(
191     CircleOptions(circleColor: "#FFFF00"),
192   );
193 }
194
195 Future<void> _changeCircleBlur() async {
196   double? current = _selectedCircle!.options.circleBlur;
197   if (current == null) {
198     // default value
199     current = 0;
200   }
201   _updateSelectedCircle(
202     CircleOptions(circleBlur: current == 0.75 ? 0 : 0.75),
203   );
204 }
205
206 
207 Widget build(BuildContext context) {
208   return Column(
209     mainAxisAlignment: MainAxisAlignment.spaceEvenly,
210     crossAxisAlignment: CrossAxisAlignment.stretch,
211     children: <Widget>[
212       Center(
213         child: SizedBox(
214           width: 300.0,
215           height: 200.0,
216           child: NBMap(
217             onMapCreated: _onMapCreated,
218             initialCameraPosition: const CameraPosition(
219               target: LatLng(-33.852, 151.211),
220               zoom: 11.0,
221             ),
222           ),
223         ),
224       ),
225       Expanded(
226         child: SingleChildScrollView(
227           child: Row(
228             mainAxisAlignment: MainAxisAlignment.spaceEvenly,
229             children: <Widget>[
230               Row(
231                 children: <Widget>[
232                   Column(
233                     children: <Widget>[
234                       TextButton(
235                         child: const Text('add'),
236                         onPressed: (_circleCount == 12) ? null : _add,
237                       ),
238                       TextButton(
239                         child: const Text('remove'),
240                         onPressed: (_selectedCircle == null) ? null : _remove,
241                       ),
242                     ],
243                   ),
244                   Column(
245                     children: <Widget>[
246                       TextButton(
247                         child: const Text('change circle-opacity'),
248                         onPressed: (_selectedCircle == null)
249                             ? null
250                             : _changeCircleOpacity,
251                       ),
252                       TextButton(
253                         child: const Text('change circle-radius'),
254                         onPressed: (_selectedCircle == null)
255                             ? null
256                             : _changeCircleRadius,
257                       ),
258                       TextButton(
259                         child: const Text('change circle-color'),
260                         onPressed: (_selectedCircle == null)
261                             ? null
262                             : _changeCircleColor,
263                       ),
264                       TextButton(
265                         child: const Text('change circle-blur'),
266                         onPressed: (_selectedCircle == null)
267                             ? null
268                             : _changeCircleBlur,
269                       ),
270                       TextButton(
271                         child: const Text('change circle-stroke-width'),
272                         onPressed: (_selectedCircle == null)
273                             ? null
274                             : _changeCircleStrokeWidth,
275                       ),
276                       TextButton(
277                         child: const Text('change circle-stroke-color'),
278                         onPressed: (_selectedCircle == null)
279                             ? null
280                             : _changeCircleStrokeColor,
281                       ),
282                       TextButton(
283                         child: const Text('change circle-stroke-opacity'),
284                         onPressed: (_selectedCircle == null)
285                             ? null
286                             : _changeCircleStrokeOpacity,
287                       ),
288                       TextButton(
289                         child: const Text('change position'),
290                         onPressed: (_selectedCircle == null)
291                             ? null
292                             : _changePosition,
293                       ),
294                       TextButton(
295                         child: const Text('toggle draggable'),
296                         onPressed: (_selectedCircle == null)
297                             ? null
298                             : _changeDraggable,
299                       ),
300                       TextButton(
301                         child: const Text('get current LatLng'),
302                         onPressed:
303                             (_selectedCircle == null) ? null : _getLatLng,
304                       ),
305                     ],
306                   ),
307                 ],
308               )
309             ],
310           ),
311         ),
312       ),
313     ],
314   );
315 }
316}

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:

  1. _onMapCreated: A callback method called when the map is created. It sets the map controller and adds a listener for circle taps.
  2. _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.
  3. _updateSelectedCircle: A method to update the properties of the selected circle.
  4. _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.
  5. _remove: A method to remove the selected circle from the map.
  6. _changePosition: A method to change the position of the selected circle on the map.
  7. _changeDraggable: A method to toggle the draggable property of the selected circle.
  8. _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.

DIDN'T FIND WHAT YOU LOOKING FOR?