Skip to content

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> {
  MapMetricsController? mapController;

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

  // --- Markers ---
  final Set<Marker> markers = {
    Marker(
      markerId: MarkerId('eiffel'),
      position: LatLng(48.8584, 2.2945),
      infoWindow: InfoWindow(title: 'Eiffel Tower'),
      icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueRed),
    ),
    Marker(
      markerId: MarkerId('louvre'),
      position: LatLng(48.8606, 2.3376),
      infoWindow: InfoWindow(title: 'Louvre Museum'),
      icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue),
    ),
    Marker(
      markerId: MarkerId('notre_dame'),
      position: LatLng(48.8530, 2.3499),
      infoWindow: InfoWindow(title: 'Notre-Dame'),
      icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen),
    ),
    Marker(
      markerId: MarkerId('sacre_coeur'),
      position: LatLng(48.8867, 2.3431),
      infoWindow: InfoWindow(title: 'Sacré-Cœur'),
      icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueOrange),
    ),
  };

  // --- Polylines ---
  final Set<Polyline> polylines = {
    Polyline(
      polylineId: PolylineId('walking_route'),
      points: [
        LatLng(48.8584, 2.2945), // Eiffel Tower
        LatLng(48.8606, 2.3376), // Louvre
        LatLng(48.8530, 2.3499), // Notre-Dame
      ],
      color: Colors.blue,
      width: 3,
    ),
    Polyline(
      polylineId: PolylineId('metro_line'),
      points: [
        LatLng(48.8530, 2.3499), // Notre-Dame
        LatLng(48.8670, 2.3640), // Midpoint
        LatLng(48.8867, 2.3431), // Sacré-Cœur
      ],
      color: Colors.purple,
      width: 3,
      patterns: [PatternItem.dash(15), PatternItem.gap(10)],
    ),
  };

  // --- Polygons ---
  final Set<Polygon> polygons = {
    Polygon(
      polygonId: PolygonId('latin_quarter'),
      points: [
        LatLng(48.855, 2.340),
        LatLng(48.855, 2.360),
        LatLng(48.845, 2.360),
        LatLng(48.845, 2.340),
      ],
      strokeWidth: 2,
      strokeColor: Colors.green,
      fillColor: Colors.green.withOpacity(0.15),
    ),
    Polygon(
      polygonId: PolygonId('marais'),
      points: [
        LatLng(48.862, 2.350),
        LatLng(48.862, 2.370),
        LatLng(48.852, 2.370),
        LatLng(48.852, 2.350),
      ],
      strokeWidth: 2,
      strokeColor: Colors.orange,
      fillColor: Colors.orange.withOpacity(0.15),
    ),
  };

  // --- Circles ---
  final Set<Circle> circles = {
    Circle(
      circleId: CircleId('eiffel_area'),
      center: LatLng(48.8584, 2.2945),
      radius: 500,
      strokeWidth: 2,
      strokeColor: Colors.red,
      fillColor: Colors.red.withOpacity(0.1),
    ),
    Circle(
      circleId: CircleId('sacre_coeur_area'),
      center: LatLng(48.8867, 2.3431),
      radius: 400,
      strokeWidth: 2,
      strokeColor: Colors.orange,
      fillColor: Colors.orange.withOpacity(0.1),
    ),
  };

  @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: MapMetrics(
              styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
              onMapCreated: (controller) => mapController = controller,
              initialCameraPosition: CameraPosition(
                target: LatLng(48.8600, 2.3300),
                zoom: 13.0,
              ),
              markers: showMarkers ? markers : {},
              polylines: showPolylines ? polylines : {},
              polygons: showPolygons ? polygons : {},
              circles: showCircles ? circles : {},
            ),
          ),
        ],
      ),
    );
  }

  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

TypeWidgetKey Properties
MarkerMarkerposition, icon, infoWindow, draggable
PolylinePolylinepoints, color, width, patterns
PolygonPolygonpoints, strokeColor, fillColor, strokeWidth
CircleCirclecenter, radius, strokeColor, fillColor

Next Steps


Tip: Use FilterChip or ChoiceChip widgets to let users toggle individual geometry layers on and off. Pass an empty Set to hide a layer without removing the data.