Easily Visualize OpenStreetMaps and Bing Maps in Flutter | Syncfusion Blogs
Detailed Blog page Skeleton loader
Easily Visualize OpenStreetMaps and Bing Maps in Flutter

The shape layer in the Syncfusion Flutter Maps widget renders geographical areas from the GeoJSON data. Another popular style of map visualization, though, is to load map tiles or images from web map tile services (WMTS) such as Bing Maps, OpenStreetMaps, Google Maps, and TomTom. We are excited to inform you that this tile layer rendering support has been included in our Syncfusion Flutter Maps widget in the Essential Studio 2020 Volume 3 release. This allows rendering tiles from these tile providers.

In this blog, we will look at the tile layer and how to add it to the Flutter Maps widget to render tiles from providers like OpenStreetMap and Bing Maps. We will also briefly talk about adding markers and enabling the zooming and panning features in the tile layer.

What is the tile layer?

The web map tile services, like OpenStreetMaps and Bing Maps, provide a single tile of 256 * 256 pixels for every request for the region we ask for. Our newly introduced tile layer does this efficiently and arranges multiple tiles in appropriate positions to render the complete map.

You can then interact with this layer to have a closer look at a specific region by pinching and then panning across the map to check the places nearby.

Tile Layer in Flutter Maps
Tile Layer in Flutter Maps

Adding an OpenStreetMap

If you are looking for a cost-effective map tile provider, then OpenStreetMap will best suit you. This is a widely used, free WMTS for mobile applications and websites, meeting the requirement of basic map rendering.

Disclaimer: OpenStreetMaps may be used free of cost. However, we recommend you check the licensing terms on their official website to make sure.

The following code example explains the procedure to add the tile layer to the Maps widget with OpenStreetMap.

@override
Widget build(BuildContext context) {
  return SfMaps(
    layers: [
      MapTileLayer(
         urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
         initialZoomLevel: 2,
         initialFocalLatLng: MapLatLng(28.644800, 77.216721),
       ),
     ],
  );
}
OpenStreetMap in Syncfusion Flutter Maps
OpenStreetMap in Syncfusion Flutter Maps

URL template

The urlTemplate property accepts the URL in WMTS format, i.e. {z} zoom level and {x} and {y} tile coordinates.

This URL might vary slightly depending on the providers. The formats can be:

https://exampleprovider/{z}/{x}/{y}.png,

https://exampleprovider/z={z}/x={x}/y={y}.png,

https://exampleprovider/z={z}/x={x}/y={y}.png?key=subscription_key, etc.

We will replace the {z}, {x}, and {y} internally based on the current focal point and the zoom level.

A subscription key may be needed for some of the providers, like Bing Maps. Please include it in the urlTemplate itself.

Note: The format may vary among map providers. You can check the exact URL format needed for the providers on their official websites.

How tiles are rendered in the tile layer

At the lowest zoom level (level 0), the map is 256 x 256 pixels and the whole world map will be rendered as a single tile. In each consecutive level, the map width and height grow by a factor of 2. So level 1 is 512 x 512 pixels with four tiles ((0, 0), (0, 1), (1, 0), (1, 1) where 0 and 1 are {x} and {y} in the urlTemplate), level 2 is 2048 x 2048 pixels with 8 tiles (from (0, 0) to (3, 3)), and so on.

However, the number of tiles needed in the current viewport alone will be requested and rendered initially. If you have enabled zooming and panning, other required tiles will be requested on demand and rendered during the interaction.

Enable zooming and panning

If you want to enable dynamic zooming and panning, please refer to the following code snippet. You can zoom in on the tile layer for a closer look at a specific region by:

  • Pinching on touch devices.
  • Scrolling the mouse wheel or trackpad.
  • Using the toolbar on the web.
MapZoomPanBehavior _zoomPanBehavior;

  @override
  void initState() {
    _zoomPanBehavior = MapZoomPanBehavior();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SfMaps(
      layers: [
        MapTileLayer(
          urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
          initialZoomLevel: 2,
          initialFocalLatLng: MapLatLng(28.644800, 77.216721),
          zoomPanBehavior: _zoomPanBehavior,
        ),
      ],
    );
  }
Zooming and Panning in the Tile Layer
Zooming and Panning in the Tile Layer
Note: MapZoomPanBehavior objects are expected to be long-lived, not recreated with each build.

While zooming and panning, new tiles will be requested and rendered. After the interaction, the current zoom level and the focal point can be obtained from the MapZoomPanBehavior.zoomLevel and MapZoomPanBehavior.focalLatLng properties, respectively. These properties can also be set dynamically.

Adding Bing Maps

Adding Bing Maps to the MapTileLayer is the same as adding OpenStreetMaps except for the way we set the urlTemplate property.

For Bing Maps, an additional step is required. The format of the required URL varies from the other tile services. So, we have added a top-level getBingUrlTemplate function that returns the URL in the required format. You can use the URL returned from this function to set it to the urlTemplate property.

