30 KiB
layout | title | description | platform | control | documentation |
---|---|---|---|---|---|
post | Shape Sublayer in Flutter Maps widget | Syncfusion | Learn here all about the Shape Sublayer feature of the Syncfusion Flutter Maps (SfMaps) widget in the tile and the shape layer. | Flutter | SfMaps | ug |
Shape Sublayer in Flutter Maps (SfMaps)
The shape sublayer is where geographical rendering will happen for the sublayer. This is similar to the main shape layer
rendering. This section explains adding a shape sublayer on the shape layer and tile layer.
Shape sublayer on tile layer
The sublayers
in MapTileLayer
contains collection of MapSublayer
.The actual geographical rendering is done in the each MapShapeSublayer
. The source
property of the MapShapeSublayer
is of type MapShapeSource
. The path of the .json file which contains the GeoJSON data has to be set to the MapShapeSource
.
The shapeDataField
property of the MapShapeSource
is used to refer the unique field name in the .json file to identify each shapes.
{% tabs %} {% highlight Dart %}
late MapShapeSource _sublayerSource;
@override void initState() { super.initState();
_sublayerSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', ); }
@override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.only(left: 15, right: 15), child: SfMaps( layers: [ MapTileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', sublayers: [ MapShapeSublayer( source: _sublayerSource, ), ], ), ], ), ), ); }
{% endhighlight %} {% endtabs %}
N>
- Refer the
MapTileLayer
, for adding tile layer inSfMaps
.
Shape sublayer on shape layer
The sublayers
in MapShapeLayer
contains collection of MapSublayer
.The actual geographical rendering is done in the each MapShapeSublayer
. The source
property of the MapShapeSublayer
is of type MapShapeSource
. The path of the .json file which contains the GeoJSON data has to be set to the MapShapeSource
.
The shapeDataField
property of the MapShapeSource
is used to refer the unique field name in the .json file to identify each shapes.
{% tabs %} {% highlight Dart %}
late MapShapeSource _shapeSource; late MapShapeSource _sublayerSource;
@override void initState() { super.initState(); _shapeSource = MapShapeSource.asset( "assets/world_map.json", shapeDataField: "continent", );
_sublayerSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', ); }
@override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.only(left: 15, right: 15), child: SfMaps( layers: [ MapShapeLayer( source: _shapeSource, sublayers: [ MapShapeSublayer( source: _sublayerSource, ), ], ), ], ), ), ); }
{% endhighlight %} {% endtabs %}
N>
- Refer the
MapShapeLayer
, for adding shape layer inSfMaps
.
Color and stroke color
You can change the color, strokeColor and strokeWidth of the shape sublayer using the color
, strokeColor
and strokeWidth
properties.
N> It is applicable for both tile layer and shape layer.
{% tabs %} {% highlight Dart %}
late MapShapeSource _shapeSource; late MapShapeSource _sublayerSource;
@override void initState() { super.initState(); _shapeSource = MapShapeSource.asset( "assets/world_map.json", shapeDataField: "continent", );
_sublayerSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', ); }
@override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.only(left: 15, right: 15), child: SfMaps( layers: [ MapShapeLayer( source: _shapeSource, sublayers: [ MapShapeSublayer( source: _sublayerSource, color: Colors.blue[100], strokeWidth: 2, strokeColor: Colors.blue[800], ), ], ), ], ), ), ); }
{% endhighlight %} {% endtabs %}
Equal color mapping
You can apply color to the sublayer 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.
{% tabs %} {% highlight Dart %}
late List data; late MapShapeSource sublayerDataSource; late MapShapeSource shapeDataSource;
@override void initState() { data = [ Model('Algeria', "Low"), Model('Nigeria', "High"), Model('Libya', "High"), ];
shapeDataSource = MapShapeSource.asset(
"assets/world_map.json",
shapeDataField: 'continent',
);
sublayerDataSource = MapShapeSource.asset(
"assets/africa.json",
shapeDataField: "name",
dataCount: data.length,
primaryValueMapper: (int index) {
return data[index].state;
},
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( source: shapeDataSource, sublayers: [ MapShapeSublayer( source: sublayerDataSource, ) ], ), ], ), ), ); }
class Model { const Model(this.state, this.storage);
final String state; final String storage; }
{% endhighlight %} {% endtabs %}
Range color mapping
You can apply color to the sublayer 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.
{% tabs %} {% highlight Dart %}
late List data; late MapShapeSource sublayerDataSource; late MapShapeSource shapeDataSource;
@override void initState() { data = [ Model('Algeria', 196), Model('Nigeria', 280), Model('Libya', 45), ];
shapeDataSource = MapShapeSource.asset(
"assets/world_map.json",
shapeDataField: 'continent',
);
sublayerDataSource = MapShapeSource.asset(
"assets/africa.json",
shapeDataField: "name",
dataCount: data.length,
primaryValueMapper: (int index) {
return data[index].state;
},
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: shapeDataSource, sublayers: [ MapShapeSublayer( source: sublayerDataSource, ) ], ), ], ), ), ); }
class Model { const Model(this.state, this.count);
final String state; final double count; }
{% endhighlight %} {% endtabs %}
Enable data labels and its customization
You can enable data labels to the shape sublayer using the showDataLabels
property and customize the data labels text using the dataLabelMapper
property.
N> Refer the DataLabels
section, for customizing data labels.
{% tabs %} {% highlight Dart %}
late MapShapeSource _shapeSource; late MapShapeSource _sublayerSource; late List _sublayerData; late MapZoomPanBehavior _zoomPanBehavior;
@override void initState() { super.initState(); _shapeSource = MapShapeSource.asset( "assets/world_map.json", shapeDataField: "continent", );
_sublayerData = [ DataModel('Algeria', Colors.green, 'Algeria'), DataModel('Libya', Colors.teal, 'Libya'), DataModel('Egypt', Colors.blue, 'Egypt'), DataModel('Mali', Colors.purple, 'Mali'), DataModel('Niger', Colors.indigo, 'Niger'), DataModel('Nigeria', Colors.purpleAccent, 'Nigeria'), DataModel('Chad', Colors.lightGreen, 'Chad'), DataModel('Sudan', Colors.redAccent, 'Sudan'), DataModel('Mauritania', Colors.orange, 'Mauritania'), DataModel('South Sudan', Colors.lime, 'South Sudan'), DataModel('Ethiopia', Colors.greenAccent, 'Ethiopia') ];
_sublayerSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', dataCount: _sublayerData.length, primaryValueMapper: (int index) => _sublayerData[index].key, dataLabelMapper: (int index) => _sublayerData[index].stateCode, ); _zoomPanBehavior = MapZoomPanBehavior( zoomLevel: 3, focalLatLng: MapLatLng(38.9637, 35.2433), ); }
@override Widget build(BuildContext context) { return Scaffold( body: SfMaps( layers: [ MapShapeLayer( source: _shapeSource, zoomPanBehavior: _zoomPanBehavior, sublayers: [ MapShapeSublayer( source: _sublayerSource, showDataLabels: true, dataLabelSettings: const MapDataLabelSettings( overflowMode: MapLabelOverflow.ellipsis, textStyle: const TextStyle( color: Colors.red, fontSize: 12, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic, fontFamily: 'Times'), ), ), ], ), ], ), ); }
class DataModel { DataModel(this.key, this.color, this.stateCode);
final String key; final Color color; final String stateCode; }
{% endhighlight %} {% endtabs %}
Add bubbles to the sublayer
You can enable bubbles to the shape sublayer using the bubbleSizeMapper
property and customize the bubbles appearance using the bubblesSettings
property and enable tooltip for the shape sublayer bubbles using the bubbleTooltipBuilder
property.
N> It is applicable for both tile layer and shape layer.
N> Refer the Bubbles
section, to know more about the bubbles customization.
{% tabs %} {% highlight Dart %}
late MapShapeSource _shapeSource; late MapShapeSource _sublayerSource; late List _sublayerData; late MapZoomPanBehavior _zoomPanBehavior;
@override void initState() { super.initState(); _shapeSource = MapShapeSource.asset( "assets/world_map.json", shapeDataField: "continent", );
_sublayerData = [ DataModel('Algeria', Colors.green, 36232), DataModel('Libya', Colors.teal, 34121), DataModel('Egypt', Colors.blue, 43453), DataModel('Mali', Colors.purple, 28123), DataModel('Niger', Colors.indigo, 40111), DataModel('Nigeria', Colors.purpleAccent, 30232), DataModel('Chad', Colors.lightGreen, 48132), DataModel('Sudan', Colors.redAccent, 52654), DataModel('Mauritania', Colors.orange, 42231), DataModel('South Sudan', Colors.lime, 40421), DataModel('Ethiopia', Colors.greenAccent, 27198) ];
_sublayerSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', dataCount: _sublayerData.length, primaryValueMapper: (int index) => _sublayerData[index].key, bubbleColorValueMapper: (int index) => _sublayerData[index].color, bubbleSizeMapper: (int index) => _sublayerData[index].size, ); _zoomPanBehavior = MapZoomPanBehavior( zoomLevel: 3, focalLatLng: MapLatLng(38.9637, 35.2433), ); }
@override Widget build(BuildContext context) { return Scaffold( body: SfMaps( layers: [ MapShapeLayer( source: _shapeSource, zoomPanBehavior: _zoomPanBehavior, sublayers: [ MapShapeSublayer( source: _sublayerSource, bubbleSettings: const MapBubbleSettings( minRadius: 5, maxRadius: 20, ), bubbleTooltipBuilder: (BuildContext context, int index) { return Container( height: 40, width: 120, padding: const EdgeInsets.all(5), child: Column( children: [ Row( children: [ Text('State : ', style: TextStyle(color: Colors.white)), Text(_sublayerData[index].key, style: TextStyle(color: Colors.white)), ], ), Row( children: [ Text('Population : ', style: TextStyle(color: Colors.white)), Text(_sublayerData[index].size.toStringAsFixed(0), style: TextStyle(color: Colors.white)), ], ), ], ), ); }, ), ], ), ], ), ); }
class DataModel { DataModel(this.key, this.color, this.size);
final String key; final Color color; final double size; }
{% endhighlight %} {% endtabs %}
Enable tooltip for shape sublayer
You can enable tooltip for the shape sublayer using the shapeTooltipBuilder
property.
N> It is applicable for both tile layer and shape layer.
N> Refer the Tooltip
section to know more about the tooltip customization.
{% tabs %} {% highlight Dart %}
late MapShapeSource _shapeSource; late MapShapeSource _sublayerSource; late List _sublayerData; late MapZoomPanBehavior _zoomPanBehavior;
@override void initState() { super.initState(); _shapeSource = MapShapeSource.asset( "assets/world_map.json", shapeDataField: "continent", );
_sublayerData = [ DataModel('Algeria', Colors.green, 36232), DataModel('Libya', Colors.teal, 34121), DataModel('Egypt', Colors.blue, 43453), DataModel('Mali', Colors.purple, 28123), DataModel('Niger', Colors.indigo, 40111), DataModel('Nigeria', Colors.purpleAccent, 30232), DataModel('Chad', Colors.lightGreen, 48132), DataModel('Sudan', Colors.redAccent, 52654), DataModel('Mauritania', Colors.orange, 42231), DataModel('South Sudan', Colors.lime, 40421), DataModel('Ethiopia', Colors.greenAccent, 27198) ];
_sublayerSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', dataCount: _sublayerData.length, primaryValueMapper: (int index) => _sublayerData[index].key, shapeColorValueMapper: (int index) => _sublayerData[index].color, ); _zoomPanBehavior = MapZoomPanBehavior( zoomLevel: 3, focalLatLng: MapLatLng(38.9637, 35.2433), ); }
@override Widget build(BuildContext context) { return Scaffold( body: SfMaps( layers: [ MapShapeLayer( source: _shapeSource, zoomPanBehavior: _zoomPanBehavior, sublayers: [ MapShapeSublayer( source: _sublayerSource, shapeTooltipBuilder: (BuildContext context, int index) { return Container( height: 40, width: 120, padding: const EdgeInsets.all(5), child: Column( children: [ Row( children: [ Text('State : ', style: TextStyle(color: Colors.white)), Text(_sublayerData[index].key, style: TextStyle(color: Colors.white)), ], ), Row( children: [ Text('Population : ', style: TextStyle(color: Colors.white)), Text(_sublayerData[index].size.toStringAsFixed(0), style: TextStyle(color: Colors.white)), ], ), ], ), ); }, ), ], ), ], ), ); }
class DataModel { DataModel(this.key, this.color, this.size);
final String key; final Color color; final double size; }
{% endhighlight %} {% endtabs %}
Selection
You can enable shape sublayer selection using the onSelectionChanged
callback along with setting the selectedIndex
property.
The onSelectionChanged
callback is used to pass the index of the selected shape when the user is selecting a shape by tapping or clicking or by programmatically.
If the selected shape is tapped or clicked again, the index will be passed as -1. It means that, the shape is unselected.
N> It is applicable for both tile layer and shape layer.
N> Refer the Shape selection
section to know more about the selection feature.
{% tabs %} {% highlight Dart %}
late MapShapeSource _shapeSource; late MapShapeSource _sublayerSource; late List _sublayerData; late MapZoomPanBehavior _zoomPanBehavior; int _selectedIndex = 0;
@override void initState() { super.initState(); _shapeSource = MapShapeSource.asset( "assets/world_map.json", shapeDataField: "continent", );
_sublayerData = [ DataModel('Algeria', Colors.green, 36232), DataModel('Libya', Colors.teal, 34121), DataModel('Egypt', Colors.blue, 43453), DataModel('Mali', Colors.purple, 28123), DataModel('Niger', Colors.indigo, 40111), DataModel('Nigeria', Colors.purpleAccent, 30232), DataModel('Chad', Colors.lightGreen, 48132), DataModel('Sudan', Colors.redAccent, 52654), DataModel('Mauritania', Colors.orange, 42231), DataModel('South Sudan', Colors.lime, 40421), DataModel('Ethiopia', Colors.greenAccent, 27198) ];
_sublayerSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', dataCount: _sublayerData.length, primaryValueMapper: (int index) => _sublayerData[index].key, shapeColorValueMapper: (int index) => _sublayerData[index].color, ); _zoomPanBehavior = MapZoomPanBehavior( zoomLevel: 3, focalLatLng: MapLatLng(38.9637, 35.2433), ); }
@override Widget build(BuildContext context) { return Scaffold( body: SfMaps( layers: [ MapShapeLayer( source: _shapeSource, zoomPanBehavior: _zoomPanBehavior, sublayers: [ MapShapeSublayer( source: _sublayerSource, selectedIndex: _selectedIndex, onSelectionChanged: (int index) { setState(() { _selectedIndex = index; }); }, selectionSettings: const MapSelectionSettings( color: Colors.lime, strokeWidth: 3, strokeColor: Colors.black, ), ), ], ), ], ), ); }
class DataModel { DataModel(this.key, this.color, this.size);
final String key; final Color color; final double size; }
{% endhighlight %} {% endtabs %}
Marker
You can show markers at any position on the map by providing latitude and longitude position to the MapMarker
, which is the widget returns from the markerBuilder
property.
The markerBuilder
callback will be called number of times equal to the value specified in the initialMarkersCount
property. The default value of the initialMarkersCount
property is null.
N> It is applicable for both tile layer and shape layer.
N>
- Refer the
Marker
section to know more about the marker feature. - Refer the
Tooltip
section to know more about the tooltip feature.
{% tabs %} {% highlight Dart %}
late MapShapeSource _shapeSource; late MapShapeSource _sublayerSource; late List _sublayerData; late MapZoomPanBehavior _zoomPanBehavior; late List _markerData;
@override void initState() { super.initState(); _shapeSource = MapShapeSource.asset( "assets/world_map.json", shapeDataField: "continent", );
_markerData = [ MapLatLng(28.0339, 1.6596), MapLatLng(26.3351, 17.2283), MapLatLng(26.8208, 30.8025), MapLatLng(17.6078, 8.0817), MapLatLng(9.0820, 8.6753), MapLatLng(9.1450, 40.4897), MapLatLng(15.4542, 18.7322), MapLatLng(6.8770, 31.3070), MapLatLng(21.0079, -10.9408), MapLatLng(12.8628, 30.2176), ];
_sublayerData = [ DataModel('Algeria', Colors.green, 36232), DataModel('Libya', Colors.teal, 34121), DataModel('Egypt', Colors.blue, 43453), DataModel('Mali', Colors.purple, 28123), DataModel('Niger', Colors.indigo, 40111), DataModel('Nigeria', Colors.purpleAccent, 30232), DataModel('Chad', Colors.lightGreen, 48132), DataModel('Sudan', Colors.redAccent, 52654), DataModel('Mauritania', Colors.orange, 42231), DataModel('South Sudan', Colors.lime, 40421), DataModel('Ethiopia', Colors.greenAccent, 27198) ];
_sublayerSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', dataCount: _sublayerData.length, primaryValueMapper: (int index) => _sublayerData[index].key, shapeColorValueMapper: (int index) => _sublayerData[index].color, ); _zoomPanBehavior = MapZoomPanBehavior( zoomLevel: 3, focalLatLng: MapLatLng(38.9637, 35.2433), ); }
@override Widget build(BuildContext context) { return Scaffold( body: SfMaps( layers: [ MapShapeLayer( source: _shapeSource, zoomPanBehavior: _zoomPanBehavior, sublayers: [ MapShapeSublayer( source: _sublayerSource, initialMarkersCount: _markerData.length, markerBuilder: (BuildContext context, int index) { return MapMarker( latitude: _markerData[index].latitude, longitude: _markerData[index].longitude, iconColor: Colors.white, iconStrokeWidth: 2, iconStrokeColor: Colors.black, iconType: MapIconType.triangle, size: Size(15, 15), ); }, markerTooltipBuilder: (BuildContext context, int index) { return Padding( padding: EdgeInsets.all(10), child: Text(_sublayerData[index].key, style: TextStyle(color: Colors.white)), ); }, ), ], ), ], ), ); }
class DataModel { DataModel(this.key, this.color, this.size);
final String key; final Color color; final double size; }
{% endhighlight %} {% endtabs %}
N> You can refer to our Flutter Maps feature tour page for its groundbreaking feature representations. You can also explore our Flutter Maps Sublayer example that shows how to configure a Maps in Flutter.