Git Product home page Git Product logo

flutter-vector-map-tiles's Introduction

A plugin for flutter_map that enables the use of vector tiles with slippy maps and Flutter.

Loads vector tiles from a source such as Mapbox or Stadia Maps, and renders them as a layer on a flutter_map.

example screenshot example screenshot

See the gallery for more examples.

Installing

Details on https://pub.dev/packages/vector_map_tiles

See vector_map_tiles/install for instructions on installing.

Usage

Read the map style:

  Future<Style> _readStyle() => StyleReader(
          uri:
              'https://tiles.stadiamaps.com/styles/osm_bright.json?api_key={key}',
          apiKey: stadiaMapsApiKey,
          logger: const Logger.console())
      .read();

Create the map:

 FlutterMap(
    mapController: _controller,
    options: MapOptions(
        center: style.center ?? LatLng(49.246292, -123.116226),
        zoom: style.zoom ?? 10,
        maxZoom: 22,
        interactiveFlags: InteractiveFlag.drag |
            InteractiveFlag.flingAnimation |
            InteractiveFlag.pinchMove |
            InteractiveFlag.pinchZoom |
            InteractiveFlag.doubleTapZoom),
    children: [
      // normally you would see TileLayer which provides raster tiles
      // instead this vector tile layer replaces the standard tile layer
      VectorTileLayer(
          theme: style.theme,
          sprites: style.sprites,
          // tileOffset: TileOffset.mapbox, enable with mapbox
          tileProviders: style.providers),
    ],
  )

See the example for details.

Customizing a Theme

A theme can be built-in to your application:

VectorTileLayer(theme: ThemeReader().read(_myTheme()), ...)

Specifying Alternate Tiles

Tiles can be loaded from alternate sources:

VectorTileLayer(tileProviders: TileProviders(
                    {'openmaptiles': _tileProvider() },
                    ...)
                )

VectorTileProvider _tileProvider() => NetworkVectorTileProvider(
            urlTemplate: 'https://tiles.example.com/openmaptiles/{z}/{x}/{y}.pbf?api_key=$myApiKey',
            // this is the maximum zoom of the provider, not the
            // maximum of the map. vector tiles are rendered
            // to larger sizes to support higher zoom levels
            maximumZoom: 14),

Tile Providers for other tile sources

Format Description Package
PMTiles A binary file format to bundle tiles and use them from a web or file system source. vector_map_tiles_pmtiles
MBTiles A commonly used file format to bundle tiles into a SQLite database. vector_map_tiles_mbtiles

More Examples

A more complete example showing use of this library is available in the examples repository flutter-vector-map-tiles-examples. The examples include use with multiple themes, tile providers, contours, hillshade and network-loaded styles.

Themes and Tile Providers

Themes and tile providers must be matched to have a working configuration, since themes reference layers and properties in the vector tile.

While we don't test with all configurations, the following themes have been tested with this library:

Tiles from Maptiler or Stadia Maps

Tiles from mapbox

Other combinations of theme/provider may work too.

Some tile providers offer tiles with more detail that are intended to be drawn at a higher zoom level. For example, Mapbox provdies tiles tiles that render at 512px instead of the default 256px (Mapbox docs). Set VectorTileLayerOptions.tileOffset with these providers.

Attribution

Examples provided in vector_map_tiles make use of Mapbox and Stadia Maps, both of which require attribution. Be sure to read the terms of service of your tile data provider to ensure that you understand their attribution requirements.

Upgrading

For guidance on upgrading from a previous version of this library, see the Upgrading Guide.

Development

Continuous Integration

CI with GitHub Actions:

CI status

License

Copyright 2021 David Green

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

flutter-vector-map-tiles's People

Contributors

amenk avatar fafre avatar greensopinion avatar jaffaketchup avatar josxha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter-vector-map-tiles's Issues

Custom Mapbox styles don't apply

I've tried to use the plugin with custom styles which I've created in Mapbox Studio and then downloaded as .jsons. Unfortunately, this plugin doesn't seem to apply the styles as the map displays with the default Mapbox Light and Dark (i.e. not dimming texts and borders like I've specified in my styles).

For references, this is how my custom light map should look:
image

I've made a minimal repo to demo the issue: https://github.com/alkaitagi/vector_map_test/tree/master/lib. I'll appreciate any help.

CancellationException occuring with Mapbox vectors

Gave this plugin a try to see if I could get vector maps in my app. Currently a CancellationException happens in tileset_executor_preprocessor.dart on line 35.

https://github.com/greensopinion/flutter-vector-map-tiles/blob/main/lib/src/stream/tileset_executor_preprocessor.dart#L35

On line 34 the deduplicationKey is "preprocess: z=8,x=51,y=95", if that means anything.

This is my code.

pubspec:

flutter_map: ^0.14.0
vector_map_tiles: ^1.4.3
@override
  Widget build(BuildContext context) {
    return FlutterMap(
        options: MapOptions(
            center: LatLng(40.632714, -106.481879),
            zoom: 9.0,
            rotationThreshold: 0,
            maxZoom: 13,
            plugins: [VectorMapTilesPlugin()],
            rotation: 0),
        layers: [
          VectorTileLayerOptions(
            theme: ProvidedThemes.lightTheme(),
            tileProviders: TileProviders({
              'openmaptiles': MemoryCacheVectorTileProvider(
                  delegate: NetworkVectorTileProvider(
                    maximumZoom: 14,
                    urlTemplate:
                        'https://api.mapbox.com/v4/mapbox.light-v10/{z}/{x}/{y}.mvt?access_token=$accessToken',
                  ),
                  maxSizeBytes: 1024 * 1024 * 2)
            }),
          )
        ]);
  }

Unhandled Exception: Cannot retrieve tile: HTTP 204

