MapLibre Flutter GL

repository·main·Indexed 43 days ago

https://github.com/maplibre/flutter-maplibre-gl

A vendor-neutral implementation of interactive, styleable vector maps for Android, iOS, and Web. Powered by open-source MapLibre engines, it provides the MapLibreMap widget for rendering maps, MapLibreMapController for camera animations, and support for various source types including GeoJSON, vector, raster, and PMTiles. Requires Flutter 3.29+ and Dart 3.7+.

Tokens
56.2K
Snippets
173
Records
251
Agent score
55%

What's inside MapLibre Flutter

  1. Core features of MapLibre GL

    main

    MapLibre GL provides a high-performance mapping experience for Flutter with the following capabilities:

    • Native C++ Rendering: Uses MapLibre Native on Android and iOS for hardware-accelerated, 60fps, GPU-powered tile rendering.
    • Web Support: Uses MapLibre GL JS on the web, allowing for a single Dart codebase across Android, iOS, and web.
    • Dual-layer API: Offers high-level Annotations for interactive pins and low-level Style Layers for large datasets and GPU-accelerated expressions.
    • Offline Maps: Supports downloading geographic regions (tiles, fonts, and sprites) to Android and iOS devices for offline use.
    • Full Style Spec Support: Supports all MapLibre layer types (symbol, circle, fill, line, heatmap, raster) and data-driven expressions.
    • Open Source & Flexible: BSD-3 licensed. Compatible with OpenFreeMap, OpenMapTiles, or self-hosted PMTiles.
  2. Control the map camera

    main

    The map camera defines the viewport's center position, zoom level, bearing (rotation), and tilt. You can control the camera to perform either animated movements or instant jumps to specific coordinates and orientations.

    To manage the camera, refer to the following specialized guides:

    • Camera Controls: For programmatic movement and animations.
    • Camera Bounds: For constraining the camera to a specific geographic area.
  3. What is Feature State and when to use it

    main

    Feature state allows you to attach arbitrary key-value pairs to individual features at runtime. This is used to drive visual changes (like highlighting or recoloring) via Data-Driven Expressions using the ["feature-state", ...] syntax.

    Why use it? Instead of re-feeding an entire GeoJSON source with setGeoJsonSource (which is expensive because the whole collection must be re-encoded and rebuilt for the GPU), you can use feature state to perform cheap, targeted updates to specific features.

    Platform Support:

    • Web and Android: Fully supported.
    • iOS: Not supported. The methods will throw an UnsupportedError because the MapLibre iOS SDK does not expose this API yet.
  4. Overview of main flutter-maplibre-gl classes

    main
    The core functionality of the library is organized into several key classes. Use MapLibreMap to embed the map in your widget tree, and MapLibreMapController to interact with the map instance (e.g., moving the camera or adding layers) once it has been created. Geographic data is handled via LatLng and LatLngBounds, while camera states are managed through CameraPosition and CameraUpdate.
  5. Behavior Changes in 0.27.0

    main

    The following changes in 0.27.0 affect runtime behavior without requiring code changes:

    • Web: onMapIdle now fires correctly; previous workarounds for it not running on web can be removed.
    • Web: queryCameraPosition(), updateContentInsets(), and setPadding() no longer throw UnimplementedError on web.
    • Android/iOS: Symbol annotations now use Noto Sans Regular as the default font. If symbols were previously invisible due to missing glyphs, they should now appear.
    • Android: Feature state now works instead of throwing errors. You can remove kIsWeb guards around these calls.
    • Android/iOS: Offline download error codes have changed. Update any code matching PlatformException.code from:
      • mapboxTileCountLimitExceeded $\rightarrow$ tileCountLimitExceeded
      • mapboxInvalidRegionDefinition $\rightarrow$ invalidRegionDefinition
    • Android/iOS: Downloading an area that is already downloaded now replaces the existing region instead of adding a duplicate. On Android, the replacement gets a new ID; always read the ID back from the returned OfflineRegion object.
  6. Understand MapLibre Map Styles

    main

    A MapLibre style is a JSON document that defines the map's visual representation. It specifies:

    • Sources: Where the data comes from (e.g., tile URLs, GeoJSON).
    • Layers: What to draw and how (e.g., colors, widths, icons).
    • Sprites: The URL for the icon spritesheet.
    • Glyphs: The URL template for font glyphs.
    • Metadata: Optional information ignored by the renderer.
  7. Platform support for Globe, Terrain, and Sky

    main

    The features for Globe projection, 3D Terrain, and Sky are Web only.

    On Android and iOS, calling setProjection, setTerrain, or setSky will throw an UnsupportedError because MapLibre Native currently implements the Mercator projection on a flat map and does not yet support 3D terrain or sky.

    However, setLight is supported on all platforms.

    Important Lifecycle Note: Because setProjection, setTerrain, and setSky modify the style itself rather than a specific layer, these changes are discarded if the style is changed. You should always execute these calls within the onStyleLoadedCallback to ensure they persist.

  8. Important limitations and constraints

    main

    Unsupported Platforms

    • Desktop targets (Windows, macOS, Linux) are not supported.

    Widget Integration

    • You cannot place Flutter widgets inside the map layers. The map is a platform view rendered by native engines. To place Flutter widgets over the map, use a Stack and place your widgets on top of the MapLibreMap widget.
  9. How Data-Driven Expressions work

    main

    Data-driven expressions allow map layers to respond dynamically to feature data (like properties or zoom levels) instead of using fixed values. The GPU evaluates these expressions per-feature at render time.

    Important Constraints:

    • Expressions only work with Style Layers (e.g., addSymbolLayer, addCircleLayer).
    • They do not work with the Annotation API (e.g., addSymbol, addCircle), which requires fixed values.

    An expression is represented in Dart as a List<dynamic> where the first element is the operator name (using Expressions constants) and the subsequent elements are arguments:

    // Equivalent to the style spec's ["get", "name"]
    [Expressions.get, 'name']
    // Example of the structure
    [Expressions.get, 'name']
  10. When to use the Annotation API vs Style Layers

    main

    The Annotation API is designed for placing individual interactive markers, circles, lines, and polygons on the map.

    Use Annotations when:

    • You have fewer than ~50 features.
    • You need individual interactivity, such as tap callbacks or draggable behavior.

    Use Style Layers when:

    • You are working with large datasets.

    Prerequisites:

    • Annotations only work once the map style has loaded.
    • The annotation type must be included in the widget's annotationOrder.
  11. Configure MyLocationTrackingMode

    main

    The myLocationTrackingMode property determines how the camera behaves when following the user's location.

    ModeCamera Behavior
    noneThe camera is never moved by location updates.
    trackingThe camera follows the user's position.
    trackingCompassThe camera follows the position and rotates with the device compass.
    trackingGpsThe camera follows the position and rotates with the direction of travel.

    Note: On Web, only none and tracking are supported because browsers do not expose compass heading.

  12. Configure collision behavior for Symbol Layers

    main

    Symbols automatically avoid overlapping each other. You can customize this behavior using the following SymbolLayerProperties fields:

    • iconAllowOverlap: If true, icons will always be shown even if they overlap other icons.
    • iconIgnorePlacement: If true, icons will not consider the space occupied by other icons when determining their own placement.
    • textAllowOverlap: If false, labels will be hidden if they overlap other symbols/labels.
    • symbolAvoidEdges: If true, symbols are kept away from the map edges.
    SymbolLayerProperties(
      iconAllowOverlap: true,        // icons always show, even if overlapping
      iconIgnorePlacement: false,    // icons consider others' space
      textAllowOverlap: false,       // labels hide if they overlap
      symbolAvoidEdges: true,       // keep symbols away from map edges
    )