A subscription key is needed for Bing Maps. It has to be added to the urlTemplate itself. Also, Bing Maps provides map types like Road, Aerial, and AerialWithLabelsOnDemand. These types, too, should be added in the urlTemplate itself, as shown in the following code example. You can check the official websites of the tile providers to learn about the available types and the code for them.

Other than these differences, everything is exactly the same among all the different types of tile providers.

@override
Widget build(BuildContext context) {
  String bingKey =
      'SUBSCRIPTION_KEY';
  return Scaffold(
    body: Center(
       child: Container(
            child: FutureBuilder(
          future: getBingUrlTemplate(
              'https://dev.virtualearth.net/REST/V1/Imagery/Metadata/AerialWithLabelsOnDemand?output=json&uriScheme=https&include=ImageryProviders&key='+bingKey),
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (snapshot.connectionState == ConnectionState.done &&
                snapshot.hasData) {
              final String urlTemplate = snapshot.data;
              return SfMaps(
                layers: [
                  MapTileLayer(
                    initialZoomLevel: 2,
                    initialFocalLatLng: MapLatLng(28.644800, 77.216721),
                    urlTemplate: urlTemplate,
                  ),
                ],
              );
            } else {
              return const Center(child: CircularProgressIndicator());
            }
          },
       )),
     ),
  );
}
Adding Bing Maps
Adding Bing Maps

Other tile providers

In addition to OpenStreetMap and Bing Maps, it is possible to render other tile providers like Google Maps or TomTom, which follow the WMTS format. For example, tiles from TomTom can be rendered like the following code.

Note: You have to append the subscription key at the end of the URL as we did for Bing Maps.

@override
Widget build(BuildContext context) {
  return SfMaps(
    layers: [
      MapTileLayer(
        urlTemplate: 'https://api.tomtom.com/map/1/tile/basic/main/{z}/{x}/{y}.png?key=SUBSCRIPTION_KEY',
        initialZoomLevel: 2,
        initialFocalLatLng: MapLatLng(28.644800, 77.216721),
      ),
    ],
  );
}

Adding markers

As in the shape layer, you can add markers in the tile layer with exactly the same approach. They can be used to denote specific latitude and longitude in the tile layer as required by the user. You can use the built-in shapes (circles, diamonds, squares, and triangles) or any type of custom widget as a marker.

The markerBuilder callback will be called the number of times the value specified in the initialMarkersCount property.

Note: If you want to dynamically add the markers, please refer to this section.

Refer to the following code example.

class _MyHomePageState extends State {
  List _data;

  @override
  void initState() {
    _data = const [
      Model('Brazil', -14.235004, -51.92528),
      Model('Germany', 51.16569, 10.451526),
      Model('Australia', -25.274398, 133.775136),
      Model('India', 20.593684, 78.96288),
      Model('Russia', 61.52401, 105.318756)
    ];

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          child: SfMaps(
            layers: [
              MapTileLayer(
                urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
                initialZoomLevel: 2,
                initialFocalLatLng: MapLatLng(28.644800, 77.216721),
                initialMarkersCount: 5,
                markerBuilder: (BuildContext context, int index) {
                  return MapMarker(
                    latitude: _data[index].latitude,
                    longitude: _data[index].longitude,
                    iconColor: Colors.white,
                    iconStrokeColor: Colors.black,
                    iconStrokeWidth: 2,
                  );
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class Model {
  const Model(this.country, this.latitude, this.longitude);

  final String country;
  final double latitude;
  final double longitude;
}
Adding Markers to the Tile Layer
Adding Markers to the Tile Layer

Conclusion

In this blog post, we walked you through the new tile layer support included in the Flutter Maps widget in our 2020 Volume 3 release. You can download the latest setup here. Try out this new feature and share your feedback in the comments section below.

Check out the complete user guide and see our samples in this GitHub location. Additionally, you can check out our demo apps on Google Play StoreApp Store, and our website.

If you need a new widget for the Flutter framework or new features in our existing widgets, you can contact us through our support forumsDirect-Trac, or feedback portal. As always, we are happy to assist you!

googleplay.png

Be the first to get updates

Mohamed Samsudeen

Meet the Author

Mohamed Samsudeen

Mohamed Samsudeen is a Product Manager for Xamarin, Flutter, WinUI, and WPF products in Syncfusion. He has been a .NET developer since 2013 who is now prominently working in creating and managing custom components for WPF and WinUI platforms.

Comments (4)

Thanks for the tutorial. I want to search in maps with names. How do I do it?

@ Usama Karim  

Hi Usama,

This functionally is not integrated into our package. However, there are many services online to achieve this. For example, you can check out the below plugin to search the address and it will return the location as latitude and longitude.

https://pub.dev/packages/geocoding

Once you got the location, you can use our `marker` feature to denote that location.
https://help.syncfusion.com/flutter/maps/markers#adding-markers

Regards,
Samsudeen

Thanks for the tutorial. Easy and simple. I have one question, can i use Syncfusion map to build offline maps.

@ Dennis  

Hi Dennis,

You can use a shape layer to build the offline maps. Currently, we don’t have offline support for Tile Layer.

https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapShapeLayer-class.html

Comments are closed.