I can not load this
https://dev-tile.terraqt.com/tile/xyz/{z}/{x}/{y}.pbf?path=cfa08636-3d72-439c-a3be-de686f1ef9e1/cor101/202010/CN-511403/vectortiles

center LatLng(30.253362,103.879004)

maybe it load succeed,but not shown

E/flutter (11409): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Cannot retrieve tile: HTTP 204: https://dev-tile.terraqt.com/tile/xyz/13/6639/3156.pbf
E/flutter (11409): #0 NetworkVectorTileProvider.provide (package:vector_map_tiles/src/vector_tile_provider.dart:56:7)
E/flutter (11409):
E/flutter (11409): #1 MemoryCacheVectorTileProvider.provide (package:vector_map_tiles/src/vector_tile_provider.dart:95:15)
E/flutter (11409):
E/flutter (11409): #2 VectorTileLoadingCache._loadBytes (package:vector_map_tiles/src/cache/vector_tile_loading_cache.dart:85:15)
E/flutter (11409):
E/flutter (11409): #3 VectorTileLoadingCache._loadTile (package:vector_map_tiles/src/cache/vector_tile_loading_cache.dart:65:15)
E/flutter (11409):
E/flutter (11409): #4 VectorTileLoadingCache.retrieve (package:vector_map_tiles/src/cache/vector_tile_loading_cache.dart:38:12)
E/flutter (11409):
E/flutter (11409): #5 CachesTileProvider.provide (package:vector_map_tiles/src/stream/caches_tile_provider.dart:30:35)
E/flutter (11409):
E/flutter (11409): #6 VectorTileModel.startLoading. (package:vector_map_tiles/src/grid/tile_model.dart)
E/flutter (11409):
E/flutter (11409):

Using sprites?

Hey, I'm trying to use sprites with the theme, it works on maputnik and the light theme has

"sprite": 'https://maputnik.github.io/osm-liberty/sprites/osm-liberty',

but the symbols from sprites are not being rendered for me. Is this even supported? If yes then how to use it?

And as a side note, can the key: property be added to the VectorTileLayerOptions? The TileLayerOptions has key

Self host vector server

I have some trouble since I want to use my custom tile server. I created a custom server with OpenMapTiles. Now I want to use this server in my application.

I tried to use the example file to understand better how to use the vector-map-tiles package but I retrieved some problems.

