Only this pageAll pages
Powered by GitBook
1 of 37

v4

Loading...

Loading...

Loading...

Getting Started

Loading...

Loading...

Loading...

Loading...

Usage

Loading...

Loading...

Loading...

Loading...

Layers

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Plugins

Loading...

Loading...

Loading...

Loading...

Tile Servers

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Raster vs Vector Tiles

It is important to note that 'flutter_map' only supports raster tiles natively. Vector tiles can be used with a community maintained plugin.

This is described in more detail at the bottom of this page.

There are 2 main types of tiles a server can serve: raster and vector; each has their own advantages and drawbacks. This page is designed to help you choose a type for your app, and help you use vector tiles if you choose to.

Raster Tiles

Raster tiles are the 'older' type of tile, and are raster images (usually .png or .jpg). These tiles are good because they can render quickly and easily, can be viewed without special software, and are readily available from most mapping services. As such, this makes them the popular choice for beginners.

However, raster tiles cannot be easily themed: a theme needs a whole new set of map tiles. This makes apps using light and dark themes have mismatching maps. As well as this, raster tiles usually have larger file sizes meaning slower download times, and they can become blurred/pixelated when viewed at a larger scale: a problem for users when zooming between zoom levels. Another issue is that shapes/text inside tiles cannot be rotated, hence the name 'static tiles': therefore, rotating the map will not rotate the name of a road, for example.

Vector Tiles

Vector tiles can be considered the 'newer' standard. These images might contain a specialised format (such as .pbf) dictating the mathematics and coordinates used to draw lines and shapes. Because these tiles are drawn at render time instead of at request/server time, theming can be used to make the map fit in better with an app's theme. The math-based image means that the images/tiles can be scaled without any loss of clarity.

However it does add complexity to the rendering process as each element needs to be parsed and painted individually, meaning an impact to performance. Text elements and certain shapes can also be rotated (unlike raster tiles) to match the user's orientation, not the orientation of the map; but calculating this rotation needs to be done every frame, meaning an even larger impact on performance.

Using Vector Tiles

Due to the complications mentioned above, 'flutter_map' does not natively support vector tiles. However, vector tiles can be used with a to do this.

community maintained plugin (vector_map_tiles)

Examples

flutter_map provides an example application showcasing much of its functionality. In some cases, the example app contains undocumented functionality, so it's definitely worth checking out!

Live Web Demo

Please don't abuse the web demo! It runs on limited bandwidth and won't hold up to thousands of loads.

If you're going to be straining the application, please see Prebuilt Artifacts, and serve the application yourself.

Prebuilt Artifacts

If you can't build from source for your platform, our GitHub Actions CI system compiles the example app to GitHub Artifacts for Windows, Web, and Android.

The Windows and Android artifacts just require unzipping and installing the .exe or .apk found inside.

Note that these artifacts may become unavailable a while, in which case you'll need to build from source.

Build From Source

If you need to use the example app on another platform, you can build from source, using the 'example' directory of the repository.

Note that the web demo is built automatically from the , so may not reflect the the latest release on pub.dev.

The Web artifact requires unzipping and serving, as it contains more than one unbundled file. You may be able to use for this purpose.

Note that these artifacts are built automatically from the , so may not reflect the the latest release on pub.dev.

'master' branch
dhttpd
'master' branch

How Does It Work?

If you don't know about standard map things, such as the latitude/longitude system and projections, you should probably read about these first!

This library is similar to most other mapping libraries in other languages, so this applies to most other mapping libraries as well.

A mapping library is usually just a wrapper for a particular language that handles requests to servers called 'tile servers', and displays it in an interactive view for the user.

What is a Tile Server?

A tile server is a server accessible on the Internet by everyone, or by only people holding the correct API key.

There are four main types of server configuration, two of which are used together by any server: WMS or WMTS (aka. CARTO) & vector or raster. This wiki will focus on WMTS raster servers, such as the main OpenStreetMaps server, as it is the most commonly used option and is easier to setup and explain for beginners, but you can read about the options for WMS later on in this wiki. At the moment, support of vector tiles is limited, but experimental functionality can be added through an existing community maintained plugin.

Simplified, the server holds multiple images in a directory structure that makes it easy to find tiles without searching for references in a database beforehand (see below). These images put together make up the whole world, or area that that tile server supports. One tile is usually really small when rendered, under 20KB for most tiles. However, the entire planet data consumes 1.5TB when un-rendered and uncompressed from the 110GB download archive. When all tiles are rendered, they add up to over 54TB! Most servers render tiles on-the-fly to get around this.

'Slippy Map' Convention

The standard Slippy Map path looks like this: '/zoom/x/y.png' or '/x/y/zoom.png'. To note, the image format does not have to be '.png', tile servers also commonly serve as '.jpg' images.

You may also see '/?x={x}&y={y}&zoom={z}', which isn't quite the same as the Slippy Map convention, but it works in essentially the same way, so the below text still applies.

Zoom

X & Y

These images show the mathematics required to convert between Latitude and Longitude & the x/y/z format and vice-versa respectively. All credit for the above images goes to the Open Street Maps foundation.

Tile Providers

In this 'flutter_map' package, the classes that conduct this maths to get these tiles are called 'tile providers'.

However, these do a lot more than just the maths. They do the maths, format the appropriate URL, potentially stagger the URL (not to get rate limited by the browser or engine), make the request, get the image, process (and potentially store) the image and finally give it back to the main process to paint onto the map for the user to see.

Unless you choose to implement your own custom tile provider, you should never need to handle this yourself.

For more information about setting up a tile provider within the API, see Tile Providers.

This can be quite confusing for newcomers!

Within this library, 'tile providers' use 'tile servers' to retrieve tiles from the Internet. On the other hand, 'tile servers' and external sites usually use 'tile providers' to mean 'tile servers'!

Map Layers

Once the tile provider has dealt with the tile, it sends it to a map layer to get painted onto the map. This can be done using canvases (such as in HTML5 for the web), or, in the case of 'flutter_map', Flutter widgets.

The map layers also handle user interaction, such as panning, zooming, rotating and tapping.

If you want a truly British insight into this, look no further than: & . Otherwise I'd recommend something else.

The main tile server that's free to use and open-source is the Open Street Maps tile server, as mentioned above, a server which provides access to millions of tiles covering the whole Earth. that get updated and maintained by the general public. You can .

The , but this page provides some basics, roughly copied from that page.

