Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarification of all options available for offline mapping #913

Merged
merged 2 commits into from
Jun 4, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 65 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ MapOptions(
),
```

### Azure Maps provider
### Azure Maps Provider

Configure the map to use [Azure Maps](https://azure.com/maps) by using the following `MapOptions` and layer options:

Expand Down Expand Up @@ -103,7 +103,7 @@ Widget build(BuildContext context) {

To use Azure Maps you will need to [setup an account and get a subscription key](https://docs.microsoft.com/en-us/azure/azure-maps/quick-demo-map-app)

### Open Street Map provider
### Open Street Maps Provider
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these titles were meant to be sentence-case. https://developers.google.com/style/headings


Configure the map to use [Open Street Map](https://openstreetmap.org) by using the following `MapOptions` and layer options:

Expand Down Expand Up @@ -229,21 +229,74 @@ child: FlutterMap(

For more details visit [Custom CRS demo page](./example/lib/pages/custom_crs/Readme.md).

## Run the example
## Run the Example

See the `example/` folder for a working example app.

To run it, in a terminal cd into the folder.
Then execute `ulimit -S -n 2048` ([ref](https://github.com/trentpiercy/trace/issues/1#issuecomment-404494469)).
You may need to then execute `ulimit -S -n 2048` ([ref](https://github.com/trentpiercy/trace/issues/1#issuecomment-404494469)).
Then execute `flutter run` with a running emulator.

## Preconfigured offline maps
## Dynamically Downloading & Caching Offline Maps

This method is only to use preconfigured and prepackaged offline maps. For advanced caching and ability to dynamically download an area, see the [flutter_map_tile_caching](https://github.com/JaffaKetchup/flutter_map_tile_caching) plugin.
In `flutter_map`, there are no available tile providers that will provide fully reliable caching or downloading, due to the extra dependencies needed to make this work. The only included tile provider that will handle caching at all is described below, but be aware that this is not fully functional. This section will guide through setting up caching and downloading functionality. If you would like to provide preconfigured and prepackaged map tiles to your app users, see the 'Preconfigured Offline Maps' section below.

First, [follow this guide to grab the tiles](https://tilemill-project.github.io/tilemill/docs/guides/osm-bright-mac-quickstart/).<br>
Once you have your map exported to `.mbtiles`, you can use [mbtilesToPng](https://github.com/alfanhui/mbtilesToPngs) to unpack into `/{z}/{x}/{y}.png`.
Move this to Assets folder and add asset directories to `pubspec.yaml`. Minimum required fields for offline maps are:
Full offline functionality, including caching and ability to download an area of map, is provided by the [`flutter_map_tile_caching`](https://github.com/JaffaKetchup/flutter_map_tile_caching) plugin package that is independently maintained. This will give you everything you need, however has the downsides of being an extra dependency for your app and having extra included dependencies for your app, both of which will increase your app's size and reliance on other developers.

If you would like to setup this functionality using minimal or no extra dependencies and without the plugin mentioned above, follow one of the two options below depending on your required use case (number 2 is recommended):

### 1. Use Flutter's built-in `NetworkImage` through the `NonCachingNetworkTileProvider`:

Whilst the name might make you think differently, it is designed to prevent you from using it and expecting it to cache; because it doesn't.

The `FlutterMap` `NonCachingNetworkTileProvider` implementaion uses `NetworkImage` which should cache images in memory until the app restart (through `Image.network`). However this is made even more confusing in the official Flutter docs. See the differences about caching between these two pages: https://api.flutter.dev/flutter/widgets/Image/Image.network.html and https://flutter.dev/docs/cookbook/images/network-image#placeholders-and-caching.

These two lines conflict:
> All network images are cached regardless of HTTP headers.

, and:

> The default Image.network constructor doesn’t handle more advanced functionality, such as [...] caching images to the device after they’re downloaded.

Therefore, unless you want to only cache until the app is restarted, you must use the second option below.

### 2. Using the `cached_network_image` dependency:

This dependency has an `ImageProvider` that caches images to disk, which means the cache persists through an app restart. You'll need to [include the package](https://pub.dev/packages/cached_network_image/install) in your `pubspec.yaml`.

Create your own provider using the code below:
```dart
import 'package:cached_network_image/cached_network_image.dart';
class CachedTileProvider extends TileProvider {
const CachedTileProvider();
@override
ImageProvider getImage(Coords<num> coords, TileLayerOptions options) {
return CachedNetworkImageProvider(
getTileUrl(coords, options),
//Now you can set options that determine how the image gets cached via whichever plugin you use.
);
}
}
```
Then, add the `CachedTileProvider` `TileProvider` to the appropriate `TileLayerOptions`:
```dart
TileLayerOptions(
urlTemplate: 'https://example.com/{x}/{y}/{z}',
tileProvider: const CachedTileProvider()
)
```

## Preconfigured Offline Maps

This method is only to use preconfigured and prepackaged offline maps. For more flexibility, and to see how to setup caching and downloading, see the 'Dynamically Downloading & Caching Offline Maps' section above.

This guide uses an open source program called [TileMill](https://tilemill-project.github.io/tilemill/). There is, however, an issue with lack of maintanace of this software. As of writing/updating on the 04th June 2021, the repo has not had an update since 13th October 2019, and there is [an issue debating what TileMill's future is](https://github.com/tilemill-project/tilemill/issues/2740). However, TileMill does still work, if not with some complicated installation process.

First, install TileMill on your machine. This may be from source, or there may be a package available for your operating system. It is recommended to install the newest version. Installation instructions can be found here https://tilemill-project.github.io/tilemill/docs/install/.

Then, [follow this guide to grab the tiles](https://tilemill-project.github.io/tilemill/docs/guides/osm-bright-mac-quickstart/). Once you have your map exported to `.mbtiles`, you can use [mbtilesToPng](https://github.com/alfanhui/mbtilesToPngs) to unpack into `/{z}/{x}/{y}.png`.

Move this to assets folder and add the appropriate asset directories to `pubspec.yaml`. Minimum required fields for this solution are:

```dart
Widget build(ctx) {
Expand All @@ -264,8 +317,9 @@ Widget build(ctx) {
}
```

Make sure PanBoundaries are within offline map boundary to stop missing asset errors.<br>
See the `flutter_map_example/` folder for a working example.
Make sure PanBoundaries are within offline map boundary to stop missing asset errors.

See the example folder for a working example.

Note that there is also `FileTileProvider()`, which you can use to load tiles from the filesystem.

Expand Down