Tile Layer

You must comply with all the terms set by your tile server

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.

TileLayer(
  urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
  userAgentPackageName: 'dev.fleaflet.flutter_map.example',
  // + many other options
),
1

Choose a map source

flutter_map doesn't provide tiles, so you'll need to bring your own raster tiles! There's multiple different supported sources.

If you have a URL with placeholders for X, Y, and Z values, this is probably what you need to set up. This is the most common format for raster tiles, although many satellite tiles will instead use WMS.

Set the urlTemplate parameter to the template provided by the tile server - usually it can be copied directly from an account portal or documentation. You may also need to copy an API/access key.

(Advanced) Fallback URL Template

It's also possible to specify a fallbackUrl template, used if fetching a tile from the primary urlTemplate fails (which has the same format as this). It follows the same format, and supports the same placeholders.

Some TileProviders may not support/provide any functionality for fallbackUrl template.

Placeholders

As well as the standard XYZ placeholders in the template, the following placeholders may also be used:

  • {s}: subdomains (see below)

  • {r}: native retina mode - see step 4 for more information

  • {d}: reflects the tileDimension property (see below)

Additional placeholders can also be added freely to the template, and are filled in with the specified values in additionalOptions. This can be used to easier add switchable styles or access tokens, for example.

Subdomains

Some tile servers provide mirrors/redirects of the main tile server on/via subdomains, such as 'a', 'b', 'c'.

These were necessary to bypass browsers' limitations on simultaneous HTTP connections, thus increasing the number of tiles that can load at once.

To use subdomains, add the {s} placeholder, and specify the available subdomains in TileLayer.subdomains. flutter_map will then fill the placeholder with one of these values based on internal logic.

Tile Dimension

Some tile servers will use 512x512px tiles instead of 256x256px, such as Mapbox. Using these larger tiles can help reduce tile requests, and when combined with Retina Mode, it can give the same resolution.

To use these tiles, set tileDimension to the actual dimensions of the tiles (otherwise they will appear to small), such as 512. Also set zoomOffset to the result of -((d/256) - 1) - ie. -1 for x512px tiles (otherwise they will appear at the wrong geographical locations).

The {d} placeholder/parameter may also be used in the URL to pass through the value of tileDimension.

2

Identify your client

It's important to identify your app to tile servers using the HTTP 'User-Agent' header (if they're not your own, and especially if their free or their ToS specifies to do so). This avoids potential issues with the tile server blocking your app because they do not know why so many tiles are being requested by unidentified clients - this can escalate to flutter_map being blocked as a whole if too many apps do not identify themselves

Set the userAgentPackageName parameter to your app's package name (such as com.example.app or any other unique identifying information). flutter_map will identify your client to the server via the header as:

flutter_map (<packageName or 'unknown'>)

In some cases, you may be able to skip this step:

  • Your app runs solely on the web: the 'User-Agent' header cannot be changed, and will always identify your users' browsers

  • The tile server is your own, or you are using entirely offline mapping

3

Manually set up a tile provider to optimize tile loading

The TileProvider is responsible for fetching tiles for the TileLayer. By default, the TileLayer creates a NetworkTileProvider every time it is constructed. TileProviders are attached to the lifecycle of the TileLayer they are used within, and automatically disposed when their TileLayer is disposed.

However, this can cause performance issues or glitches for many apps. For example, the HTTP client can be manually constructed to be long-living, which will keep connections to a tile server open, increasing tile loading speeds.

Flowchart describing the best method to optimize a tile layer & tile provider setup. Is your `FlutterMap` or `TileLayer` rebuilt (frequently)? Or, are you using a different tile provider to the default? If not, don't worry about it, the `TileLayer` will do it for you. Otherwise, does your tile provider (or its properties) change frequently, or depend on the build method? If it does, construct a tile provider within the build method if necessary, but manually create a HTTP client outside of the build method and pass it in. Otherwise, do you need to reuse your tile provider across multiple different (volatile) tile layers? If you do, construct a tile provider outside of the build method, but also manually create a HTTP client and pass it in. Otherwise, just construct a tile provider as normal, but outside of the build method.

If you're not using a different tile provider, such as one provided by a plugin or one for offline mapping, then installing and using the official CancellableNetworkTileProvider plugin may be beneficial, especially on the web. See CancellableNetworkTileProvider for more information.

See Tile Providers for more information about tile providers generally.

4

Enable retina mode (if supported by your tiles)

Retina mode improves the resolution of map tiles, an effect particularly visible on high density (aka. retina) displays.

Raster map tiles can look especially pixelated on retina displays, so some servers support high-resolution "@2x" tiles, which are tiles at twice the resolution of normal tiles.

Where the display is high density, and the server supports retina tiles - usually indicated by an {r} placeholder in the URL template - it is recommended to enable retina mode.

To enable retina mode in these circumstances, use the following:

    retinaMode: RetinaMode.isHighDensity(context),

Note that where tiles are larger than the standard x256px (such as x512px), retina mode can help make them appear very similar to x256px tiles, but still retain the other benefits of larger tiles. In this case, consider fixing retinaMode to true, depending on your own tests.

Emulating retina mode

It is also possible to emulate retina mode, even when the server does not natively support it. If retinaMode is true, and no {r} placeholder is present, flutter_map will emulate it by requesting four tiles at a larger zoom level and combining them together in place of one.

Emulating retina mode has multiple negative effects:

  • it increases tile requests

  • it likely causes text/labels and POI markers embedded in the tiles to become smaller and unreadable

  • it decreases the effective maximum zoom by 1

Therefore, carefully consider whether emulating retina mode is appropriate for your application, and disable it if necessary. Always prefer native retina tiles if they are available.

5

Set the maximum zoom level covered by your tiles

Set the maxNativeZoom parameter to the maximum zoom level covered by your tile source. This will make flutter_map scale the tiles at this level when zooming in further, instead of attempting to load new tiles at the higher zoom level (which will fail).

You can also set MapOptions.maxZoom, which is an absolute zoom limit for users. It is recommended to set this to a few levels greater than the maximum zoom level covered by any of your tile layers.

Other Properties

panBuffer

To make a more seamless experience, tiles outside the current viewable area can be 'preloaded', with the aim of minimizing the amount of non-tile space a user sees.

panBuffer sets the number of surrounding rows and columns around the viewable tiles that should be loaded, and defaults to 1.

Tile Update Transformers

TileUpdateTransformer(s) is a power-user feature. Most applications won't require it.

A TileUpdateTransformer restricts and limits TileUpdateEvents (which are emitted 'by' MapEvents), which cause tiles to update.

For example, a transformer can delay (throttle or debounce) updates through one of the built-in transformers, or pause updates during an animation, or force updates even when a MapEvent wasn't emitted.

For more information, see:

Last updated

Was this helpful?