Getting started with Flutter Maps (SfMaps)

5 May 202116 minutes to read

This section explains the steps required to add the maps widget with shape layer and its elements such as data labels, tooltip, assignable colors based on region, and legends. It also explains about adding tile layer with OpenStreetMap. This section covers only basic features needed to know to get started with Syncfusion maps.

To get start quickly with our Flutter Maps widget, you can check on this video.

Add Flutter maps to an application

Create a simple project using the instructions given in the Getting Started with your first Flutter app documentation.

Add dependency

Add the Syncfusion Flutter maps dependency to your pubspec.yaml file.

  • dart
  • dependencies:
    
    syncfusion_flutter_maps: ^xx.x.xx

    NOTE

    Here xx.x.xx denotes the current version of Syncfusion Flutter Maps package.

    Get packages

    Run the following command to get the required packages.

  • dart
  • $ flutter pub get

    Import package

    Import the following package in your Dart code.

    import 'package:syncfusion_flutter_maps/maps.dart';

    Initialize maps

    After importing the package, initialize the maps widget as a child of any widget.

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Center(
          child: SfMaps(),
        ),
      );
    }

    Set GeoJSON data for shape layer from various source

    The layers in SfMaps contains collection of either MapShapeLayer or MapTileLayer. The actual geographical rendering is done in the each MapShapeLayer. The source property of the MapShapeLayer is of type MapShapeSource. The source can be set as the .json source from an asset bundle, from network or from Uint8List as bytes. Use the respective constructor depends on the type of the source.

    The shapeDataField property of the MapShapeSource is used to refer the unique field name in the .json source to identify each shapes. In Mapping the data source section of this document, this shapeDataField will be used to map with respective value returned in primaryValueMapper from the data source.

    From asset bundle

    Load .json data from an asset bundle.

    NOTE

    If you are using the MapShapeSource.asset constructor, you must add the .json file to the assets folder of your root directory and refer the json file path in the pubspec.yaml file as shown in the below code snippet. You can get the australia.json file here.

    flutter:
      uses-material-design: true
      assets:
        - australia.json
    late MapShapeSource _dataSource;
    
    @override
    void initState() {
      _dataSource = MapShapeSource.asset(
        'assets/australia.json',
        shapeDataField: 'STATE_NAME',
      );
      super.initState();
    }
    
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Padding(
          padding: EdgeInsets.all(15),
          child: SfMaps(
            layers: [
              MapShapeLayer(source: _dataSource),
            ],
          ),
        ),
      );
    }

    From network

    Load .json data from the network.

    late MapShapeSource _dataSource;
    
    @override
    void initState() {
      _dataSource = MapShapeSource.network(
        'http://www.json-generator.com/api/json/get/bVqXoJvfjC?indent=2',
         shapeDataField: 'name',
      );
      super.initState();
    }
    
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Padding(
          padding: EdgeInsets.all(15),
          child: SfMaps(
            layers: [
              MapShapeLayer(source: _dataSource),
            ],
          ),
        ),
      );
    }

    From memory

    Load .json data as bytes from Uint8List.

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: FutureBuilder(
          future: _fetchJsonData(),
          builder: (BuildContext context, snapshot) {
            if (snapshot.hasData) {
              Uint8List bytesData = snapshot.data as Uint8List;
              return SfMaps(
                layers: [
                  MapShapeLayer(
                    source: MapShapeSource.memory(
                      bytesData,
                      shapeDataField: 'STATE_NAME',
                    ),
                  ),
                ],
              );
            } else {
              return CircularProgressIndicator();
            }
          },
        ),
      );
    }
    
    Future<Uint8List> _fetchJsonData() async {
      return (await rootBundle.load('assets/australia.json')).buffer.asUint8List();
    }

    maps basic view

    Mapping the data source for shape layer

    By default, the value specified for the shapeDataField in the GeoJSON source will be used in the elements like data labels, tooltip, and legend for their respective shapes. However, it is possible to keep a data source and customize these elements based on the requirement. As mentioned above, shapeDataField will be used to map with respective value returned in primaryValueMapper from the data source.

    late List<Model> data;
    
    @override
    void initState() {
      data = <Model>[
        Model('New South Wales',
         '       New\nSouth Wales'),
        Model('Queensland', 'Queensland'),
        Model('Northern Territory', 'Northern\nTerritory'),
        Model('Victoria', 'Victoria'),
        Model('South Australia', 'South Australia'),
        Model('Western Australia', 'Western Australia'),
        Model('Tasmania', 'Tasmania'),
        Model('Australian Capital Territory', 'ACT')
      ];
    
      super.initState();
    }
    
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SfMaps(
           layers: <MapShapeLayer>[
             MapShapeLayer(
               source: MapShapeSource.asset(
                 'assets/australia.json',
                 shapeDataField: 'STATE_NAME',
                 dataCount: data.length,
                 primaryValueMapper: (int index) => data[index].state,
               ),
             ),
           ],
         ),
       );
    }
    
    class Model {
      Model(this.state, this.stateCode);
    
      String state;
      String stateCode;
    }

    NOTE

    Add shape layer maps elements

    Add the basic maps elements such as data labels, legend, and tooltip as shown in the below code snippet.

    late List<Model> data;
    late MapShapeSource dataSource;
    
    @override
    void initState() {
      data = <Model>[
        Model('New South Wales', Color.fromRGBO(255, 215, 0, 1.0),
            '       New\nSouth Wales'),
        Model('Queensland', Color.fromRGBO(72, 209, 204, 1.0), 'Queensland'),
        Model('Northern Territory', Colors.red.withOpacity(0.85),
            'Northern\nTerritory'),
        Model('Victoria', Color.fromRGBO(171, 56, 224, 0.75), 'Victoria'),
        Model('South Australia', Color.fromRGBO(126, 247, 74, 0.75),
            'South Australia'),
        Model('Western Australia', Color.fromRGBO(79, 60, 201, 0.7),
            'Western Australia'),
        Model('Tasmania', Color.fromRGBO(99, 164, 230, 1), 'Tasmania'),
        Model('Australian Capital Territory', Colors.teal, 'ACT')
      ];
    
      dataSource = MapShapeSource.asset(
        'assets/australia.json',
        shapeDataField: 'STATE_NAME',
        dataCount: data.length,
        primaryValueMapper: (int index) => data[index].state,
        dataLabelMapper: (int index) => data[index].stateCode,
        shapeColorValueMapper: (int index) => data[index].color,
      );
      super.initState();
    }
    
    @override
    Widget build(BuildContext context) {
      final ThemeData themeData = Theme.of(context);
      return Scaffold(
        body: Center(
          child: SizedBox(
            height: MediaQuery.of(context).size.height * 0.55,
            child: SfMaps(
              layers: <MapShapeLayer>[
                MapShapeLayer(
                  source: dataSource,
                  showDataLabels: true,
                  legend: MapLegend(MapElement.shape),
                  shapeTooltipBuilder: (BuildContext context, int index) {
                    return Padding(
                      padding: const EdgeInsets.all(7),
                      child: Text(data[index].stateCode,
                          style: themeData.textTheme.caption!
                              .copyWith(color: themeData.colorScheme.surface)),
                    );
                  },
                  tooltipSettings: MapTooltipSettings(
                      color: Colors.grey[700],
                      strokeColor: Colors.white,
                      strokeWidth: 2),
                  strokeColor: Colors.white,
                  strokeWidth: 0.5,
                  dataLabelSettings: MapDataLabelSettings(
                      textStyle: TextStyle(
                          color: Colors.black,
                          fontWeight: FontWeight.bold,
                          fontSize: themeData.textTheme.caption!.fontSize)),
                ),
              ],
            ),
          ),
        ),
      );
    }
    
    class Model {
      Model(this.state, this.color, this.stateCode);
    
      String state;
      Color color;
      String stateCode;
    }

    Maps getting started

    Add tile layer

    The MapTileLayer needs to be added in the layers collection in SfMaps. The URL of the providers must be set in the MapTileLayer.urlTemplate property.

    Kindly refer the tile layer section for more information.

    @override
    Widget build(BuildContext context) {
      return SfMaps(
        layers: [
          MapTileLayer(
            urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
          ),
        ],
      );
    }

    Maps tile layer getting started