# Mapview Polygon

This example shows how to add Polygons in MapView

-   Add Polygon from a set of Latlng
-   Set Polygon visibility
-   Set Polygon color

| ![documentation image](https://static.nextbillion.io/docs-next/docs/maps/flutter/examples/mapview-polygon-2.webp) | ![documentation image](https://static.nextbillion.io/docs-next/docs/maps/flutter/examples/mapview-polygon-1.webp) |
| --- | --- |
| **Android snapshot** | **iOS snapshot** |



For all code examples, refer to [Flutter Maps SDK Code Examples](https://github.com/nextbillion-ai/nb-maps-flutter)

**PlaceFillPage** [view source](https://github.com/nextbillion-ai/nb-maps-flutter/blob/main/example/lib/place_fill.dart)

```dart
import 'dart:async';
import 'dart:typed_data';

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

import 'page.dart';

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

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

class PlaceFillBody extends StatefulWidget {
 const PlaceFillBody();

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

class PlaceFillBodyState extends State<PlaceFillBody> {
 PlaceFillBodyState();

 static final LatLng center = const LatLng(-33.86711, 151.1947171);
 final String _fillPatternImage = "assets/fill/cat_silhouette_pattern.png";

 final List<List<LatLng>> _defaultGeometry = [
   [
     LatLng(-33.719, 151.150),
     LatLng(-33.858, 151.150),
     LatLng(-33.866, 151.401),
     LatLng(-33.747, 151.328),
     LatLng(-33.719, 151.150),
   ],
   [
     LatLng(-33.762, 151.250),
     LatLng(-33.827, 151.250),
     LatLng(-33.833, 151.347),
     LatLng(-33.762, 151.250),
   ]
 ];

 NextbillionMapController? controller;
 int _fillCount = 0;
 Fill? _selectedFill;

 void _onMapCreated(NextbillionMapController controller) {
   this.controller = controller;
   controller.onFillTapped.add(_onFillTapped);
   this.controller!.onFeatureDrag.add(_onFeatureDrag);
 }

 void _onFeatureDrag(id,
     {required current,
     required delta,
     required origin,
     required point,
     required eventType}) {
   DragEventType type = eventType;
   switch (type) {
     case DragEventType.start:
       // TODO: Handle this case.
       break;
     case DragEventType.drag:
       // TODO: Handle this case.
       break;
     case DragEventType.end:
       // TODO: Handle this case.
       break;
   }
 }

 void _onStyleLoaded() {
   addImageFromAsset("assetImage", _fillPatternImage);
 }

 /// Adds an asset image to the currently displayed style
 Future<void> addImageFromAsset(String name, String assetName) async {
   final ByteData bytes = await rootBundle.load(assetName);
   final Uint8List list = bytes.buffer.asUint8List();
   return controller!.addImage(name, list);
 }

 @override
 void dispose() {
   controller?.onFillTapped.remove(_onFillTapped);
   super.dispose();
 }

 void _onFillTapped(Fill fill) {
   setState(() {
     _selectedFill = fill;
   });
 }

 void _updateSelectedFill(FillOptions changes) {
   controller!.updateFill(_selectedFill!, changes);
 }

 void _add() {
   controller!.addFill(
     FillOptions(
         geometry: _defaultGeometry,
         fillColor: "#FF0000",
         fillOutlineColor: "#FF0000"),
   );
   setState(() {
     _fillCount += 1;
   });
 }

 void _remove() {
   controller!.removeFill(_selectedFill!);
   setState(() {
     _selectedFill = null;
     _fillCount -= 1;
   });
 }

 void _changePosition() {
   List<List<LatLng>>? geometry = _selectedFill!.options.geometry;

   if (geometry == null) {
     geometry = _defaultGeometry;
   }

   _updateSelectedFill(FillOptions(
       geometry: geometry
           .map((list) => list
               .map(
                   // Move to right with 0.1 degree on longitude
                   (latLng) => LatLng(latLng.latitude, latLng.longitude + 0.1))
               .toList())
           .toList()));
 }

 void _changeDraggable() {
   bool? draggable = _selectedFill!.options.draggable;
   if (draggable == null) {
     // default value
     draggable = false;
   }
   _updateSelectedFill(
     FillOptions(draggable: !draggable),
   );
 }

 Future<void> _changeFillOpacity() async {
   double? current = _selectedFill!.options.fillOpacity;
   if (current == null) {
     // default value
     current = 1.0;
   }

   _updateSelectedFill(
     FillOptions(fillOpacity: current < 0.1 ? 1.0 : current * 0.75),
   );
 }

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

   _updateSelectedFill(
     FillOptions(fillColor: "#FFFF00"),
   );
 }

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

   _updateSelectedFill(
     FillOptions(fillOutlineColor: "#FFFF00"),
   );
 }

 Future<void> _changeFillPattern() async {
   String? current =
       _selectedFill!.options.fillPattern == null ? "assetImage" : null;
   _updateSelectedFill(
     FillOptions(fillPattern: current),
   );
 }

 @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,
             onStyleLoadedCallback: _onStyleLoaded,
             initialCameraPosition: const CameraPosition(
               target: LatLng(-33.852, 151.211),
               zoom: 7.0,
             ),
           ),
         ),
       ),
       Expanded(
         child: SingleChildScrollView(
           child: Row(
             mainAxisAlignment: MainAxisAlignment.spaceEvenly,
             children: <Widget>[
               Row(
                 children: <Widget>[
                   Column(
                     children: <Widget>[
                       TextButton(
                         child: const Text('add'),
                         onPressed: (_fillCount == 12) ? null : _add,
                       ),
                       TextButton(
                         child: const Text('remove'),
                         onPressed: (_selectedFill == null) ? null : _remove,
                       ),
                     ],
                   ),
                   Column(
                     children: <Widget>[
                       TextButton(
                         child: const Text('change fill-opacity'),
                         onPressed: (_selectedFill == null)
                             ? null
                             : _changeFillOpacity,
                       ),
                       TextButton(
                         child: const Text('change fill-color'),
                         onPressed:
                             (_selectedFill == null) ? null : _changeFillColor,
                       ),
                       TextButton(
                         child: const Text('change fill-outline-color'),
                         onPressed: (_selectedFill == null)
                             ? null
                             : _changeFillOutlineColor,
                       ),
                       TextButton(
                         child: const Text('change fill-pattern'),
                         onPressed: (_selectedFill == null)
                             ? null
                             : _changeFillPattern,
                       ),
                       TextButton(
                         child: const Text('change position'),
                         onPressed:
                             (_selectedFill == null) ? null : _changePosition,
                       ),
                       TextButton(
                         child: const Text('toggle draggable'),
                         onPressed:
                             (_selectedFill == null) ? null : _changeDraggable,
                       ),
                     ],
                   ),
                 ],
               )
             ],
           ),
         ),
       ),
     ],
   );
 }
}
```

## Code summary

The above code snippet displays a map with various functionalities related to polygons. The user can interact with the map, add and remove fills, change fill properties (such as color, opacity, outline color, and pattern), move fills, and toggle the fill's draggable state. It utilizes the **nb_maps_flutter** package for map-related functionalities.

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

**PlaceFillBody Class**: is a StatefulWidget class representing the main body of the **PlaceFillPage**. It manages the state of the **PlaceFillPage** and contains the map and various buttons for interacting with the fills.

**PlaceFillBodyState Class**: This is the state class for the **PlaceFillBody** widget. It handles the interactions with the map, such as adding fills, updating fill properties, and removing fills. Some key methods include:

-   **_onMapCreated**: A callback method called when the map is created. It sets the map controller and adds listeners for fill taps and feature drags (used for dragging the fill on the map).
-   **_onFeatureDrag**: A method called when a feature (fill) on the map is dragged. It currently handles the start, drag, and end events for dragging.
-   **_onStyleLoaded**: A callback method called when the map style is loaded. It adds an image from an asset to the style.

**build Method**: The build method returns a Column widget containing a map **(NBMap)** and a set of buttons for interacting with the fills. The buttons include 'add', 'remove', 'change fill-opacity', 'change fill-color', 'change fill-outline-color', 'change fill-pattern', 'change position', and 'toggle draggable'. The map displays fills, and when a fill is tapped, it becomes selected, and its properties can be modified using the buttons.