@override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        children: [
          Flexible(
            child: FlutterMap(
              options: MapOptions(
                center: LatLng(41.301710, 19.795678),
                zoom: 10,
                maxZoom: 15,
                plugins: [VectorMapTilesPlugin()]
              ),
              layers: <LayerOptions>[
                VectorTileLayerOptions(
                  theme: ProvidedThemes.lightTheme(),
                  tileProviders: TileProviders(
                    {
                      'openmaptiles': MemoryCacheVectorTileProvider(
                        delegate: NetworkVectorTileProvider(
                          urlTemplate: 'http://<my_ip>:8080/styles/basic-preview/{z}/{x}/{y}.png',
                          maximumZoom: 14
                        ),
                        maxSizeBytes: 1024 * 1024 * 2
                      ),
                    }
                  )
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

Error:

[VERBOSE-2:ui_dart_state.cc(198)] Unhandled Exception: MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io[/path_provider]())
#0      MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:165
<asynchronous suspension>
#1      getTemporaryDirectory (package:path_provider[/path_provider.dart:55:24]())
<asynchronous suspension>
#2      ByteStorage._storagePath (package:vector_map_tiles[/src/cache/byte_storage.dart:20:25]())
<asynchronous suspension>
#3      ByteStorage.fileOf (package:vector_map_tiles[/src/cache/byte_storage.dart:32:18]())
<asynchronous suspension>
#4      ByteStorage.write (package:vector_map_tiles[/src/cache/byte_storage.dart:42:18]())
<asynchronous suspension>
#5      StorageCache.put (package:vector_map_tiles[/src/cache/storage_cache.dart:39:5]())
<asynchronous suspension>
#6      VectorTileLoadingCache._loadBytes (package:vector_map_tiles[/src/cache/vector_tile_loading_cache.dart:87:7]())
<asynchronous suspension>

I'm posting also the Tileserver-gl since is just a debug server to understand how to work with maps: http://46.101.253.155:8080

Switching between sources

I would like to have switching between an on-line map (pulling from an URL), and an off-line map (pulling from a mbtiles file, which does not work yet, but that is beside the point). However, simply providing different tile provider (or even a whole tile layer, see below) does not make the source switch. As suggested in #27, I tried to use different map theme keys for the two sources, but the map is still pulled from the one that was used first.

So this is basically a feature request - allow source switching, or enable clearing the caches or something like that. I can help with a PR, if pointed into the right place and direction.

This is a snipped of my code:

if (offlineMapProvider == null)
  VectorTileLayerWidget(
      options: VectorTileLayerOptions(
          tileProviders: TileProviders({
            'online': MemoryCacheVectorTileProvider(
                delegate: NetworkVectorTileProvider(
                    urlTemplate: '... here be template ...',
                    maximumZoom: 14),
                maxSizeBytes: 1024 * 1024 * 5)
          }),
          theme: ThemeReader().read(mapThemeData('online')),
          backgroundTheme: ThemeReader().readAsBackground(
              mapThemeData('online'),
              layerPredicate: defaultBackgroundLayerPredicate)))
else
  VectorTileLayerWidget(
      options: VectorTileLayerOptions(
          tileProviders: TileProviders({
            'offline': MemoryCacheVectorTileProvider(
                delegate: offlineMapProvider!,
                maxSizeBytes: 1024 * 1024 * 5)
          }),
          theme: ThemeReader().read(mapThemeData('offline')),
          backgroundTheme: ThemeReader().readAsBackground(
              mapThemeData('offline'),
              layerPredicate: defaultBackgroundLayerPredicate)))

where 'mapThemeData' produces a map theme spec with the argument used as the source.

Rendering in background isolates

After looking at how tiles are rendered and thinking a bit about how to reduce jank, I feel that vector tiles probably should not be rendered on the UI thread.

  1. Jank is not only caused by the UI isolate, but also by the raster thread.

    I suspect one factor for this is shader compilation jank. Because maps are so irregular, I'm not sure how much SkSL warm up can help here.

    The other problem is that, if multiple complex enough tiles are painted for the first time in the same frame, it just takes too long to raster them.

  2. Rendering tiles to images often blocks the UI thread.

    This could be offloaded to a background isolate, but we would need to have copies of themes, tilesets and all the cached data in the UI isolate and the background isolate.

Proposal

Each Tileset gets its own isolate, which is used to read it, preprocess it and render it to images at different zoom levels.
This parallelizes all the stages of processing.

ui.Images cannot be passed between isolates. They have to be encoded in one isolate and decoded in the other.
The raw TypedData itself can be transferred between isolates without copying. It is an open question how much of a performance penalty encoding and decoding ui.Images imposes.

The UI isolate just schedules tiles to be rendered when necessary and composes the images.

The TileImageProvider provides a simple interface for the UI isolate to access cached images and request rendering of new ones:

/// The data that describes the contents of a rendered tile image.
///
/// Two tile images with the same [TileImageDescriptor] must have identical contents.
abstract class TileImageDescriptor {
  /// The id of the theme the tile was rendered with.
  String get themeId;

  /// The zoom level at which the tile was rendered.
  ///
  /// The zoom level must be >= 0.
  double get zoom;

  /// The x coordinate of the rendered tile.
  int get x;

  /// The y coordinate of the rendered tile.
  int get y;

  /// The width and hight of the rendered image, in physical pixels.
  int get size;
}

/// The image of a rendered tile.
abstract class TileImage {
  /// Describes the contents of this image.
  TileImageDescriptor get descriptor;

  /// The actual image of the tile.
  ///
  /// Don't dispose this image. This is handled by [release].
  ui.Image get image;

  /// Retains this image.
  ///
  /// An image must only used while it is retained.
  void retain();

  /// Releases this image.
  ///
  /// An image must be released when it is no longer needed.
  void release();
}

/// Provides images of rendered tiles.
abstract class TileImageProvider {
  /// Returns the immediately available rendered tile images.
  ///
  /// An image from the returned list must be retained before it can be used.
  List<TileImage> get images;

  /// Returns the rendered tile image with given [descriptor].
  ///
  /// The returned image is already retained and must be released by the caller.
  Future<TileImage> requestImage(TileImageDescriptor descriptor);
}

Both background isolates and rendered images can be cached. The caching policy can make decisions based on which tile images are being retained/released.

I have not though it all through, but this approach would make it practically impossible for map rendering to cause jank.

Performance tweaks

Just noting a few performance issues I've hit in the past, and listing them could be useful for any thoughts on performance improvements here as well, either that we've found, or could be useful in future.

Things that I've spotted that can make a big difference.

TextPainters can be very slow to initialise, they are quite expensive, so it's good to avoid those being initialised every frame. If those can be cached, it can make a big difference. Iirc they can't be reused without recalculation if they have to be rescaled, but if they stay the same size on screen, they should be able to be reused.

Paths with a strokeWidth of > 1px are very slow in flutter (possibly with the combination of a transform). I've raised this before, and hairline strokes have a very fast algorithm, so they can be preferred in some places (especially if pinchzooming). I've never found a good solution to this though, other than slightly hacky solutions.

Removing the amount of labels (probably by some collision detection or other strategy, as well as styling).

Checking shouldRepaint is set correctly (note even if repaint is false, when scaling, there is some form of recalculation behind the scenes which can be slow)

Using RepaintBoundary on tiles/canvases etc.

consider removing RenderMode.mixed and RenderMode.raster

I'd like to consider removing raster-based rendering since with recent performance improvements, it's not clear that it offers any benefit.

By removing support for raster-based rendering we will no longer require users to understand what it is and how to choose a RenderMode option, or to decide how much memory and disk space to allocate to image storage. We also stand to benefit by dropping significant complexity from the codebase.

RenderMode (raster,mixed) was created as a way to work around performance problems that caused jank in the UI, especially while zooming. Both of these modes render tiles to raster images, which are expensive to create, occupy a lot of memory, and require significant disk space for caching.

It is somewhat ironic that these render modes are intended to improve performance but require a lot more computation. What makes it even worse is that raster images must be rendered on the UI thread, leaving less time for rendering UI frames. In the case of mixed mode, apps must render both vectors and images, more than doubling the work required.

This is a proposal to remove RenderMode completely, so that tiles are only rendered one way. See branch flutter-vector-map-tiles/tree/vector-only for what it could look like.

I've opened this issue in case there is any feedback from the community. Do you use RenderMode mixed or raster? If so, why do you prefer that over vector mode? Any and all feedback is appreciated!

Theme switching

Hi I have this setup, where I am switching a vector map or an orthophoto map with a vector overlay, switching doesn't really work. Everything rendes good when the default value is there. But when I switch, the vector layer doesnt switch the theme and keep loading the theme by the initially loaded theme, while my raster layer turns on off as it should. if I hardcodedly change the initial value everything is good.

layers: <LayerOptions>[
        if (widget.isMap)
          VectorTileLayerOptions(
              maximumZoomDifference: 2,
              theme: MapThemes.terrainTheme(),
              tileProviders: TileProviders(
                  {'openmaptiles': _cachingTileProvider(_urlTemplate())})),
        if (!widget.isMap)
          TileLayerOptions(
            opacity: widget.isMap ? 0 : 0.5,
            urlTemplate: "http://localhost:5232/map/{z}/{y}-{x}.jpg",
                        tileProvider: NonCachingNetworkTileProvider(),
          ),
        if (!widget.isMap)
          VectorTileLayerOptions(
              maximumZoomDifference: 2,
              theme: MapThemes.transparentTheme(),
              tileProviders: TileProviders(
                  {'openmaptiles': _cachingTileProvider(_urlTemplate())})),
]

FLUTTER_MAP: Bump version to v1.0.0

Hi there,

'flutter_map' v1.0.0 has just been released with a few breaking changes but many new features, fixes, and performance improvements. Please consider updating your plugin to make it more accessible to users!

If you want to join the new Discord server, either just because, or because you want to offer more support to your users, just join using the link on the README. Please ping me and I'll give you the plugin maintainer role and access to a plugin support channel :)

Many thanks,
'flutter_map' maintainer (Luka S)

Question: How to use MapTiler

Hello,

I'm trying to use this plugin to display MapTiler vector map with FlutterMap.
But the map isn't displayed properly.

My code is below:

code
FlutterMap(
  options: MapOptions(
    center: latlng.LatLng(latitude, longitude),
    zoom: 16.0,
    enableScrollWheel: true,
    enableMultiFingerGestureRace: false,
    interactiveFlags: InteractiveFlag.pinchMove |
        InteractiveFlag.drag |
        InteractiveFlag.pinchZoom,
    minZoom: 1,
    maxZoom: 20,
    plugins: [VectorMapTilesPlugin()],
  ),
  layers: [
    VectorTileLayerOptions(
      tileProviders: TileProviders({
        "openmaptiles": NetworkVectorTileProvider(
          urlTemplate:
              "https://api.maptiler.com/tiles/jp-mierune/{z}/{x}/{y}.pbf?key=${myKey}",
        ),
      }),
      theme: ProvidedThemes.lightTheme(),
    ),
  ],
),

And the error message is below:

error message
[VERBOSE-2:ui_dart_state.cc(198)] Unhandled Exception: InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag.
#0      CodedBufferReader.checkLastTagWas (package:protobuf/src/protobuf/coded_buffer_reader.dart:32:7)
#1      CodedBufferReader.readUnknownFieldSetGroup (package:protobuf/src/protobuf/coded_buffer_reader.dart:80:5)
#2      UnknownFieldSet.mergeFieldFromBuffer (package:protobuf/src/protobuf/unknown_field_set.dart:70:30)
#3      UnknownFieldSet.mergeFromCodedBufferReader (package:protobuf/src/protobuf/unknown_field_set.dart:87:24)
#4      CodedBufferReader.readUnknownFieldSetGroup (package:protobuf/src/protobuf/coded_buffer_reader.dart:79:21)
#5      UnknownFieldSet.mergeFieldFromBuffer (package:protobuf/src/protobuf/unknown_field_set.dart:70:30)
#6      _mergeFromCodedBufferReader (package:protobuf/src/protobuf/coded_buffer.dart:42:38)
#7      GeneratedMessage.mergeFromBuffer (package:protobuf/src/protobuf/generated_message.dart:185:5)
#8      new VectorTile.fromBuffer (package:vector_tile/raw/proto/vector_tile.pb.dart:340:128)
#9      VectorTile.fromBytes (package:vector_tile/vector_tile.dart:29:33)
#10     VectorTileReader.read.<anonymous closure> (package:vector_tile_renderer/src/vector_tile_reader.dart:10:25)
#11     Timeline.timeSync (dart:developer/timeline.dart:157:22)
#12     profileSync (package:vector_tile_renderer/src/profiling.dart:16:19)
#13     VectorTileReader.read (package:vector_tile_renderer/src/vector_tile_reader.dart:9:12)
#14     _createTile (package:vector_map_tiles/src/cache/vector_tile_loading_cache.dart:101:44)
#15     _Job.apply (package:vector_map_tiles/src/executor/queue_executor.dart:96:59)
#16     QueueExecutor._runOneAndReschedule (package:vector_map_tiles/src/executor/queue_executor.dart:51:34)
#17     _rootRun (dart:async/zone.dart:1418:47)
#18     _CustomZone.run (dart:async/zone.dart:1328:19)
#19     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#20     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
#21     _rootRun (dart:async/zone.dart:1426:13)
#22     _CustomZone.run (dart:async/zone.dart:1328:19)
#23     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#24     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
#25     _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
#26     _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)

If you have any clue, I'm very happy to hear that.

how to get pbf from this url ?

this is url template i got from my map provider to get pbf :
https://map.ir/vector/xyz/1.0.0/Shiveh:Vector@EPSG:900913@pbf/13/5268/3224.pbf

can you help me to convert this url to something that work with your package ?

Running example

Hi, I'm trying to run the example project with mapbox layer, using the url template 'https://api.mapbox.com/v4/mapbox.mapbox-streets-v8/{z}/{x}/{y}.mvt?access_token=$MY_TOKEN'; but I don't see the map as it should be, I see the same thing no matter what url I put (tried the stadia one too) there, and there are no errors at all in console and I only see this:
Simulator Screen Shot - iPhone 12 Pro Max - 2021-09-20 at 16 44 28

Am I doing something wrong? How to make the vector tiles work? Tried both android and iOS and the same thing.

Can't render Mapbox tiles

Hi, I've been playing around with this plugin for the last few days (and am really excited about it!), but I had a question around Mapbox support. With the given example, I'm able to successfully render a map with the Stadia Maps URL. However, when I try to use the Mapbox URL, it doesn't seem to render the tiles. I don't see any errors to the console. I was wondering if this is a known issue and/or if anyone has have any ideas to fix this.

Repro steps:

  1. Download the example.
  2. Add your Stadia Maps access token to the Stadia Maps URL in main.dart.
  3. Change the zoom level to 15 (so that we should see streets and names on the initial render).
  4. Run the application. I've encountered this issue on both Mac and Android (the only platforms I've tried).
  5. See that it renders the map correctly.

Screen Shot 2022-01-07 at 11 07 09 AM

  1. Close the application and clear the cache. On Android, I'm doing this by long pressing on the app icon and navigating to "clear storage." On Mac, I'm doing this by deleting the "example" folder at ~/Library/Containers/.
  2. Comment out the Stadia Maps URL, uncomment the Mapbox URL, and add your access token.
  3. Run the application again.
  4. See that streets/names don't show up.

Screen Shot 2022-01-07 at 11 11 23 AM

InvalidProtocolBufferException: Protocol message tag had invalid wire type

I'm using tilemaker to generate vector tiles from .pbf datasets that can be downloaded from Geofabrik.
tilemaker claims to produce vector tiles in the Mapbox format, but the flutter_vector_map_tiles package does not seem to be able to parse them.
Any ideas on how I could debug this?

Example vector tile generated by tilemaker

example_vector_tile.zip

Code

import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:vector_map_tiles/vector_map_tiles.dart';
// ignore: depend_on_referenced_packages
import 'package:vector_tile_renderer/vector_tile_renderer.dart' show ProvidedThemes;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Vector Map',
      home: MapView(),
    );
  }
}

