Skip to content

Both copy text to your clipboard — Build with AI copies a setup prompt to paste into Claude Code, Cursor, Codex or Copilot; Copy page as Markdown copies this page to paste into a chat. How it works

Multiple Geometries in Flutter

This tutorial shows how to display markers, polylines, polygons, and circles all on the same map.

Prerequisites

Before you begin, ensure you have:

Complete Example

Display all geometry types together on a single map:

dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';

class MultipleGeometriesScreen extends StatefulWidget {
  @override
  _MultipleGeometriesScreenState createState() => _MultipleGeometriesScreenState();
}

class _MultipleGeometriesScreenState extends State<MultipleGeometriesScreen> {
  MapController? mapController;

  bool showMarkers = true;
  bool showPolylines = true;
  bool showPolygons = true;
  bool showCircles = true;

  // --- Markers (widget-based, from mapChildren) ---
  final List<Marker> markers = [
    Marker(
      point: Position(2.2945, 48.8584), // Eiffel Tower
      size: const Size(32, 32),
      alignment: Alignment.bottomCenter,
      child: const Icon(Icons.location_on, color: Colors.red, size: 32),
    ),
    Marker(
      point: Position(2.3376, 48.8606), // Louvre
      size: const Size(32, 32),
      alignment: Alignment.bottomCenter,
      child: const Icon(Icons.location_on, color: Colors.blue, size: 32),
    ),
    Marker(
      point: Position(2.3499, 48.8530), // Notre-Dame
      size: const Size(32, 32),
      alignment: Alignment.bottomCenter,
      child: const Icon(Icons.location_on, color: Colors.green, size: 32),
    ),
    Marker(
      point: Position(2.3431, 48.8867), // Sacré-Cœur
      size: const Size(32, 32),
      alignment: Alignment.bottomCenter,
      child: const Icon(Icons.location_on, color: Colors.orange, size: 32),
    ),
  ];

  // --- Polylines (style layer) ---
  final List<LineString> polylines = [
    LineString(
      coordinates: [
        Position(2.2945, 48.8584), // Eiffel Tower
        Position(2.3376, 48.8606), // Louvre
        Position(2.3499, 48.8530), // Notre-Dame
      ],
    ),
    LineString(
      coordinates: [
        Position(2.3499, 48.8530), // Notre-Dame
        Position(2.3640, 48.8670), // Midpoint
        Position(2.3431, 48.8867), // Sacré-Cœur
      ],
    ),
  ];

  // --- Polygons (style layer) ---
  final List<Polygon> polygons = [
    Polygon(
      coordinates: [
        [
          Position(2.340, 48.855),
          Position(2.360, 48.855),
          Position(2.360, 48.845),
          Position(2.340, 48.845),
          Position(2.340, 48.855), // ring must close
        ],
      ],
    ),
    Polygon(
      coordinates: [
        [
          Position(2.350, 48.862),
          Position(2.370, 48.862),
          Position(2.370, 48.852),
          Position(2.350, 48.852),
          Position(2.350, 48.862),
        ],
      ],
    ),
  ];

  // --- Circles (style layer) ---
  final List<Point> circlePoints = [
    Point(coordinates: Position(2.2945, 48.8584)), // Eiffel Tower area
    Point(coordinates: Position(2.3431, 48.8867)), // Sacré-Cœur area
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Multiple Geometries')),
      body: Column(
        children: [
          // Toggle buttons
          Container(
            padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            color: Colors.grey[100],
            child: Row(
              children: [
                _toggleChip('Markers', showMarkers, (v) => setState(() => showMarkers = v)),
                SizedBox(width: 4),
                _toggleChip('Lines', showPolylines, (v) => setState(() => showPolylines = v)),
                SizedBox(width: 4),
                _toggleChip('Polygons', showPolygons, (v) => setState(() => showPolygons = v)),
                SizedBox(width: 4),
                _toggleChip('Circles', showCircles, (v) => setState(() => showCircles = v)),
              ],
            ),
          ),
          // Map
          Expanded(
            child: MapMetricsView(
              options: MapOptions(
                initStyle: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
                initCenter: Position(2.3300, 48.8600), // lng, lat
                initZoom: 13.0,
              ),
              onMapCreated: (controller) => mapController = controller,
              layers: [
                if (showPolylines)
                  PolylineLayer(polylines: polylines, color: Colors.blue, width: 3),
                if (showPolygons)
                  PolygonLayer(
                    polygons: polygons,
                    color: Colors.green.withOpacity(0.15),
                    outlineColor: Colors.green,
                  ),
                if (showCircles)
                  CircleLayer(
                    points: circlePoints,
                    radius: 20,
                    color: Colors.red.withOpacity(0.15),
                    strokeWidth: 2,
                    strokeColor: Colors.red,
                  ),
              ],
              mapChildren: [
                if (showMarkers) WidgetLayer(markers: markers),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _toggleChip(String label, bool value, ValueChanged<bool> onChanged) {
    return FilterChip(
      label: Text(label, style: TextStyle(fontSize: 12)),
      selected: value,
      onSelected: onChanged,
      selectedColor: Colors.blue[100],
      checkmarkColor: Colors.blue,
      visualDensity: VisualDensity.compact,
    );
  }
}

Geometry Types Summary

TypeHow it's renderedKey Properties
MarkerMarker in WidgetLayer (mapChildren) — a real Flutter widget positioned over the mappoint, size, child, alignment, rotate, flat
PolylinePolylineLayer (layers), built from LineString geometriespolylines, color, width, dashArray
PolygonPolygonLayer (layers), built from Polygon geometriespolygons, color, outlineColor
CircleCircleLayer (layers), built from Point geometriespoints, radius, color, strokeColor, strokeWidth

There is no Marker/MarkerId/Polyline/PolylineId/Polygon/PolygonId/Circle/CircleId/InfoWindow/BitmapDescriptor API in this SDK. Point-based annotations come in two real flavors:

  • WidgetLayer + Marker — put in mapChildren, renders arbitrary Flutter widgets (icons, cards, custom shapes) positioned by Position. Best when you need per-marker styling, taps, or custom widgets.
  • MarkerLayer (in layers) — a native style layer that renders a batch of Point geometries with a single shared iconImage/textField style. Cheaper for large numbers of uniformly-styled points, but all points in one MarkerLayer share the same paint properties.

PolylineLayer, PolygonLayer, and CircleLayer are always native style layers built from geotypes geometry objects (LineString, Polygon, Point) — there's no widget-based equivalent for lines/polygons/circles.

Next Steps


Tip: Toggle a layers:/mapChildren: entry in and out of the list (as shown with the if (showX) guards above) to hide a layer without discarding the underlying data.