Shapes in Flutter Maps (SfMaps)

2 Nov 202119 minutes to read

This section explains about shapes and how to apply colors to the shapes based on specific values in the Flutter maps.

Loading progress indicator

You can notify the user that the map is being loaded using the MapShapeLayer.loadingBuilder. It returns the widget which will be visible till the maps is loaded.

late MapShapeSource dataSource;

@override
void initState() {
  dataSource = MapShapeSource.asset(
    'assets/world_map.json',
    shapeDataField: 'continent',
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(15),
        child: SfMaps(
          layers: <MapLayer>[
            MapShapeLayer(
              source: dataSource,
              loadingBuilder: (BuildContext context) {
                return Container(
                  height: 25,
                  width: 25,
                  child: const CircularProgressIndicator(
                    strokeWidth: 3,
                  ),
                );
              },
            ),
          ],
        ),
      ),
   );
}

Loading builder

Shape color

You can apply color, stroke color and stroke width to the shapes using the MapShapeLayer.color, MapShapeLayer.strokeColor and MapShapeLayer.strokeWidth properties respectively.

late MapShapeSource dataSource;

@override
void initState() {
  dataSource = MapShapeSource.asset(
    'assets/world_map.json',
    shapeDataField: 'continent',
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(15),
        child: SfMaps(
          layers: <MapLayer>[
            MapShapeLayer(
              source: dataSource,
               color: Colors.blue[100],
               strokeColor: Colors.blue,
               strokeWidth: 2,
            ),
          ],
        ),
      ),
   );
}

Using SfMapsTheme

You can also customize the below appearance of the shape using SfMapsTheme.

NOTE

You must import the theme.dart library from the Core package to use SfMapsTheme.

late MapShapeSource dataSource;

@override
void initState() {
  dataSource = MapShapeSource.asset(
    'assets/world_map.json',
    shapeDataField: 'continent',
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Padding(
      padding: EdgeInsets.all(15),
      child: SfMapsTheme(
        data: SfMapsThemeData(
          layerColor: Colors.blue[100],
          layerStrokeColor: Colors.blue,
          layerStrokeWidth: 2,
        ),
        child: SfMaps(
          layers: <MapLayer>[
            MapShapeLayer(
              source: dataSource,
            ),
          ],
        ),
      ),
    ),
  );
}

Shapes color

Hover color

You can apply hover color, stroke color and stroke width to the shapes in the web platform using the SfMapsThemeData.shapeHoverColor, SfMapsThemeData.shapeHoverStrokeColor and SfMapsThemeData.shapeHoverStrokeWidth properties respectively.

NOTE

You must import the theme.dart library from the Core package to use SfMapsTheme.

late MapShapeSource dataSource;

@override
void initState() {
  dataSource = MapShapeSource.asset(
    'assets/world_map.json',
    shapeDataField: 'continent',
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Padding(
      padding: EdgeInsets.all(15),
      child: SfMapsTheme(
        data: SfMapsThemeData(
           shapeHoverColor: Colors.red[800],
           shapeHoverStrokeColor: Colors.black,
           shapeHoverStrokeWidth: 2,
        ),
        child: SfMaps(
          layers: <MapLayer>[
            MapShapeLayer(
              source: dataSource,
            ),
          ],
        ),
      ),
    ),
  );
}

Applying colors based on the data

If you return a color from the shapeColorValueMapper, then the color will be applied to the respective shape straightaway.

If you return a value of different type other than the color from the shapeColorValueMapper, then you must set the MapShapeSource.shapeColorMappers property which is a collection of MapColorMapper to apply colors for the respective shapes.

NOTE

You can show legend using the MapShapeLayer.legend property. The icons color of the legend is applied based on the colors returned in the MapShapeSource.shapeColorValueMapper property and the text will be taken from the primaryValueMapper. It is possible to customize the legend icons color and text using the MapShapeSource.shapeColorMappers property.

late List<Model> data;
late MapShapeSource dataSource;

@override
void initState() {
    data = const <Model>[
      Model('Asia', Color.fromRGBO(60, 120, 255, 0.8)),
      Model('Africa', Color.fromRGBO(51, 102, 255, 0.8)),
      Model('Europe', Color.fromRGBO(0, 57, 230, 0.8)),
      Model('South America', Color.fromRGBO(0, 51, 204, 0.8)),
      Model('Australia', Color.fromRGBO(0, 45, 179, 0.8)),
      Model('North America', Color.fromRGBO(0, 38, 153, 0.8))
    ];

    dataSource = MapShapeSource.asset(
      'assets/world_map.json',
       shapeDataField: 'continent',
       dataCount: data.length,
       primaryValueMapper: (int index) => data[index].country,
       shapeColorValueMapper: (int index) => data[index].color,
    );
    super.initState();
}

