Add a Polygon in Flutter
This tutorial shows how to draw filled polygons on your MapMetrics Flutter map. Polygons are useful for highlighting areas, zones, or boundaries.
Prerequisites
Before you begin, ensure you have:
- Completed the Flutter Setup Guide
- A MapMetrics API key and style URL from the MapMetrics Portal
Basic Polygon
Draw a simple polygon by providing a list of LatLng points. The shape will automatically close by connecting the last point to the first:
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class PolygonExampleScreen extends StatefulWidget {
@override
_PolygonExampleScreenState createState() => _PolygonExampleScreenState();
}
class _PolygonExampleScreenState extends State<PolygonExampleScreen> {
MapMetricsController? mapController;
final Set<Polygon> polygons = {
Polygon(
polygonId: PolygonId('manhattan'),
points: [
LatLng(40.800, -73.958),
LatLng(40.800, -74.020),
LatLng(40.700, -74.020),
LatLng(40.700, -73.970),
],
strokeWidth: 2,
strokeColor: Colors.blue,
fillColor: Colors.blue.withOpacity(0.2),
),
};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Polygon Example')),
body: MapMetrics(
styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
onMapCreated: (MapMetricsController controller) {
mapController = controller;
},
initialCameraPosition: CameraPosition(
target: LatLng(40.750, -73.990),
zoom: 12.0,
),
polygons: polygons,
),
);
}
}Multiple Colored Zones
Show different areas with distinct colors:
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class ColoredZonesScreen extends StatefulWidget {
@override
_ColoredZonesScreenState createState() => _ColoredZonesScreenState();
}
class _ColoredZonesScreenState extends State<ColoredZonesScreen> {
MapMetricsController? mapController;
final Set<Polygon> zones = {
// Zone A - Green (safe zone)
Polygon(
polygonId: PolygonId('zone_a'),
points: [
LatLng(48.870, 2.330),
LatLng(48.870, 2.350),
LatLng(48.860, 2.350),
LatLng(48.860, 2.330),
],
strokeWidth: 2,
strokeColor: Colors.green,
fillColor: Colors.green.withOpacity(0.25),
),
// Zone B - Orange (caution zone)
Polygon(
polygonId: PolygonId('zone_b'),
points: [
LatLng(48.860, 2.330),
LatLng(48.860, 2.350),
LatLng(48.850, 2.350),
LatLng(48.850, 2.330),
],
strokeWidth: 2,
strokeColor: Colors.orange,
fillColor: Colors.orange.withOpacity(0.25),
),
// Zone C - Red (restricted zone)
Polygon(
polygonId: PolygonId('zone_c'),
points: [
LatLng(48.850, 2.330),
LatLng(48.850, 2.350),
LatLng(48.840, 2.350),
LatLng(48.840, 2.330),
],
strokeWidth: 2,
strokeColor: Colors.red,
fillColor: Colors.red.withOpacity(0.25),
),
};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Colored Zones')),
body: Stack(
children: [
MapMetrics(
styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
onMapCreated: (controller) => mapController = controller,
initialCameraPosition: CameraPosition(
target: LatLng(48.855, 2.340),
zoom: 14.0,
),
polygons: zones,
),
// Legend
Positioned(
top: 16,
right: 16,
child: Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_legendItem(Colors.green, 'Safe Zone'),
SizedBox(height: 6),
_legendItem(Colors.orange, 'Caution Zone'),
SizedBox(height: 6),
_legendItem(Colors.red, 'Restricted Zone'),
],
),
),
),
],
),
);
}
Widget _legendItem(Color color, String label) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 16,
height: 16,
decoration: BoxDecoration(
color: color.withOpacity(0.3),
border: Border.all(color: color, width: 2),
borderRadius: BorderRadius.circular(3),
),
),
SizedBox(width: 8),
Text(label, style: TextStyle(fontSize: 13)),
],
);
}
}Tappable Polygons
Make polygons respond to taps:
dart
Polygon(
polygonId: PolygonId('tappable_area'),
points: [
LatLng(48.870, 2.330),
LatLng(48.870, 2.360),
LatLng(48.850, 2.360),
LatLng(48.850, 2.330),
],
strokeWidth: 2,
strokeColor: Colors.purple,
fillColor: Colors.purple.withOpacity(0.2),
consumeTapEvents: true,
onTap: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Area Selected'),
content: Text('You tapped on the highlighted area.'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('OK'),
),
],
),
);
},
)Polygon Properties
| Property | Type | Description |
|---|---|---|
polygonId | PolygonId | Unique identifier for the polygon |
points | List<LatLng> | Vertices of the polygon (auto-closed) |
strokeWidth | int | Border width in pixels |
strokeColor | Color | Border color |
fillColor | Color | Fill color (use withOpacity for transparency) |
visible | bool | Whether the polygon is visible |
zIndex | int | Drawing order relative to other overlays |
consumeTapEvents | bool | If true, tap events are consumed by the polygon |
onTap | VoidCallback | Called when the polygon is tapped |
Next Steps
- Draw a Circle — Draw circular areas on the map
- Add a Polyline — Draw lines and routes
- Markers and Annotations — Add markers to your polygons
Tip: Use withOpacity on your fill colors to keep the polygon semi-transparent so the map underneath remains visible.