class MapView extends StatelessWidget {
  const MapView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => FlutterMap(
        options: MapOptions(
          center: LatLng(46.933849942685754, 7.424258598204977),
          zoom: 13.0,
          plugins: [
            VectorMapTilesPlugin(),
          ],
        ),
        layers: [
          VectorTileLayerOptions(
            theme: ProvidedThemes.lightTheme(),
            tileProviders: TileProviders({
              'openmaptiles': AssetTileVectorProvider(),
            }),
          ),
        ],
      );
}

class AssetTileVectorProvider extends VectorTileProvider {
  @override
  int get maximumZoom => 19;

  @override
  Future<Uint8List> provide(TileIdentity tile) {
    return rootBundle
        .load("assets/vector_tiles/${tile.z}_${tile.x}_${tile.y}.pbf")
        .then((value) => value.buffer.asUint8List());
  }
}

Unable to run on Chrome(Web)

Getting following exception

Uncaught (in promise) Error: MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io/path_provider) at Object.throw_ [as throw] (errors.dart:236) at platform_channel.MethodChannel.new._invokeMethod (platform_channel.dart:156) at _invokeMethod.next (<anonymous>) at async_patch.dart:45 at _RootZone.runUnary (zone.dart:1612) at _FutureListener.thenAwait.handleValue (future_impl.dart:152) at handleValueCallback (future_impl.dart:704) at Function._propagateToListeners (future_impl.dart:733) at _Future.new.[_completeWithValue] (future_impl.dart:539) at async._AsyncCallbackEntry.new.callback (future_impl.dart:577) at Object._microtaskLoop (schedule_microtask.dart:40) at _startMicrotaskLoop (schedule_microtask.dart:49) at async_patch.dart:166