Zoom refers to the zoom level. 1 is the lowest zoom level and contains the whole world in one tile. The higher the number, the more the zoom, and the more the detail, and therefore the less space covered. You can read more about this at . Most servers go up to 18, some up to 19, but no servers (as of writing) have a maximum limit above 22.

X and Y are values corresponding to the longitude and latitude of a location, however they are not actual longitude and latitude. See .

Lat/Lng to x/y/z
x/y/z to Lat/Lng
https://youtu.be/3mHC-Pf8-dU
https://youtu.be/jtBV3GgQLg8
find other 'semi-endorsed' public servers here
slippy map convention is documented extensively here
wiki.openstreetmap.org/wiki/Zoom_levels
wiki.openstreetmap.org/wiki/Slippy_map_tilenames

flutter_map

Mapping package for Flutter, based off of 'leaflet.js'. Simple and easy to learn, yet completely customizable and configurable, it's the best choice for mapping in your Flutter app.

This documentation applies to v4 only!

Use the version selector in the top left to choose documentation suitable for your version.

Demonstration

Setting up an interactive and map is simpler than making your lunch-time coffee! It can be accomplished in just over 20 lines and a minute or two to install.

This code snippet demonstrates everything you need for a simple map (in just over 20 lines!), but of course, FM is capable of much more than just this, and you could find yourself lost in the many options available and possibilities opened!

@override
Widget build(BuildContext context) {
  return (
    options: MapOptions(
      center: LatLng(51.509364, -0.128928),
      zoom: 9.2,
    ),
    : [
      TileLayer(
         'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
        userAgentPackageName: 'com.example.app',
      ),
    ],
    nonRotatedChildren: [
      (
        attributions: [
          TextSourceAttribution(
            'OpenStreetMap contributors',
            onTap: () => (Uri.parse('https://openstreetmap.org/copyright')),
          ),
        ],
      ),
    ],
  );
}

Feature Highlights

How does flutter_map compare to other mapping libraries?

This usually refers to libraries such as 'mapbox_gl' and 'google_maps_flutter'. In some ways, it is better, in some it is worse.

flutter_map wins on:

  • Less vendor lock-in You're not locked into a particular tile server with us - choose from hundreds of options, or build your own!

  • Customizability & extensibility Add all sorts of layers to display custom widgets and data on top of your map, and choose from flutter_map's many community maintained plugins to add even more functionality!

  • Ease of use/setup We don't require any API keys or platform specific setup (other than enabling the Internet permission!), so you can get started quicker, and make changes without fear of breaking your release application.

  • Support quality and frequency Most questions are answered and resolved within 12-24 hours, thanks to our dedicated maintainers and community.

However, alternatives may win on:

  • Performance* flutter_map's performance is very adequate for the vast majority of applications, and many big businesses use FM to provide maps in their Flutter app. However, if you're using high-thousands of Markers or Polygons and such like, alternatives may win, purely because they use platform views and GL, and so can do calculations outside of Dart.

  • ... and that's pretty much it 😉

Get Help

Not quite sure about something? No problem. Please get in touch via any of these methods, and we'll be with you as soon as possible. Please remember that we are volunteers, so we cannot guarantee (fast) support.

Due to time shortages and other internal matters, wait times for feature request implementations are currently extremely long and may not happen at all.

We'd love to have your contributions to add your own or others' pull requests!

Options

To dictate what the map can/should do, regardless of its contents, it needs some guidance!

It provides options that can be categorized into three main parts:

Initial Positioning

One part of MapOptions responsibilities is to define how the map should be positioned when first loaded. There's two ways to do this (that are incompatible):

  • center & zoom Defines the center coordinates of the map and a zoom level

  • bounds Defines an area with two/four coordinates that the viewport should fit to

It is possible to also set the map's rotation in degrees, if you don't want it North (0°) facing initially.

Changing these properties after the map has already been built for the first time will have no effect: they only apply on initialisation.

To control the map programatically, use a MapController: Controller.

Permanent Rules

One part of MapOptions responsibilities is to define the restrictions and limitations of the map and what users can/cannot do with it.

  • maxZoom (and minZoom) Limits how far the map can be zoomed by the user, to avoid showing empty tiles

  • maxBounds Limits how far the map can be moved by the user to a coordinate-based boundary

  • keepAlive If FlutterMap is located inside a PageView, ListView or another complex lazy layout, set this true to prevent the map from resetting to the Initial Positioning on rebuild

Instead of maxZoom (or in addition to), consider setting maxNativeZoom per TileLayer instead, to allow tiles to scale (and lose quality) on the final zoom level, instead of setting a hard limit.

Event Handling

When changes happen to FlutterMap's internal state, such as a change to the current position or zoom, it emits an event, some of which can be handled through callbacks, others of which can be handled through listening to a Stream.

If building a custom layer (Creating New Layers), consider using FlutterMapState directly instead.

Through MapController

If you are doing any of the following, setup a MapController, and listen to its mapEventStream instead:

  • Capturing more than a couple of events & using the event's payload/data

  • Needing the events in a single Stream

  • Handling events that aren't available in the callbacks below (Through MapOptions)

Through MapOptions

The following callbacks are available:

  • onTap

  • onLongPress

  • onPositionChanged

  • onPointerDown/onPointerUp/onPointerHover/onPointerCancel

  • onMapReady Primarily used for a MapController's Usage In initState()

  • onMapEvent (does not expose event data) Prefer Through MapController

Migrating To v4

This update brings major breaking changes for all users.

We apologise for any difficulty this may cause and time you may spend migrating.

However, this update is a part of our aim to simplify this library, and should improve stability, readability, and performance for you in the long term. In addition, this will make the library much easier to maintain and add new functionality to through plugins and future features.

Please refer to the sections below for information on how to migrate your project. This will contain the changes that most users may need to make, but not all changes.

TileLayer Changes

One of the major cores of flutter_map has been upgraded to the 21st century by a generous contributor (@rorystephenson). This increases the simplicity of the layer, and its performance!

Consolidated multiple properties into tileDisplay and tileUpdateTransformer

The following properties have been removed:

  • updateInterval

  • tileFadeInDuration

  • tileFadeInStart

  • tileFadeInStartWhenOverride

  • overrideTilesWhenUrlChanges

  • fastReplace

... and replaced with tileDisplay (TileDisplay) & tileUpdateTransformer (StreamTransformer<TileUpdateEvent, TileUpdateEvent>).

There is no "one size fits all" available for this migration: you'll need to experiment to find a combination of the two that work. Read the in-code API documentation for more information about what each one does.

Removed opacity property

