Draw a Circle in Flutter
This tutorial shows how to draw circles on your MapMetrics Flutter map. Circles are useful for showing a radius around a point — like a search area, delivery zone, or coverage range.
Prerequisites
Before you begin, ensure you have:
- Completed the Flutter Setup Guide
- A MapMetrics API key and style URL from the MapMetrics Portal
Basic Circle
Draw a circle by specifying a center point and a radius in meters:
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class CircleExampleScreen extends StatefulWidget {
@override
_CircleExampleScreenState createState() => _CircleExampleScreenState();
}
class _CircleExampleScreenState extends State<CircleExampleScreen> {
MapMetricsController? mapController;
final Set<Circle> circles = {
Circle(
circleId: CircleId('search_radius'),
center: LatLng(48.8566, 2.3522),
radius: 2000, // 2 km radius
strokeWidth: 2,
strokeColor: Colors.blue,
fillColor: Colors.blue.withOpacity(0.15),
),
};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Circle 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(48.8566, 2.3522),
zoom: 13.0,
),
circles: circles,
),
);
}
}Multiple Circles with Different Radii
Show concentric circles or multiple zones:
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class MultipleCirclesScreen extends StatefulWidget {
@override
_MultipleCirclesScreenState createState() => _MultipleCirclesScreenState();
}
class _MultipleCirclesScreenState extends State<MultipleCirclesScreen> {
MapMetricsController? mapController;
final LatLng center = LatLng(40.7128, -74.0060);
Set<Circle> get circles => {
// Inner zone - 1 km
Circle(
circleId: CircleId('inner'),
center: center,
radius: 1000,
strokeWidth: 2,
strokeColor: Colors.green,
fillColor: Colors.green.withOpacity(0.2),
),
// Middle zone - 3 km
Circle(
circleId: CircleId('middle'),
center: center,
radius: 3000,
strokeWidth: 2,
strokeColor: Colors.orange,
fillColor: Colors.orange.withOpacity(0.1),
),
// Outer zone - 5 km
Circle(
circleId: CircleId('outer'),
center: center,
radius: 5000,
strokeWidth: 2,
strokeColor: Colors.red,
fillColor: Colors.red.withOpacity(0.05),
),
};
// Center marker
Set<Marker> get markers => {
Marker(
markerId: MarkerId('center'),
position: center,
infoWindow: InfoWindow(
title: 'Center Point',
snippet: '1 km / 3 km / 5 km zones',
),
),
};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Coverage Zones')),
body: MapMetrics(
styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
onMapCreated: (controller) => mapController = controller,
initialCameraPosition: CameraPosition(
target: center,
zoom: 12.0,
),
circles: circles,
markers: markers,
),
);
}
}Dynamic Circle: Tap to Place
Let users tap the map to place a circle at any location:
dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class DynamicCircleScreen extends StatefulWidget {
@override
_DynamicCircleScreenState createState() => _DynamicCircleScreenState();
}
class _DynamicCircleScreenState extends State<DynamicCircleScreen> {
MapMetricsController? mapController;
Set<Circle> circles = {};
Set<Marker> markers = {};
double radiusInMeters = 1000;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Tap to Draw Circle')),
body: Column(
children: [
// Radius slider
Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
Text('Radius: ${radiusInMeters.toInt()} m'),
Expanded(
child: Slider(
value: radiusInMeters,
min: 200,
max: 5000,
divisions: 24,
onChanged: (value) {
setState(() {
radiusInMeters = value;
});
},
),
),
],
),
),
// Map
Expanded(
child: MapMetrics(
styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
onMapCreated: (controller) => mapController = controller,
onMapClick: (Point point, LatLng coordinates) {
_addCircle(coordinates);
},
initialCameraPosition: CameraPosition(
target: LatLng(48.8566, 2.3522),
zoom: 13.0,
),
circles: circles,
markers: markers,
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
circles.clear();
markers.clear();
});
},
child: Icon(Icons.clear_all),
),
);
}
void _addCircle(LatLng position) {
final String id = 'circle_${DateTime.now().millisecondsSinceEpoch}';
setState(() {
circles.add(
Circle(
circleId: CircleId(id),
center: position,
radius: radiusInMeters,
strokeWidth: 2,
strokeColor: Colors.blue,
fillColor: Colors.blue.withOpacity(0.15),
),
);
markers.add(
Marker(
markerId: MarkerId(id),
position: position,
infoWindow: InfoWindow(
title: 'Circle',
snippet: 'Radius: ${radiusInMeters.toInt()} m',
),
),
);
});
}
}Circle Properties
| Property | Type | Description |
|---|---|---|
circleId | CircleId | Unique identifier for the circle |
center | LatLng | Center point of the circle |
radius | double | Radius in meters |
strokeWidth | int | Border width in pixels |
strokeColor | Color | Border color |
fillColor | Color | Fill color (use withOpacity for transparency) |
visible | bool | Whether the circle is visible |
zIndex | int | Drawing order relative to other overlays |
consumeTapEvents | bool | If true, tap events are consumed by the circle |
Next Steps
- Add a Polygon — Draw custom shapes on the map
- Add a Polyline — Draw lines and routes
- Markers and Annotations — Add markers with popups
Tip: The radius is always in meters and the circle scales correctly at all zoom levels — it represents a real geographic area on the map.