Performance improvement for tablet

Hello,

We are currently using flutter_map with raster maps from mapbox. But in order to reduce our mapProvider cost we are planning to deploy our own server. Which led us to explore the idea of only serving vectors and let the client app do the rendering.

To that objective I knew about your plugin, problem is our users are using tablets. I saw you wrote in the readme about the performance issues on tablet (that I tested too).

We really need a vector map that works well for our project. So I am down to try and help finding ways to improve performance, either on your repo or on a fork.

Do you have any ressources, blogs, lines of code pointing to where you think there is improvement possible ?

Thanks in advance

eliminate flicker when zooming

When zooming in/out there is sometimes a brief moment when tiles have no tile data, so the map is repainted with the background colour. The visual effect is a brief moment when the whole map is blank, which is a disorienting effect.

WFS?

This may be a dumb question due to not understanding vector formats well. But would it be possible to extend this tool to deal with wfs services?

investigate excessive memory usage while zooming

Memory usage can spike occasionally while zooming. Sometimes it's severe enough for iOS to terminate the app.

I can reproduce this on the example app by zooming in/out in an area such as Los Angeles or San Francisco where there is a lot of detail on the map.

Valid theme for the Vectory Layer

I have issues getting the example running, it looks like

_mapTheme(BuildContext context) {
// maps are rendered using themes
// to provide a dark theme do something like this:
// if (MediaQuery.of(context).platformBrightness == Brightness.dark) return myDarkTheme();
return ProvidedThemes.lightTheme();
}

doesn't return a correct Theme, as the code throws this:

[VERBOSE-2:shell.cc(103)] Dart Unhandled Exception: NoSuchMethodError: The getter 'id' was called on null.
Receiver: null

Can you give add myDarkTheme() to the example ?

Example on hillslade version

Hi,

I am having some difficulties how to implement hillslade example. I have a custom theme but when I try to use it resulting output is nothing like what is shown in studio.mapbox.com. Can you help me with this? I have set up map like in the example and have a similar url but the result is almost all white.

Thank you

Does not render symbol

Hello again, btw I wanna say huge thanks to you for the performance improvements you made. We're back on flutter map since we need labels on polyline, which Gmaps can't do.

We have a problem now with rendering POI and other symbols. For example it does not render house number
{ "id": "housenumber", "type": "symbol", "source": "openmaptiles", "source-layer": "housenumber", "minzoom": 17, "layout": {"text-field": "{housenumber}", "text-size": 6} },