To migrate, wrap the TileLayer with an Opacity widget.

Old Code (<4.0.0)
children: [
    TileLayer(
        // urlTemplate: '',
        opacity: 0.5,
    ),
],
New Code (4.0.0+)
children: [
    Opacity(
        opacity: 0.5,
        child: TileLayer(
            // urlTemplate: '',
        ),
    ),
],

Attribution Changes

Grey boxes get a little boring, don't you think? We think so as well, so we've developed a new interactive animated attribution layer that should cover all your needs.

Replaced AttributionWidget.defaultWidget with SimpleAttributionWidget

To migrate, replace with SimpleAttributionWidget and fill properties as necessary - see the in-code API documentation.

Removed AttributionWidget

To migrate, replace with an Align widget (and insert directly into the map's nonRotatedChildren).

Other Changes

Removed absorbPanEventsOnScrollables

Setting this to false was equivalent to disabling drag gestures through interactiveFlags.

To migrate map code, use the interactiveFlags as above. See Permanent Rules.

Changed some CustomPoint<T>s' generic type

CustomPoints previously used num as their generic type, which lead to type casting within FM and plugins, as some code only allowed int/double, not num.

Many of these have been updated to reflect their true usage.

To migrate, look for any methods which now take a different generic typed CustomPoint than was previously required. These should then be either casted at this location, or the source of the number should more accuratley represent what the number will be.

Controller

To programatically interact with the map (such as panning, zooming and rotating) and receive it's events, you'll need a MapController.

If building a custom layer (Creating New Layers), consider using FlutterMapState directly instead.

Initialisation

To use a MapController, it must initialised like any other object and then passed to the FlutterMap. This attaches them until the map is disposed.

final mapController = MapController();

@override
Widget build(BuildContext context) =>
    FlutterMap(
        mapController: mapController,
        ...
    );

Avoid disconnecting the map from the controller, as it can cause problems. If you need to change the map's contents:

  • Change its children (layers) individually

  • Re-initialise a new MapController, and keep it in an external state system

If you still get issues, and FlutterMap is located inside a PageView, ListView or another complex lazy layout, try setting keepAlive true in MapOptions: Permanent Rules.

Usage In initState()

It is a fairly common requirement to need to use the MapController in initState(), before the map has been built. Unfortunately, this is not possible, as the map must be built for the controller to be attached.

This isn't a problem however! The MapOptions contains an onMapReady callback (see Event Handling) is called when the map is initialised, and the initialised map controller can be used freely within it.

final mapController = MapController();

@override
Widget build(BuildContext context) =>
    FlutterMap(
        mapController: mapController,
        options: MapOptions(
            onMapReady: () {
                mapController.mapEventStream.listen((evt) {});
                // And any other `MapController` dependent non-movement methods
            },
        ),
    );

That method will, however, not work if the map is not built on the first frame. This may be the case if it is, for example, in a FutureBuilder.

Using them as a reaction to a map event is still fine.

Animation

The example application also includes a page demonstrating a custom animated map movement.

Latest Build Artifacts (thanks )

For bug reports & feature requests:

For general support & everything else:

Defines the location of the map when it is first loaded

Defines restrictions that last throughout the map's lifetime

Defines methods that are called on specific map events

You should check , but these are recommended for most maps:

interactiveFlags - see for available options Limits what methods the user can interact with the map through (for example, preventing rotation)

For a full list of changes, please see the full , and make use of the old and new API reference.

Alternatively, consider implementing attribution using to take advantage of the new interactive, animated layer.

To migrate plugin code, use onVerticalDrag and onHorizontalDrag updates instead of onPan. For more information, see .

For more information, see .

It may also be possible to use SchedulerBinding or WidgetsBinding in initState to run a method after the first frame has been built, as detailed here: . You'll probably see this approach in many older projects.

MapController methods that change the position of the map should not be used instantly in onMapReady - see .

Whilst animated movements through MapControllers aren't built-in, the provides this, and much more!

Supports any* map style

We natively support any static raster tile server, including from a web server or even from the local file system or app asset store. No more vendor lock-in!

Stress-free setup and use

Migrating from a commercial library such as Google Maps has never been easier! No more complex platform-specific setup, no more API keys: just add a widget and you're done.

Wide ecosystem of plugins

In the unlikely event that flutter_map doesn't natively contain something you need, just check to see if there's a community maintained plugin that does what you need!

Add other map features

Add polygons, polylines, and markers/pins to your map easily and quickly. Markers support displaying any widget you might want.

Frequently Asked Questions
GitHub Issues
flutter_map Discord server
all the available options
InteractiveFlag
Controller
CHANGELOG
Attribution Layer
https://github.com/fleaflet/flutter_map/pull/1455
https://github.com/fleaflet/flutter_map/pull/1482
https://stackoverflow.com/a/64186549/11846040
issue #1507
community maintained plugin flutter_map_animations
Initial positioning
Permanent rules
Event handling
Logoflutter_map Demo
Logoflutter_map/example at master · fleaflet/flutter_mapGitHub
Logonightly.link | Repository fleaflet/flutter_map | Workflow main.yml | Branch master
nightly

Layers

To display anything on the map, you'll need to include at least one "layer"!

Multiple layers can be used - similar to a Stack - each one showing different data in different ways, from actual map tiles (Tile Layer) to shapes on top of them (Polygon Layer), and even just your own custom layers (Creating New Layers).

Each layer has its own configuration and handling, but can also access the map's state/configuration, as well as be controlled by it.

Layers are usually defined in the children property of the FlutterMap - as is with the TileLayer, for example.

However, the nonRotatedChildren property can be used for layers which shouldn't move with the map, but still require access to the map's state/configuration - for example, the AttributionLayers.

Do not use nonRotatedChildren to enforce a non-rotatable map/TileLayer.

Instead, use interactiveFlags: Permanent Rules. These apply to the entire map and all layers.

Marker Layer

You can add single point features - such as pins, labels, or markers - to maps using MarkerLayer and Markers.

Excessive use of markers may create performance issues.

Rotation

Marker rotation support isn't built in (other than counter rotating to the map, to ensure the marker is always displayed right side up), but can easily be implemented through a rotation widget, such as Transform.rotate.

No more image only markers! , we allow usage of any widget as the marker.

Consider using a clustering plugin to merge nearby markers together, reducing the work that needs to be done when rendering: .

Layers
MarkerLayer(
  markers: [
    Marker(
      point: LatLng(30, 40),
      width: 80,
      height: 80,
      builder: (context) => FlutterLogo(),
    ),
  ],
),
LogoMapController class - flutter_map library - Dart API
Unlike other
popular mapping libraries

Circle Layer

You can add circle areas to maps by making them out of a center coordinate and radius using CircleLayer and CircleMarkers.

CircleLayer(
  circles: [
    CircleMarker(
      point: LatLng(51.50739215592943, -0.127709825533512),
      radius: 10000,
      useRadiusInMeter: true,
    ),
  ],
),

Due to the nature of the Earth being a sphere, drawing lines perfectly requires large amounts of difficult maths that may not behave correctly when given certain edge-cases.

Avoid creating large polygons, or polygons that cross the edges of the map, as this may create undesired results.

Excessive use of circles may create performance issues.

Polyline Layer

You can add lines to maps by making them out of individual coordinates using PolylineLayer and Polylines.

PolylineLayer(
  polylines: [
    Polyline(
      points: [LatLng(30, 40), LatLng(20, 50), LatLng(25, 45)],
      color: Colors.blue,
    ),
  ],
),

Due to the nature of the Earth being a sphere, drawing lines perfectly requires large amounts of difficult maths that may not behave correctly when given certain edge-cases.

Avoid creating large polylines, or polylines that cross the edges of the map, as this may create undesired results.

Excessive use of polylines may create performance issues.

Consider using one of the methods below if you encounter jank:

  • Keep saveLayers set to false (which is default). This will reduce rendering times, however it will also reduce the visual quality of the line at intersections.

  • Enable polylineCulling. This will prevent the calculation and rendering of lines outside of the current viewport, however this may not work as expected in all situations.

Routing/Navigation

Routing is out of scope for 'flutter_map'. However, if you can get a list of coordinates from a 3rd party, then you can use polylines to show them!

Converting Formats

You may have a polyline with 'Google Polyline Encoding' (which is a lossy compression algorithm to convert coordinates into a string and back). These are often returned from routing engines, for example. In this case, you'll need to decode the polyline to the correct format first, before you can use it in a Polyline's points argument.

import 'package:latlong2/latlong.dart';
export 'package:google_polyline_algorithm/google_polyline_algorithm.dart'
    show decodePolyline;

extension PolylineExt on List<List<num>> {
  List<LatLng> unpackPolyline() =>
      map((p) => LatLng(p[0].toDouble(), p[1].toDouble())).toList();
}

You can then use the package and the above snippet by doing:

import '<code_snippet_path>'

decodePolyline('<encoded-polyline>').unpackPolyline(); // Returns `List<LatLng>` for a map polyline

Simplify the polyline by reducing the number of points within it. This will reduce calculation times, however it will make the line less precise. This is recommended, for example, when zoomed further out. You may be able to use an external Flutter library for this, called .

A good open source option is , but if you want higher reliability and more functionality such as real-time based routing, you may want to try a commercial solution such as Mapbox or Google Maps.

One way to accomplish this is to use another Flutter library called , together with a custom method. You can use the code snippet below, which can just be pasted into a file and imported whenever needed:

'simplify'
OSRM
'google_polyline_algorithm'

Making A Plugin

There are many independently maintained plugins created by the 'flutter_map' community that give extra, prebuilt functionality, saving you even more time and potentially money.

Unfortunately, you may need more niche functionality that hasn't been provided by an existing plugin or by 'flutter_map' itself. Alternatively, you may have found a gap in functionality that not everyone will need, but some people will: in this case, it's likely the maintainers will ask you to submit a plugin instead of a pull request.

Plugins can add/change a wide variety of functionality, so this guide is not exhaustive. However, it will help with the most common requirements. Each subpage covers a specific part of the plugin API, and the section below sets out requirements for plugins to be accepted into the list.

Submitting A New Plugin

If you've made your own plugin that you're willing to share, you can add it to this list by creating a pull request in GitHub. We're always looking forward to see what you've made!

When submitting a plugin & PR, please ensure the plugin:

  • preferably includes 'flutter_map_' in the name

  • preferably available via a pub.dev installation

  • includes a runnable example, and/or screenshots or recordings

  • has a description that accurately and concisely represents your plugin

If you want to provide extra assistance to your users in a shared space, consider the official 'flutter_map' Discord server! Join using the link at the bottom of this page, and ping '@Github Maintainer' to be added to the 'Plugin Owner' role. You can then be easily identified and provide help or announcements in a dedicated plugins channel.

Tile Providers

This has a default of NetworkNoRetryTileProvider, which is recommended for most setups for better performance, unless your tile server is especially unreliable, or you need a local tile provider.

Custom TileProviders can be implemented by your application or other libraries. These may not conform to the usual rules above, and may additionally have their own parameters.

Network Tile Providers

Whilst not on the web, network tile providers can take a custom HttpClient/RetryClient, if you need to use it for whatever reason.

NetworkNoRetryTileProvider()

This is the default tile provider.

This tile provider uses the templateUrl to get the appropriate tile from the Internet, and it won't retry the request if it fails.

There is no guarantee about the default caching behaviour, but tiles should be cached until an application restart.

NetworkTileProvider()

This tile provider uses the templateUrl to get the appropriate tile from the Internet, but it will retry the request as specified in the RetryClient (which can be customised as needed when not on the web).

There is no guarantee about the default caching behaviour, but tiles should be cached until an application restart.

Local Tile Providers

These tile providers use the templateUrl to get the appropriate tile from the asset store of the application, or from a file on the users device, respectively

AssetTileProvider()

This tile providers uses the templateUrl to get the appropriate tile from the asset store of the application.

FileTileProvider()

This tile providers uses the templateUrl to get the appropriate tile from the a path/directory/file on the user's device - either internal application storage or external storage.

On the web, FileTileProvider() will automatically use NetworkImage() behind the scenes. This is not recommended. If you know you are running on the web platform, avoid using this tile provider.

Offline Mapping

The tileProvider parameter in TileLayer takes a TileProvider object specifying a to use for that layer.

Network tile providers can take a Map<String, String> of custom headers. Note that the that is automatically generated will not override any 'User-Agent' header if specified here. On the web, the 'User-Agent' header is not sent, as the browser controls the user agent.

Offline Mapping
tile provider
user agent
LogoMarkerLayer class - flutter_map.plugin_api library - Dart API
LogoMarker class - flutter_map.plugin_api library - Dart API
LogoMapOptions class - flutter_map library - Dart API

WMS Usage

flutter_map supports WMS tile servers through WMSTileLayerOptions - wmsOptions in TileLayers.

For usage, please refer to the Full API Reference, and the examples in the example app.

Omit urlTemplate if using WMS tiles. The template is now specified in the baseUrl property of WMSTileLayerOptions.

LogoCircleLayer class - flutter_map.plugin_api library - Dart API
Marker Clustering

Plugins List

There are many independently maintained 'plugins' created by the 'flutter_map' community that give extra, prebuilt functionality, saving you even more time and potentially money.

Some pages in this documentation provide direct links to these plugins to make it easier for you to find a suitable plugin.

However, if you're just browsing, a full list is provided below (in no particular order), containing many of the available plugins. You can click on any of the tiles to visit its GitHub repo or pub.dev package.

Although these plugins have been checked by 'flutter_map' maintainers, we do not accept responsibility for any issues or threats posed by independently maintained plugins.

Use plugins at your own risk.

There is no guarantee that any of these plugins will support the latest version of flutter_map.

Please remain patient with the plugin authors/owners.

Many plugins provide multiple methods to achieve similar goals. It is recommended to read the documentation of each potential plugin before using it in your project, as they might have slightly different feature sets or stability.

For example, there are two plugins that provide GeoJson parsing, and there are three plugins that provide marker clustering.

Miscellaneous

From more layers to whole heaps of new functionality, it's all here - assuming it's not in one of the other sections!

Marker Clustering

Marker clustering groups markers together under bigger markers when zoomed further out, decluttering your UI and giving a performance boost.

Better Markers

Better Polylines & Polygons

Parsing & Creating Map Features

LogoCircleMarker class - flutter_map.plugin_api library - Dart API

flutter_osrm (JaffaKetchup)

Suite of tools for working with routing information from an OSRM server

flutter_map_tile_caching (JaffaKetchup)

Advanced and highly-configurable caching solution, with support for bulk downloading

vector_map_tiles (greensopinion)

Suite of tools and layers for working with vector maps and style files

lat_lon_grid_plugin (matthiasdittmer)

A latitude longitude grid layer/overlay

flutter_map_animations (TesteurManiak)

Replacement for MapController which provides animated movement alternatives

flutter_map_supercluster (rorystephenson)

Superfast™ marker clustering solution, without animations

flutter_map_marker_cluster (lpongetti)

Beautiful and animated marker clustering solution

flutter_map_radius_cluster (rorystephenson)

Marker clustering solution with support for async marker searching within a radius

flutter_map_location_marker (tlserver)

Provides a prebuilt solution to display the user's location and heading/direction

flutter_map_marker_popup (rorystephenson)

Provides a prebuilt solution to display a popup above a marker when tapped

flutter_map_floating_marker_titles (androidseb)

Enables the display of 'floating' titles over markers

flutter_map_fast_markers (KanarekApp)

Improves performance of markers by painting directly onto canvas

flutter_map_line_editor (ibrierley)

Enables better dynamic editing of Polylines and Polygons

line_animator (ibrierley)

Interpolates along a set of points, allowing gradual drawing of lines and animating moving markers

flutter_map_tappable_polyline (OwnWeb)

Provides an onTap callback for Polylines

flutter_map_geojson (jozes)

Suite of tools to parse data in the GeoJson format into map features

polybool (mohammedX6)

Suite of tools to operate on polygons, such as union, intersection, and difference

geojson_vector_slicer (ibrierley)

Suite of tools to display GeoJson, vector tiles, and marker clusters, using sliced vector tiles

fluttermap_heatmap (tprebs)

Provides a layer to represent multiple data points in a density to color relationship

LogoPolylineLayer class - flutter_map.plugin_api library - Dart API
RichAttributionWidget
LogoPolyline class - flutter_map.plugin_api library - Dart API

Attribution Layer

Before publishing your app to users, you should credit any sources you use, according to their Terms of Service.

There are two built in methods to provide attribution, RichAttributionWidget and SimpleAttributionWidget, but you can also build your own using a simple Align widget. All of these should be inserted into the map's nonRotatedChildren.

You must comply to your tile server's ToS. Failure to do so may result in you being banned from their services.

This package is not responsible for your misuse of another tile server.

Please consider crediting flutter_map. It helps us to gain more awareness, which helps make this project better for everyone!

RichAttributionWidget

An animated, interactive attribution layer that supports both logos/images (displayed permanently) and text (displayed in a popup controlled by an icon button adjacent to the logos).

It is heavily customizable (in both animation and contents), and designed to easily meet the needs of most ToSs out of the box.

nonRotatedChildren: [
  RichAttributionWidget(
    animationConfig: const ScaleRAWA(), // Or `FadeRAWA` as is default
    attributions: [
      TextSourceAttribution(
        'OpenStreetMap contributors',
        onTap: () => launchUrl(Uri.parse('https://openstreetmap.org/copyright')),
      ),
    ],
  ),
],

For more information about configuration and all the many options this supports, see the in-code API documentation.

SimpleAttributionWidget

We also provide a more 'classic' styled box, similar to those found on many web maps. These are less customizable, but might be preferred over RichAttributionWidget for maps with limited interactivity.

nonRotatedChildren: [
  SimpleAttributionWidget(
    source: Text('OpenStreetMap contributors'),
  ),
],

Creating New Tile Providers

One common requirement is a custom TileProvider, and potentially a custom ImageProvider inside. This will allow your plugin to intercept all tile requests made by a map, and take your own action(s), before finally returning a tile.

Some useful steps are below, but there are more properties of a TileProvider that can be overridden.

Extending The Base TileProvider

To create your own usable TileProvider, the first step is making a class that extends the abstract class. It is not recommended to implement the base, as this will require overriding methods unnecessarily for most custom providers.

Overriding getImage

The majority of custom TileProviders will want to implement their own method to retrieve tiles. This is done by overriding the getImage method, and usually specifying your own ImageProvider, for example:

Notice that the 'User-Agent' header has been changed. This is recommended, as it helps further differentiate your plugin's traffic from vanilla 'flutter_map' traffic.

Overriding getTileUrl

Some custom TileProviders may want to change the way URLs for tiles are generated. Note that this is quite advanced usage.

The OpenStreetMap Tile Server (as used above) can be . Other servers may have different terms.

found here
class CustomTileProvider extends TileProvider {
    // Add your own custom properties, methods, etc.
    CustomTileProvider({
        // Suitably initialise your own custom properties
        super.headers, // Use the Dart 2.17 `super` syntax to initialise the base's header `Map`
    })
}
    @override
    ImageProvider getImage(Coords<num> coords, TileLayerOptions options) =>
        CustomImageProvider(
            options: options,
            coords: coords,
            headers: {
                ...headers,
                'User-Agent': headers['User-Agent'] == null
                    ? '<pluginName> for flutter_map (unknown)'
                    : '<pluginName> for ${headers['User-Agent']}',
            },
        );
    @override
    String getTileUrl(Coords coords, TileLayerOptions options) {
        // Custom generation
    }
LogoWMSTileLayerOptions class - flutter_map.plugin_api library - Dart API

Using Thunderforest

'flutter_map' is in no way associated or related with Thunderforest (or Gravitystorm Limited).

Thunderforest is a popular tiered-payment (with free tier) tile provider solution, especially for generic mapping applications. Note that using 'flutter_map' uses up your 'Map Tiles API' requests.

Using Mapbox

'flutter_map' is in no way associated or related with Mapbox.

To integrate with 3rd party mapping libraries, Mapbox provides an alternative to the normal 'Style URL' for each map style (and any custom map styles).

The 'CARTO' 'Integration URL' contains all the information and placeholders that flutter_map requires to display a map. Tiles requested through this endpoint consume the 'Static Tiles API' quota.

Once you have the appropriate URL for your desired map style (see Styles), use it in a TileLayer's urlTemplate as normal.

Retina tiles (high-DPI) tiles are used by default ('@2x'). The maximum zoom level that Mapbox supports is 22, so it is recommended to set maxNativeZoom or maxZoom as such.

Consider using the RichAttributionWidget, which meets the requirements by supporting both logo and text attribution.

Styles

Custom (Studio)

Mapbox supports creating and using custom styled maps through Studio. These are compatible with flutter_map.

Once you've found a style that suits your needs, or created your own, make it public, then open the 'Share & develop' modal:

Scroll to the bottom of the modal, and select 'Third party'. Then from the drop down box, select 'CARTO'. Copy the 'Integration URL' to your clipboard, and use as above.

Prebuilt

This URL should be used as above, although you may need to insert the placeholders manually.

Tile Layer

CARTO/XYZ/Slippy Map Only

The basis of any map is a TileLayer, which displays square raster images in a continuous grid, sourced from the Internet or a local file system.

flutter_map supports WMS Usage, but most map tiles are accessed through the CARTO/XYZ/Slippy Map standard, where the mapping library (flutter_map) fills in XYZ placeholders in a URL.

TileLayer(
  urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
  : 'dev.fleaflet.flutter_map.example',
),

You must comply to your tile server's ToS. Failure to do so may result in you being banned from their services.

This package is not responsible for your misuse of any tile server.

It is possible to use more than one tile layer, and can be used with transparency/opacity.

The children list works like the children of a Stack: last is on top.

Offline Mapping

Using maps without an Internet connection is common requirement. Luckily, there are a few options available to you to implement offline mapping in your app.

Caching & Bulk Downloading

To help choose whether FMTC or DIY is more appropriate for your use case, please see:

Bundled Map Tiles

If you have a set of custom raster tiles that you need to provide to all your users, you may want to consider bundling them together, to make a them easier to deploy to your users.

There is essentially two options for doing this:

  • Using AssetTileProvider, you can bundle a set of map tiles and register them as an asset within your app's pubspec.yaml. This means that they will be downloaded together with your application, keeping setup simple, but at the expense of a larger application bundle size.

  • Using FileTileProvider, you can bundle a set of map tiles and store them on a remote web server, that can be downloaded from later. This means that the setup may be more complicated for users, but the application's bundle size will be much smaller.

Either way, the filesystem should be structured like this: 'offlineMap/{z}/{x}/{y}.png', where every .png image is a tile.

Thunderstorm's home page: Thunderstorm's pricing page: Thunderstorm's documentation page:

Mapbox's Maps home page: Mapbox's Maps pricing page: Mapbox's Maps documentation:

Attribution is required, see .

Mapbox offers a variety of ready-made map styles that don't require customization. An example URL can be found in .

The OpenStreetMap Tile Server (as used above) can be . Other servers may have different terms.

Automatically store tiles as the user loads them through interacting with the map

Download an entire area/region of tiles in one shot, ready for a known no-Internet situation

Provide a set of tiles to all users through assets or the filesystem

The aims to solve the first two points. FMTC is designed to be easy to implement, but also sufficiently advanced to cover most (if not all) use cases.

However, using simpler packages in a DIY solution can be a better option in some cases. You'll need to implement a custom TileProvider backed by an alternative image provider or cache lookup system: see .

If you have a raster-format .mbtiles file, for example from TileMill, you should use to convert it to the correct structure first. Alternatively, you can use an external package such as '' to extract during runtime.

thunderforest.com
thunderforest.com/pricing
thunderforest.com/docs/map-tiles-api
mapbox.com/maps
mapbox.com/pricing#maps
docs.mapbox.com/api/maps/static-tiles
docs.mapbox.com/help/getting-started/attribution
the example here
found here
Creating New Tile Providers

Creating New Layers

Creating a new map layer is just as easy as it is to create a normal StatelessWidget or StatefulWidget.

Only one method call is needed to 'connect' the widget to the map state: FlutterMapState.maybeOf(). This call does two important things:

  • Cause the widget/layer to rebuild automatically when required (if in the build method)

  • Expose the map's internal state, meaning that it's information (such as zoom) can be accessed

You can see an example of how this is done below:

class CustomLayer extends StatelessWidget {
  const CustomLayer({super.key});

  @override
  Widget build(BuildContext context) {
    final mapState = FlutterMapState.maybeOf(context)!;
    // Use `mapState` as necessary, for example `mapState.zoom`
  }
}

Attempting to use the widget above outside of a FlutterMap widget will result in an error.

The FlutterMapState.maybeOf method will return null, because it cannot locate a parent/inherited state, and therefore cause a null exception.

community maintained plugin 'flutter_map_tile_caching'
mbtilesToPngs
flutter_mbtiles_extractor
Caching
Bulk downloading
Bundling

Frequently Asked Questions

We get quite a lot of similar questions, so please check if your question is here before you ask!

How can I use a custom map style? How can I prevent POI/labels rotating when the map rotates? How can I remove certain POI/labels from the map?

Unfortunately, this library cannot provide this functionality. It has no control over the tiles displayed in the TileLayer. This is a limitation of the technology, not this library.

This is because raster tiles are just images generated by a 3rd party tile server (dictated by your URL template), and therefore cannot be changed by the library that displays the tiles. Filters can be applied to the entire tile, such as an emulated dark mode, but these effects do not look great.

However, tilesets can be styled. This is the most effective way of using custom styles. These methods may help you with this:

  • You may wish to use a commercial service like Mapbox Studio, which allows you to style multiple tilesets. See Using Mapbox.

  • Alternatively, you can experiment with vector tiles. These are not pre-rendered, and so allow any style you desire to be applied on the fly. See Vector Tiles.

  • Your last option is to serve tiles yourself. See Other Options.

How can I route a user between two locations? Why does the Polyline only go in a straight line between two points?

See Routing/Navigation.

Why does the map disappear/go grey when I zoom in far?

This is a limitation of the chosen tile server: it cannot provide tiles at any higher zoom level, so the map just disappears as the requests for tiles get 404 Not Found responses.

To resolve this, there's 3 options:

  • Find a tile server with a higher maximum zoom level 22 is the highest that most will provide, including Mapbox

  • Set the maxNativeZoom property of the TileLayer This will scale the last set of tiles instead of requesting new ones, which has the side effect of making them blurry as their pixels are enlarged

  • Set the maxZoom property of the MapOptions This will prevent the user from zooming any further in

Contributing

Therefore, your contribution would be greatly appreciated, so we've written a guide to help you contribute successfully.

Contribution Guide

Do you think your contribution is essential to 'flutter_map'/useful to all users?

If not, then creating a plugin might be a good idea. To do this, see the Plugins section in these docs: there is advice, starting templates and a few rules to bear in mind. Plugins are preferred when possible as they keep the base library lightweight and easy to understand.

If you think it might be, continue onwards.

Is the contribution to fix a bug? Do you feel comfortable coding it yourself?

If it is, and you are comfortable fixing it yourself, feel free to create an issue stating the bug, mentioning that you're working on fixing it. Then cleanly fork the main repository, and fix the bug. Make sure you only fix/add/remove what's necessary, as this helps to avoid breaking changes. If there is a quick and dirty fix, try not to use it unless the bug is a big one and might take time to fix otherwise.

If it isn't, open a discussion or an issue stating your request. It might be that other people have already found a way to do it. If people like the idea, and you are comfortable doing it yourself, cleanly fork the main repository. Instead of then working on the main branch, work in a new branch: this helps to avoid merge conflicts until the end of development. You may choose to then open a DRAFT pull request to signify that you are working on it. Make sure you only fix/add/remove what's necessary, as this helps to keep track of changes.

If you don't feel comfortable coding changes yourself, start a discussion or an issue.

I've finished coding it. What's next?

Make sure you thoroughly test your changes, and consider writing automated tests.

Then consider whether you need to write documentation. If you do, make sure you follow a similar format to all the other pages in these docs, and use correct spelling and grammar (consider getting a spell checker for Markdown). Then remember to change the documentation version at 'introduction/go'. Change the title of the grey box, the text version, and the link (to the newest migration page), but leave the dynamic badge and other text untouched. If no new documentation is needed, don't touch the grey box.

After that, check if you need to add a migration guide. This is only applicable if the change was a breaking change.

One last thing! Consider if you need to write examples for your changes. If it's a bug fix, you probably won't need to, unless an example also needs to be fixed. But if it's a feature addition, it needs an example, or at least the updating of an existing example. Make sure you test the example as well!

Can I publish it yet?

Yes! Open a PR (or take the existing PR out of draft stage), and link the issue that you opened.

Hopefully a maintainer will merge your changes quickly. Note that not every new merge will result in a new pub.dev release, so you may have to switch to using the GitHub installation method for your new features.

We appreciate your changes!

Using Stadia Maps

'flutter_map' is in no way associated or related with Stadia Maps.

To integrate with 3rd party mapping libraries, Stadia Maps provides an alternative to the normal 'Static Maps Base URL' for each map style.

The 'Raster XYZ PNGs' URL contains all the information and placeholders that flutter_map requires to display a map. Tiles requested through this endpoint consume the 'Styled Raster Map Tiles' credits.

Retina tiles (high-DPI) tiles are available. Use the URLs containing '@2x' instead of '{r}'. The maximum zoom level that Stadia Maps supports is 20, so it is recommended to set maxNativeZoom or maxZoom as such.

Styles

Vector Usage

However, please note that this method of integration is still experimental. Many of the Stadia Maps styles utilize advanced features of the Mapbox GL JSON style language which are not yet well-supported.

Credits

Thanks to everyone who has contributed to flutter_map in anyway, you've helped make it the most popular non-commercially owned mapping solution for Flutter. As well as those that have contributed directly to the code, this includes everyone on the Discord server, everyone who's following the progress, and everyone that's participating in discussions and issues.

In particular, thanks go to:

  • John P Ryan - the founder of this project

  • All the current maintainers:

    • @ibrierley

    • @JaffaKetchup

    • @mootw (previously @MooNag)

    • @TesteurManiak

  • All the previous maintainers:

    • @kengu

    • @maRci002

  • The original authors of this documentation:

    • @JaffaKetchup

    • @themisir

    • @comatory

  • Notable contributors:

    • @rorystepenson

    • @ignatz

Installation

Just import the package as you would normally, from the command line:

Commits available from Git (GitHub) may not be stable. Only use this method if you have no other choice.

If you urgently need the latest version, a specific branch, or a specific fork, you can use this method.

Import

After installing the package, import it into the necessary files in your project:

Before continuing with usage, make sure you comply with the appropriate rules and ToS for your server. Some have stricter rules than others. This package or the creator(s) are not responsible for any violations you make using this package.

Open PRs
Pub.dev
Visit our documentation over on Thunderforest's site (may be outdated)
Read the API documentation to find out all the available options
How can I add a Marker where the user's location is? How can I center the map on the user's location?

This is beyond the scope of flutter_map. However, you can use the to do this.

Alternatively, use the 'location' and 'compass' packages to generate a stream of the user's location and heading, and feed that to a Marker using a StreamBuilder.

'flutter_map' is only as big and useful as it is because of contributors. You can see a , and there are currently , each potentially from a new contributor.

Stadia Maps' home page: Stadia Maps' pricing page: Stadia Maps' documentation page:

Once you have the appropriate URL for your desired map style (see ), use it in a TileLayer's urlTemplate as normal.

Attribution is required, see .

Consider using the or s, which meet the requirements.

Stadia Maps offers a variety of ready-made map styles that don't require customization. URLs are found with the style: see the available . The URL should be used as above.

Stadia Maps' also provides vector tiles. For more information about using vector tiles, please see .

If you want to contribute to the codebase, please visit the instructions. We'd love to have your input!

Anyone who has made plugins for flutter_map, see the

All users should also to work with coordinates in 'flutter_map'.

In the event that the LatLng object provided by that library conflicts with another, for example the one provided by Google Maps, you may need to .

From

From

First, use , then add the following lines to your pubspec.yaml file, as a root object:

How Does It Work?
community maintained plugin 'flutter_map_location_marker'
Logoflutter_map - Thunderforest
LogoTileLayer class - flutter_map.plugin_api library - Dart API
LogoIs FMTC Right For Me?FMTC Docs
flutter pub add flutter_map
flutter pub add latlong2
pubspec.yaml
dependency_overrides:
    flutter_map:
        git:
            url: https://github.com/fleaflet/flutter_map.git
            # ref: main 
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:flutter_map/plugin_api.dart'; // Only import if required functionality is not exposed by default
Contributing
Plugins List
stars
points
likes
Open Issues
Styles
RichAttributionWidget
SimpleAttributionWidget
Using Vector Tiles
From pub.dev
stadiamaps.com
stadiamaps.com/pricing
docs.stadiamaps.com
docs.stadiamaps.com/#legal-details-required-attribution
map styles
install 'latlong2'
use the 'as' suffix
pub.dev
github.com
list of current contributors here
GitHub PRs
Example FlutterMap, containing a Marker, Polyline, Polygon, and RichAttributionLayer on top of a TileLayer
An example Marker, using FlutterLogo as the child
An example CircleMarker
An example Polyline
Closed RichAttributionWidget
Opened RichAttributionWidget, as in the example app
SimpleAttributionWidget, as in the example app
Example Flutter Map widget, showing an OpenStreetMap map, with multiple shapes overlaid on it
An icon and a button displayed over a map, in the bottom right corner
A white box with attribution text displayed over a map

Additional Setup

Web

Always compile to web using the CanvasKit renderer instead of the HTML renderer, even on mobile devices.

Failure to do so leads to severely impacted performance. Additionally, some features may be broken - for example, tile fading doesn't work when rendering in HTML.

Android

flutter_map needs to access the Internet to load tiles, in most cases. On Android, apps must include the INTERNET permission in their manifest. Add the following line to all manifests.

AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>

Overlay Image Layer

You can overlay images on the map (for example, town or floor plans) using OverlayImageLayer and OverlayImages or RotatedOverlayImages.

For more information about web renderers, see .

https://docs.flutter.dev/platform-integration/web/renderers
OverlayImageLayer(
  circles: [
    OverlayImage(
      bounds: LatLngBounds(
        LatLng(45.3367881884556, 14.159452282322459),
        LatLng(45.264129635422826, 14.252585831779033),
      ),
      imageProvider: NetworkImage(),
    ),
  ],
),
Example RotatedOverlayImage

Base Widget

FlutterMap(
    mapController: _mapController,
    options: MapOptions(),
    children: [],
    nonRotatedChildren: [],
);

Placement Recommendations

It is recommended to make the map as large as possible, to allow it to display a lot of useful information easily.

As such, we recommend using a depth-based layout (eg. using Stacks) instead of a flat-based layout (eg. using Columns). The following 3rd party packages might help with creating a modern design:

If you must restrict the widget's size, you won't find a height or width property. Instead, use a SizedBox or Column/Row & Expanded.

nonRotatedChildren

Similar to children, but these don't rotate or move with the other layers.

options (MapOptions)

Configure options that don't directly affect the appearance of the map, such as starting location and maximum zoom limit.

mapController

Attach a controller object to control the map programatically, including panning and zooming.

children

Takes a List of Widgets (usually a dedicated 'layer') to display on the map, such as tile layers or polygon layers,

https://pub.dev/packages/backdrop
https://pub.dev/packages/sliding_up_panel
https://pub.dev/packages/material_floating_search_bar_2

Polygon Layer

You can add areas/shapes to maps by making them out of individual coordinates using PolygonLayer and Polygons.

PolygonLayer(
  polygons: [
    Polygon(
      points: [LatLng(30, 40), LatLng(20, 50), LatLng(25, 45)],
      color: Colors.blue,
    ),
  ],
),

Due to the nature of the Earth being a sphere, drawing lines perfectly requires large amounts of difficult maths that may not behave correctly when given certain edge-cases.

Avoid creating large polygons, or polygons that cross the edges of the map, as this may create undesired results.

Excessive use of polygons may create performance issues.

Consider enabling polygonCulling. This will prevent the calculation and rendering of polygons outside of the current viewport, however this may not work as expected in all situations.

Polygon Manipulation

'flutter_map' doesn't provide any public methods to manipulate polygons, as these would be deemed out of scope.

onTap Support

There is no support for handling taps on polygons, due to multiple technical challenges. To stay up to date with this existing feature request, see the linked issue.

An example Polygon

However, some useful methods can be found in libraries such as 'latlong2' and . These can be applied to the input of Polygon's points argument, and the map will do it's best to try to render them. However, more complex polygons - such as those with holes - may be painted inaccurately, and may therefore require manual adjustment (of holePointsList, for example).

'poly_bool_dart'
LogoPolygonLayer class - flutter_map.plugin_api library - Dart API
LogoBaseOverlayImage class - flutter_map.plugin_api library - Dart API
LogoPolygon class - flutter_map.plugin_api library - Dart API

Other Options

Other servers

There are plenty of other tile servers you can choose from, free or paid. Most provide a static tile service/API, usually called Static Tiles or just Tile Requests (if no vector tiles are supported).

A good catalogue of servers (usually called Providers elsewhere) can be found at the websites below:

Google Maps does not document a static raster tile server. Therefore, flutter_map is unable to show Google Maps.

There is an undocumented endpoint available, however it violates the Google Maps Platform ToS.

Serving your own tiles

Switch2OSM also provides detailed instructions on how to serve your own tiles: this can be surprisingly economical and enjoyable if you don't mind a few hours in a Linux console.

However, this will require a very high-spec computer, especially for larger areas, and hosting this might be more complicated than it's worth. It's very difficult to fully understand the technologies involved.

LogoPolygon onTap? · Issue #385 · fleaflet/flutter_mapGitHub
LogoOverlayImageLayer class - flutter_map.plugin_api library - Dart API
LogoRaster tile providers - OpenStreetMap Wiki
LogoServing TilesSwitch2OSM
LogoProvidersSwitch2OSM