Add a GeoJSON Polygon in Flutter
This tutorial shows how to add a GeoJSON Polygon to your MapMetrics Flutter map — perfect for highlighting regions, zones, or areas.
Prerequisites
Before you begin, ensure you have:
- Completed the Flutter Setup Guide
- A MapMetrics API key and style URL from the MapMetrics Portal
Basic GeoJSON Polygon
Add a filled polygon from GeoJSON data:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class GeoJsonPolygonScreen extends StatefulWidget {
@override
_GeoJsonPolygonScreenState createState() => _GeoJsonPolygonScreenState();
}
class _GeoJsonPolygonScreenState extends State<GeoJsonPolygonScreen> {
MapController? mapController;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('GeoJSON Polygon')),
body: MapMetricsView(
options: MapOptions(
initCenter: Position(2.35, 48.8), // lng, lat
initZoom: 11.0,
initStyle:
'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
),
onMapCreated: (MapController controller) {
mapController = controller;
},
onStyleLoaded: (StyleController style) {
_addGeoJsonPolygon(style);
},
),
);
}
Future<void> _addGeoJsonPolygon(StyleController style) async {
// GeoJSON coordinates are already [lng, lat] — no swapping needed here.
final geoJson = {
'type': 'Feature',
'properties': {'name': 'Central Paris'},
'geometry': {
'type': 'Polygon',
'coordinates': [
[
[2.3200, 48.8400],
[2.3800, 48.8400],
[2.3800, 48.8700],
[2.3200, 48.8700],
[2.3200, 48.8400], // close the ring
]
],
},
};
// Add the GeoJSON source
await style.addSource(
GeoJsonSource(id: 'region-source', data: jsonEncode(geoJson)),
);
// Add a fill layer
await style.addLayer(
const FillStyleLayer(
id: 'region-fill',
sourceId: 'region-source',
paint: {'fill-color': '#3b82f6', 'fill-opacity': 0.3},
),
);
// Add an outline layer
await style.addLayer(
const LineStyleLayer(
id: 'region-outline',
sourceId: 'region-source',
paint: {'line-color': '#1d4ed8', 'line-width': 2.0},
),
);
}
}Multiple Polygons with FeatureCollection
Display several regions with different colors:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class MultiPolygonScreen extends StatefulWidget {
@override
_MultiPolygonScreenState createState() => _MultiPolygonScreenState();
}
class _MultiPolygonScreenState extends State<MultiPolygonScreen> {
MapController? mapController;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Multiple Polygons')),
body: MapMetricsView(
options: MapOptions(
initCenter: Position(8.0, 48.0), // lng, lat
initZoom: 4.0,
initStyle:
'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
),
onMapCreated: (MapController controller) {
mapController = controller;
},
onStyleLoaded: (StyleController style) {
_addMultiplePolygons(style);
},
),
);
}
Future<void> _addMultiplePolygons(StyleController style) async {
final featureCollection = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {'name': 'France', 'color': 'blue'},
'geometry': {
'type': 'Polygon',
'coordinates': [
[
[-1.75, 43.3],
[3.0, 43.3],
[7.7, 43.8],
[8.2, 48.9],
[2.5, 51.1],
[-4.8, 48.5],
[-1.75, 43.3],
]
],
},
},
{
'type': 'Feature',
'properties': {'name': 'Germany', 'color': 'red'},
'geometry': {
'type': 'Polygon',
'coordinates': [
[
[5.9, 47.3],
[15.0, 47.3],
[15.0, 55.0],
[5.9, 55.0],
[5.9, 47.3],
]
],
},
},
],
};
await style.addSource(
GeoJsonSource(id: 'countries', data: jsonEncode(featureCollection)),
);
// Fill layer with semi-transparent color
await style.addLayer(
const FillStyleLayer(
id: 'countries-fill',
sourceId: 'countries',
paint: {'fill-color': '#3b82f6', 'fill-opacity': 0.2},
),
);
// Outline layer
await style.addLayer(
const LineStyleLayer(
id: 'countries-outline',
sourceId: 'countries',
paint: {'line-color': '#1e40af', 'line-width': 2.0},
),
);
}
}Polygon with Hole
Create a polygon with a cutout hole inside:
Future<void> _addPolygonWithHole(StyleController style) async {
final geoJson = {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Polygon',
'coordinates': [
// Outer ring
[
[2.2800, 48.8200],
[2.4200, 48.8200],
[2.4200, 48.8900],
[2.2800, 48.8900],
[2.2800, 48.8200],
],
// Inner ring (hole)
[
[2.3300, 48.8450],
[2.3700, 48.8450],
[2.3700, 48.8650],
[2.3300, 48.8650],
[2.3300, 48.8450],
],
],
},
};
await style.addSource(
GeoJsonSource(id: 'polygon-hole', data: jsonEncode(geoJson)),
);
await style.addLayer(
const FillStyleLayer(
id: 'polygon-hole-fill',
sourceId: 'polygon-hole',
paint: {'fill-color': '#22c55e', 'fill-opacity': 0.4},
),
);
await style.addLayer(
const LineStyleLayer(
id: 'polygon-hole-outline',
sourceId: 'polygon-hole',
paint: {'line-color': '#15803d', 'line-width': 2.0},
),
);
}GeoJSON Polygon Properties
FillStyleLayer and LineStyleLayer take plain MapLibre style spec keys in their paint maps:
| Property | Layer | Type | Description |
|---|---|---|---|
fill-color | FillStyleLayer | String | Fill color as hex string |
fill-opacity | FillStyleLayer | double | Fill opacity from 0.0 to 1.0 |
line-color | LineStyleLayer | String | Outline color as hex string |
line-width | LineStyleLayer | double | Outline width in pixels |
Next Steps
- Add a GeoJSON Line — Draw lines from GeoJSON data
- Draw GeoJSON Points — Render point data on the map
- Show Polygon Info on Click — Display polygon data on tap
Tip: Always close polygon rings — the first and last coordinate must be identical. Use FeatureCollection to group multiple polygons into one source for better performance.