It does work on maputnik, but not on your code. Do you know if it's a bug or just not implemented ?

improve visual while tiles are loading

A mechanism is present to use alternative tiles if the needed tile isn't available, however it's not reliable. While zooming there is occasionally a missing tile which results in a flash of background color to the user. The alternative selection relies on map coordinates, zoom and scale factor. Occasionally when a tile is present in the cache with the appropriate coordinates, it is missed.

Throw Invalid tile coordinates z=1,x=0,y=2 error with esri map

Hi I am tryin to load esri map using flutter-vector-map-tiles, I am using the same example code as well. But map is not rendering at all in application. It just show blank screen. Could you tell me what was the issue here.
Code:

import 'package:flutter/material.dart' as material;
import 'package:flutter/widgets.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:vector_map_tiles/vector_map_tiles.dart';
import 'package:vector_tile_renderer/vector_tile_renderer.dart';
import 'api_key.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({material.Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return material.MaterialApp(
      title: 'vector_map_tiles Example',
      theme: material.ThemeData.light(),
      home: const MyHomePage(title: 'vector_map_tiles Example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return material.Scaffold(
        appBar: material.AppBar(
          title: Text(widget.title),
        ),
        body: SafeArea(
            child: Column(children: [
          Flexible(
              child: FlutterMap(
            options: MapOptions(
                center: LatLng(12.925007, 77.593803),
                zoom: 2,
                maxZoom: 18,
                interactiveFlags: InteractiveFlag.drag |
                    InteractiveFlag.flingAnimation |
                    InteractiveFlag.pinchMove |
                    InteractiveFlag.pinchZoom |
                    InteractiveFlag.doubleTapZoom,
                plugins: [VectorMapTilesPlugin()]),
            layers: <LayerOptions>[
              // normally you would see TileLayerOptions which provides raster tiles
              // instead this vector tile layer replaces the standard tile layer
              VectorTileLayerOptions(
                  theme: _mapTheme(),
                  backgroundTheme: _backgroundTheme(),
                  // tileOffset: TileOffset.mapbox, enable with mapbox
                  tileProviders: TileProviders(
                      // Name must match name under "sources" in theme
                      {'esri': _cachingTileProvider(_urlTemplate())})),
            ],
          ))
        ])));
  }

  VectorTileProvider _cachingTileProvider(String urlTemplate) {
    return NetworkVectorTileProvider(
        urlTemplate: urlTemplate,
        // this is the maximum zoom of the provider, not the
        // maximum of the map. vector tiles are rendered
        // to larger sizes to support higher zoom levels
        maximumZoom: 18);
  }

  Theme _mapTheme() {
    // maps are rendered using themes
    // to provide a dark theme do something like this:
    // if (MediaQuery.of(context).platformBrightness == Brightness.dark) return myDarkTheme();
    return ProvidedThemes.lightTheme();
  }

  _backgroundTheme() {
    return _mapTheme()
        .copyWith(types: {ThemeLayerType.background, ThemeLayerType.fill});
  }

  String _urlTemplate() {
    // IMPORTANT: See readme about matching tile provider with theme

    // Stadia Maps source https://docs.stadiamaps.com/vector/
    return 'https://basemaps.arcgis.com/arcgis/rest/services/OpenStreetMap_v2/VectorTileServer/tile/{z}/{y}/{x}.pbf?token=$apiKey';

    // Mapbox source https://docs.mapbox.com/api/maps/vector-tiles/#example-request-retrieve-vector-tiles
    // return 'https://api.mapbox.com/v4/mapbox.mapbox-streets-v8/{z}/{x}/{y}.mvt?access_token=$mapboxApiKey',
  }
}

Output:

Blank screen with log:   
E/flutter (16275): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: Invalid tile coordinates z=1,x=0,y=2
E/flutter (16275): #0      NetworkVectorTileProvider.provide (package:vector_map_tiles/src/vector_tile_provider.dart:42:7)
E/flutter (16275): #1      VectorTileLoadingCache._loadBytes (package:vector_map_tiles/src/cache/vector_tile_loading_cache.dart:85:44)
E/flutter (16275): <asynchronous suspension>
E/flutter (16275): #2      VectorTileLoadingCache._loadTile (package:vector_map_tiles/src/cache/vector_tile_loading_cache.dart:65:15)

memory leak

memory usage grows unreasonably as the map is zoomed/panned, especially in dense areas such as London

Improvement of tile caching

This is just a rough idea I had today while working with some sqlite data. I felt like sharing this here, although the impact might be insignificant and as well has a low priority for the project.

At the moment the project uses the standard filesystem for caching tiles. As performance is always an topic here, we might can squeeze out some time for read/write operations, and have the option to add some more metadata to cached tiles, for example ttl, or preprocessed render data.