@override
Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: Container(
        height: 350,
        child: Padding(
          padding: EdgeInsets.only(left: 15, right: 15),
          child: SfMaps(
            layers: <MapLayer>[
              MapShapeLayer(
                source: dataSource,
              ),
            ],
          ),
        ),
      )),
   );
}

class Model {
  const Model(this.country, this.color);

  final String country;
  final Color color;
}

Shape color

Equal color mapping

You can apply color to the shape by comparing a value that returns from the shapeColorValueMapper with the MapColorMapper.value. For the matched values, the MapColorMapper.color will be applied to the respective shapes.

late List<Model> data;
late MapShapeSource dataSource;

@override
void initState() {
  data = <Model>[
    Model('India', "Low"),
    Model('United States of America', "High"),
    Model('Pakistan', "Low"),
  ];

  dataSource = MapShapeSource.asset(
    "assets/world_map.json",
     shapeDataField: "name",
     dataCount: data.length,
     primaryValueMapper: (int index) {
       return data[index].country;
     },
     shapeColorValueMapper: (int index) {
       return data[index].storage;
     },
     shapeColorMappers: [
       MapColorMapper(value: "Low", color: Colors.red),
       MapColorMapper(value: "High", color: Colors.green)
     ],
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.only(left: 15, right: 15),
        child: SfMaps(
          layers: <MapShapeLayer>[
            MapShapeLayer(source: dataSource),
          ],
        ),
      ),
   );
}

class Model {
  const Model(this.country, this.storage);

  final String country;
  final String storage;
}

Equal color mapping

Range color mapping

You can apply color to the shape based on whether the value returned from shapeColorValueMapper falls within the MapColorMapper.from and MapColorMapper.to. Then, the MapColorMapper.color will be applied to the respective shapes.

late List<Model> data;
late MapShapeSource dataSource;

@override
void initState() {
  data = <Model>[
    Model('India', 280),
    Model('United States of America', 190),
    Model('Kazakhstan', 37),
  ];

  dataSource = MapShapeSource.asset(
     "assets/world_map.json",
      shapeDataField: "name",
      dataCount: data.length,
      primaryValueMapper: (int index) => data[index].country,
      shapeColorValueMapper: (int index) => data[index].count,
      shapeColorMappers: [
        MapColorMapper(from: 0, to: 100, color: Colors.red),
        MapColorMapper(from: 101, to: 300, color: Colors.green)
      ],
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.only(left: 15, right: 15),
        child: SfMaps(
          layers: [
            MapShapeLayer(source: dataSource),
          ],
        ),
      ),
   );
}

class Model {
  const Model(this.country, this.count);

  final String country;
  final double count;
}

Range color mapping

Opacity

You can apply the maximum and minimum opacity to the shape or bubbles while using MapColorMapper.from and MapColorMapper.to properties.

The shapes or bubbles with lowest value which is from will be applied a minOpacity and the shapes or bubbles with highest value which is to will be applied a maxOpacity. The shapes or bubbles with values in-between the range will get a opacity based on their respective value.

late List<Model> data;
late MapShapeSource dataSource;

@override
void initState() {
  data = <Model>[
    Model('India', 280),
    Model('United States of America', 190),
    Model('Kazakhstan', 37),
  ];

  dataSource = MapShapeSource.asset(
    "assets/world_map.json",
     shapeDataField: "name",
     dataCount: data.length,
     primaryValueMapper: (int index) => data[index].country,
     shapeColorValueMapper: (int index) => data[index].count,
     shapeColorMappers: [
       MapColorMapper(
          from: 0,
          to: 100,
          color: Colors.red,
          minOpacity: 0.2,
          maxOpacity: 0.4,
       ),
       MapColorMapper(
          from: 101,
          to: 300,
          color: Colors.green,
          minOpacity: 0.4,
          maxOpacity: 0.6,
       ),
     ],
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.only(left: 15, right: 15),
        child: SfMaps(
          layers: [
            MapShapeLayer(source: dataSource),
          ],
        ),
      ),
   );
}

class Model {
  const Model(this.country, this.count);

  final String country;
  final double count;
}

Shape color opacity

NOTE