Display the Whole World in Flutter
Static pins render better with MarkerLayer
This page uses WidgetLayer, which repositions each marker in Dart every frame — it lags a frame while panning, ignores tilt and bearing, and does not scale past a few dozen markers. If your markers are plain pins with no Flutter content or gestures, use MarkerLayer instead; see Markers and Annotations.
This tutorial shows how to display a zoomed-out view of the entire world — perfect for global dashboards, flight maps, or selecting a region.
Prerequisites
Before you begin, ensure you have:
- Completed the Flutter Setup Guide
- A MapMetrics API key and style URL from the MapMetrics Portal
Basic World View
Show the entire world with a low zoom level:
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class WholeWorldScreen extends StatefulWidget {
@override
_WholeWorldScreenState createState() => _WholeWorldScreenState();
}
class _WholeWorldScreenState extends State<WholeWorldScreen> {
MapController? mapController;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('World View')),
body: MapMetricsView(
options: MapOptions(
initCenter: Position(0.0, 20.0), // Center on equator
initZoom: 1.0, // Zoomed out to see the whole world
initStyle:
'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
),
onMapCreated: (MapController controller) {
mapController = controller;
},
),
);
}
}World Map with Global Markers
Display markers for major world cities on a global view. There's no BitmapDescriptor/hue API for tinting built-in marker icons, so this uses WidgetLayer with a colored Icon per continent — each marker is an ordinary Flutter widget wrapped in a GestureDetector for the tap handler:
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class GlobalMarkersScreen extends StatefulWidget {
@override
_GlobalMarkersScreenState createState() => _GlobalMarkersScreenState();
}
class _GlobalMarkersScreenState extends State<GlobalMarkersScreen> {
MapController? mapController;
final List<Map<String, dynamic>> worldCities = [
{'name': 'New York', 'position': Position(-74.006, 40.7128), 'continent': 'NA'},
{'name': 'Los Angeles', 'position': Position(-118.2437, 34.0522), 'continent': 'NA'},
{'name': 'London', 'position': Position(-0.1276, 51.5074), 'continent': 'EU'},
{'name': 'Paris', 'position': Position(2.3522, 48.8566), 'continent': 'EU'},
{'name': 'Tokyo', 'position': Position(139.6503, 35.6762), 'continent': 'AS'},
{'name': 'Shanghai', 'position': Position(121.4737, 31.2304), 'continent': 'AS'},
{'name': 'Dubai', 'position': Position(55.2708, 25.2048), 'continent': 'AS'},
{'name': 'Mumbai', 'position': Position(72.8777, 19.076), 'continent': 'AS'},
{'name': 'Sydney', 'position': Position(151.2093, -33.8688), 'continent': 'OC'},
{'name': 'Sao Paulo', 'position': Position(-46.6333, -23.5505), 'continent': 'SA'},
{'name': 'Cairo', 'position': Position(31.2357, 30.0444), 'continent': 'AF'},
{'name': 'Lagos', 'position': Position(3.3792, 6.5244), 'continent': 'AF'},
{'name': 'Singapore', 'position': Position(103.8198, 1.3521), 'continent': 'AS'},
{'name': 'Moscow', 'position': Position(37.6173, 55.7558), 'continent': 'EU'},
{'name': 'Mexico City', 'position': Position(-99.1332, 19.4326), 'continent': 'NA'},
];
final Map<String, Color> continentColors = {
'NA': Colors.blue,
'SA': Colors.green,
'EU': Colors.red,
'AF': Colors.orange,
'AS': Colors.purple,
'OC': Colors.cyan,
};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Global Cities')),
body: Stack(
children: [
MapMetricsView(
options: MapOptions(
initCenter: Position(0.0, 20.0),
initZoom: 1.5,
initStyle:
'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
),
onMapCreated: (MapController controller) {
mapController = controller;
},
mapChildren: [
WidgetLayer(
allowInteraction: true,
markers: worldCities.map((city) {
final position = city['position'] as Position;
return Marker(
point: position,
size: const Size.square(22),
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
mapController?.animateCamera(
center: position,
zoom: 10.0,
);
},
child: Icon(
Icons.circle,
color: continentColors[city['continent']],
size: 16,
),
),
);
}).toList(),
),
],
),
// Legend
Positioned(
bottom: 16,
left: 16,
child: Card(
child: Padding(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_legendRow(Colors.blue, 'North America'),
_legendRow(Colors.green, 'South America'),
_legendRow(Colors.red, 'Europe'),
_legendRow(Colors.orange, 'Africa'),
_legendRow(Colors.purple, 'Asia'),
_legendRow(Colors.cyan, 'Oceania'),
],
),
),
),
),
// Zoom out button
Positioned(
top: 16,
right: 16,
child: FloatingActionButton.small(
onPressed: () {
mapController?.animateCamera(
center: Position(0.0, 20.0),
zoom: 1.5,
);
},
child: Icon(Icons.public),
tooltip: 'Show World',
),
),
],
),
);
}
Widget _legendRow(Color color, String label) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 1),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.circle, color: color, size: 10),
SizedBox(width: 4),
Text(label, style: TextStyle(fontSize: 11)),
],
),
);
}
}Region Selector
Let users tap a continent to zoom in:
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class RegionSelectorScreen extends StatefulWidget {
@override
_RegionSelectorScreenState createState() => _RegionSelectorScreenState();
}
class _RegionSelectorScreenState extends State<RegionSelectorScreen> {
MapController? mapController;
final List<Map<String, dynamic>> regions = [
{'name': 'Europe', 'position': Position(10.0, 50.0), 'zoom': 4.0},
{'name': 'Asia', 'position': Position(100.0, 35.0), 'zoom': 3.0},
{'name': 'N. America', 'position': Position(-100.0, 40.0), 'zoom': 3.0},
{'name': 'S. America', 'position': Position(-60.0, -15.0), 'zoom': 3.0},
{'name': 'Africa', 'position': Position(20.0, 5.0), 'zoom': 3.0},
{'name': 'Oceania', 'position': Position(140.0, -25.0), 'zoom': 3.5},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Region Selector')),
body: Column(
children: [
Container(
padding: EdgeInsets.all(8),
child: Wrap(
spacing: 6,
runSpacing: 6,
children: [
ActionChip(
avatar: Icon(Icons.public, size: 16),
label: Text('World'),
onPressed: () {
mapController?.animateCamera(
center: Position(0.0, 20.0),
zoom: 1.0,
);
},
),
...regions.map((r) => ActionChip(
label: Text(r['name'] as String),
onPressed: () {
mapController?.animateCamera(
center: r['position'] as Position,
zoom: r['zoom'] as double,
);
},
)),
],
),
),
Expanded(
child: MapMetricsView(
options: MapOptions(
initCenter: Position(0.0, 20.0),
initZoom: 1.0,
initStyle:
'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
),
onMapCreated: (MapController controller) {
mapController = controller;
},
),
),
],
),
);
}
}World View Zoom Levels
| Zoom | View |
|---|---|
| 0 - 1 | Full globe / world |
| 2 - 3 | Continent |
| 4 - 6 | Country |
| 7 - 10 | Region / State |
| 11 - 14 | City |
| 15 - 18 | Street / Building |
Next Steps
- Restrict Map Panning — Lock to a specific region
- Jump to Locations — Navigate between locations
- Arc Layer — Draw flight routes across the globe
Tip: At zoom level 1, the map shows the whole world. Use Position(0.0, 20.0) (longitude, latitude) as the center for a balanced view that shows all continents. For global dashboards, disable pitch and rotation to keep the view clean (MapGestures.all(rotate: false, pitch: false)).