There is a great package that thinly wraps around sqlite using ffi (https://pub.dev/packages/sqlite3) which supports all platforms, including web (experimental).

There are some benchmarks comparing sqlite to fs performance like https://www.sqlite.org/intern-v-extern-blob.html and https://www.sqlite.org/fasterthanfs.html

Mapbox has a specification for storing tilesets inside an sqlite database https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md which might could get applied.

Benefits of sqlite:

  1. Very portable, tiles could be bundled server-side and delivered as a single database for e.g. offline-use
  2. Storing additional metadata like cache ttl, or preprocessed render data
  3. Possible improvement of reading or writing tiles
  4. Could bring some additional features/securities with locks, when working with isolates and having parallel operations

MBTiles Support

Hi and thanks for the plugin. Unfortunately I did not find anything in the documentation, but does this plugin also support the use of offline MBTiles?

FLUTTER_MAP RELATIONS: New Documentation

This message has been sent to multiple plugin authors, so it is not personalised

As part of fleaflet/flutter_map#992 & fleaflet/flutter_map#927 (reply in thread), I (a documentation author) am contacting plugin authors to ensure the information about this plugin on the new documentation is correct; or alternatively, if this plugin is not yet on the existing list, to check whether you would like to add your plugin to the new documentation.

I would also like you to check you conform to these new rules:

  • this plugin is available via a pub.dev installation to make it easier for developers - if your plugin does not currently have a pub.dev page, please add one or let me know otherwise,
  • the plugin documentation includes enough information for installation and basic setup/functionality,
  • the plugin includes a runnable example and/or screenshots,
  • the plugin description contains the words ' - IN BETA' after the author link on the same line if your plugin is in beta,

Currently I have copied over the existing plugin descriptions, and you can see these here: https://flutter-map.vercel.app/plugins/list. Please note that this documentation is currently unapproved and should not be used unless otherwise directed, as some information may be incorrect or missing, or might change in the future. There is no ETA at the moment, but things seem to be moving along.

Should you wish for the description to remain the same as current on the page linked above, you do not have to reply, you can close this issue.

If you wish to change any information, please leave this issue open and add your reply as a comment.

flutter_map maintainers do not take any responsibility for this message, I am the sole author.

On behalf of myself and the flutter_map community thank you for your excellent plugin :).

Widget support

Hi, is there a plan to support not only layer VectorTileLayerOptions but also to have a VectorTileLayerWidget that will accept options, same as every other layer has in the flutter_map?
This will help a lot with building custom map abstractions

urlTemplate does not get updated with setState

I ran into an issue that when I setState on my stateful widget (which contains FlutterMap which uses a vector tile layer). I have the url template stored in a variable which can change (e.g. different tile providers). However, when I change the url template in setState, the NetworkVectorTileProvider still uses the old url.

Example

It is identical to the example provided in this repo except for a few changes:

  • there are two constants and one field in _MyHomePageState:
    • constant urlGood is a working url template
    • constant urlBad is a non-working url template
    • field good is a switch choosing one of those urls
  • _urlTemplate returns one of the two urls based on the value of good
  • there is a leading icon button in the app bar which toggles between the two urls
  • the app bar title shows the used url

If the app is started with good = false, the map does not load the tiles, which is correct. When I tap the button, the url should switch, which it does as indicated by the change of the app bar title, but the map tiles still don't load. To make the change, I need to change it to good = true in the code and (hot)restart the app.

Source code (my stadiamaps api key redacted):

import 'dart:developer' as developer;
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:vector_map_tiles/vector_map_tiles.dart';
import 'package:vector_tile_renderer/vector_tile_renderer.dart';
// ignore: implementation_imports
import 'package:vector_tile_renderer/src/themes/light_theme.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'vector_map_tiles Example',
      theme: ThemeData.light(),
      home: MyHomePage(title: 'vector_map_tiles Example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static const String urlGood = 'https://tiles.stadiamaps.com/data/openmaptiles/{z}/{x}/{y}.pbf?api_key=...';
  static const String urlBad = 'http://localhost:12345/tileserver/map/tiles/{z}/{x}/{y}.pbf';
  bool good = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(_urlTemplate()),
          leading: IconButton(
            onPressed: () => setState(() {
              good = !good;
            }),
            icon: Icon(Icons.swap_horiz),
          ),
        ),
        body: SafeArea(
            child: Column(children: [
          Flexible(
              child: FlutterMap(
            options: MapOptions(
                center: LatLng(49.246292, -123.116226),
                zoom: 10,
                maxZoom: 18,
                interactiveFlags: InteractiveFlag.drag |
                    InteractiveFlag.flingAnimation |
                    InteractiveFlag.pinchMove |
                    InteractiveFlag.pinchZoom |
                    InteractiveFlag.doubleTapZoom,
                plugins: [VectorMapTilesPlugin()]),
            layers: <LayerOptions>[
              // normally you would see TileLayerOptions which provides raster tiles
              // instead this vector tile layer replaces the standard tile layer
              VectorTileLayerOptions(
                  theme: _mapTheme(),
                  backgroundTheme: _backgroundTheme(),
                  tileProviders: TileProviders(
                      {'openmaptiles': _cachingTileProvider(_urlTemplate())})),
            ],
          ))
        ])));
  }

  VectorTileProvider _cachingTileProvider(String urlTemplate) {
    return MemoryCacheVectorTileProvider(
        delegate: NetworkVectorTileProvider(
            urlTemplate: urlTemplate,
            // this is the maximum zoom of the provider, not the
            // maximum of the map. vector tiles are rendered
            // to larger sizes to support higher zoom levels
            maximumZoom: 14),
        maxSizeBytes: 1024 * 1024 * 2);
  }

  _mapTheme() {
    // maps are rendered using themes
    // to provide a dark theme do something like this:
    // if (MediaQuery.of(context).platformBrightness == Brightness.dark) return myDarkTheme();
    return ProvidedThemes.lightTheme();
  }

  _backgroundTheme() {
    return ThemeReader().readAsBackground(lightThemeData(),
        layerPredicate: defaultBackgroundLayerPredicate);
  }

  String _urlTemplate() {
    // Stadia Maps source https://docs.stadiamaps.com/vector/
    // ignore: undefined_identifier
    return good ? urlGood : urlBad;

    // Mapbox source https://docs.mapbox.com/api/maps/vector-tiles/#example-request-retrieve-vector-tiles
    // return 'https://api.mapbox.com/v4/mapbox.mapbox-streets-v8/{z}/{x}/{y}.mvt?access_token=$apiKey',
  }
}

Plugin Extensions

Hello,

Thanks a lot for the great flutter plugin!

Do you plan to support a web version? how about caching?
Any parameters that one can use in order to improve performance? --> Update: see this point was already addressed here, I will give it a try

Many Thanks,

Custom Style

it will be great if we have an option to customize color style

Street names not correctly displayed at certain zoom-levels

I was exploring around on the map with the example application (native Linux).
Some street names are displayed incorrectly at certain zoom levels:

image

Is this a hard to tackle problem (I haven't had the time to look at the code or the rendering of the tiles s far...)?
Are there other known issues at the moment (I understand the package is in early stage)?

improve support for overzooming

Some vector tile servers only supply tiles up to zoom level 14, however it's desirable to be able to display maps at higher zoom levels. Mapping libraries commonly support rendering tiles at a higher zoom level so that it's possible to zoom in further. This is called overzooming.

This library supports overzooming, however overzooming by several levels can cause excessive memory usage to the point of crashing the application as described in issue #24.

The investigation in issue #24 revealed that memory usage was driven by raster picture memory usage, increasing exponentially with overzoom level. In testing, I found that overzooming had to be limited to 2 levels to keep memory usage within reasonable limits imposed by mobile devices (~2GB)

Digging deeper, I discovered that line data in vector tiles can extend far beyond the tile boundary. In one example, with a tile having a size of 4096, I observed at least one line extending to an offset of 58,000. It's likely that tile servers are clipping lines based on line segment points, rather than trimming lines to the tile boundary.

In an experiment I was able to determine that applying a clip to lines and dropping polygons and points that do not intersect the clip bounds resulted in stable memory usage. Ad-hoc testing has shown raster picture memory usage < 80MB even when zooming up to level 22 on a level 14 tile.

Clipping is CPU-intensive, so could potentially contribute to lag or jank. Further, the approach taken in the experiment causes an intermediary tile model to be created which further adds to computational overhead, both by creating the model and in GC. Some of this overhead can be alleviated by performing model calculations on a non-UI isolate. More investigation is needed to determine whether CPU overhead can be reduced further.

Though the approach has proven promising, it's possible that it doesn't fully solve the problem. Since polygons are not reshaped as part of the clipping process, it's possible (for example) that a large polygon extending into the clip bounds only partially could cause high memory usage as previously observed with lines. I haven't encountered such an issue in testing, however it may be that I got lucky with the tile data that I used. Alternatively, it's possible that Canvas-native clipping works better with polygons than it does with lines. Further testing is needed to determine if the problem is fully resolved with the clipping approach in its current form.

Anyone interested in trying out this experiment will need the following branches:

Vector tile without background.

I would like to display a vector tile map, which displays some polygons and I need to display them on top of other layers because. If it was just a tilelayeroptions object, I could pass a background color argument and make it transparent. Is there any way to make it like that in vector tiles too?

image

unexpected separation between tiles

from issue #2:

when I looked at the last version there were hairline gaps between the tiles. I think I had similar, which was typically either anti-aliasing needed turning off, or rounding on the tile/canvas positioning.

Web support

Thank for this much needed package. But one platform is surely missing. Is web support planned? What are the blocking limitations?

Performance issues

Hi there,

first kudos, its amazing someone finally took to implement native vector maps for Flutter,

unfortunately, I just tried this package with our own tiles and I am having serious performance issues, basically the map freezes and I am unable to interact with it, after every zoom change/movement, for a few seconds.

This happens both in debug mode (Android emulator/device) and release mode.

Our config: https://gist.github.com/filipproch/a010f95fcab7a559ab3074c3ebd0e290
We use the map mostly over Czech Republic - Europe

I would like to contribute to help improve this, but not sure where exactly to look/start
or maybe you already have some ideas for performance improvements?

Artifacts between tiles

I checked out the example project and added my custom urlTemplate and style.
The map renders streets and text, but the tiles is cutting off content.

image

Here is the code:

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:latlong2/latlong.dart';
import 'package:map_test/dark_theme.dart';
import 'package:vector_map_tiles/vector_map_tiles.dart';
import 'package:vector_tile_renderer/src/themes/light_theme.dart';
import 'package:vector_tile_renderer/vector_tile_renderer.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _isDarkMode = true;
  final _lightTheme = ThemeReader().read(lightThemeData());
  final _darkTheme = ThemeReader().read(darkThemeData);

  static const urlTemplate =
      "https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/tile/{z}/{x}/{y}.pbf";

  @override
  Widget build(BuildContext context) {
    final centerMunich = LatLng(48.129710, 11.586124);

    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            onPressed: () => setState(() => _isDarkMode = !_isDarkMode),
            icon: Icon(_isDarkMode ? Icons.dark_mode : Icons.light_mode),
          ),
        ],
      ),
      body: FlutterMap(
        options: MapOptions(
          center: centerMunich,
          zoom: 13.0,
          plugins: [VectorMapTilesPlugin()],
        ),
        layers: [
          VectorTileLayerOptions(
            theme: _isDarkMode ? _darkTheme : _lightTheme,
            tileProviders: TileProviders(
              {
                'esri': MemoryCacheVectorTileProvider(
                  delegate: NetworkVectorTileProvider(
                    urlTemplate: urlTemplate,
                    maximumZoom: 14,
                  ),
                  maxSizeBytes: 1024 * 1024 * 2,
                ),
              },
            ),
          ),
          MarkerLayerOptions(
            markers: [
              Marker(
                width: 80.0,
                height: 80.0,
                point: centerMunich,
                builder: (ctx) => Icon(
                  Icons.location_on_outlined,
                  color: _isDarkMode ? Colors.white : Colors.black,
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

Here is the json for the dark theme:
The content for final _darkTheme = ThemeReader().read(darkThemeData); can be found here:
https://gist.github.com/JulianBissekkou/527d0ade9d4d0a87af9fc9198ad5f94a

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.