Spike Spiegel
Spike Spiegel

Reputation: 199

Displaying Feature IDs from Map Layers in Flutter using Mapbox Maps

I'm working on a Flutter application that utilizes Mapbox Maps, and I'm facing challenges in displaying feature IDs when users click on specific map layers. So basically, i have a Mapbox map in my Flutter app, where I've loaded GeoJSON data with various features and assigned different layers based on their status using mapbox_maps_flutter: ^0.5.1,

This is how it looks currently

When a user clicks on a feature within a specific layer (those grids), I want to display its feature ID in a popup, Snackbar, or any other user-friendly way. As there is no clear documentation or instruction about how click or tap event works, i'm unable to fulfill my requirements

/*view page code */
SizedBox(
  height: Get.height,
  child: Obx(() => MapWidget(
        key: const ValueKey("mapWidget"),
        onMapCreated: controller.onMapCreated,
        cameraOptions: CameraOptions(
            center: Point(
                    coordinates:
                        Position(-107.882000467, 47.616100673))
                .toJson(),
            zoom: controller.zoom.value),
        resourceOptions: ResourceOptions(
          accessToken: "<MAPBOX ACCESSS TOKEN>",
        ),
      )),
)
/* view page code */

/* controller page code */
Rx<MapboxMap?> mapboxMap = Rx<MapboxMap?>(null);

Future<void> onMapCreated(MapboxMap mapboxMap) async {
    this.mapboxMap.value = mapboxMap;

    // Load GeoJSON data
    var data = await rootBundle.loadString('assets/geo.geojson');
    var geoJson = json.decode(data);
    var geoJsonFeatures = geoJson['features'];

    // Create a Map to store colors based on status
    Map<int, Color> statusColors = {
      1: Color.fromARGB(128, 247, 247, 0), // 50% opacity
      2: Color.fromARGB(128, 24, 225, 31), // 50% opacity
      3: Color.fromARGB(128, 13, 104, 185), // 50% opacity
      4: const Color.fromARGB(0, 229, 210, 210), // Custom color for status 4
    };

    // Filter GeoJSON features based on status and create separate sources
    for (var status in statusColors.keys) {
      var filteredFeatures = geoJsonFeatures
          .where((feature) =>
              feature['properties'] != null &&
              feature['properties']['status'] == status)
          .toList();

      var filteredGeoJson = {
        'type': 'FeatureCollection',
        'features': filteredFeatures,
      };

      await mapboxMap.style.addSource(GeoJsonSource(
        id: 'fill_source_$status',
        data: json.encode(filteredGeoJson), // Ensure GeoJSON is a string
      ));

      await mapboxMap.style.addLayer(FillLayer(
        id: 'fill_layer_$status',
        sourceId: 'fill_source_$status',
        fillColor: statusColors[status]?.value ?? Colors.transparent.value,
        fillOutlineColor: Colors.black.value,
        fillOpacity: .5,
      ));
    }
  }
/* controller page code*/

This is my sample geojson data,

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -107.900000467,
              47.598100673
            ],
            [
              -107.891000467,
              47.598100673
            ],
            [
              -107.891000467,
              47.589100673
            ],
            [
              -107.900000467,
              47.589100673
            ],
            [
              -107.900000467,
              47.598100673
            ]
          ]
        ]
      },
      "properties": {
        "dbId": "5",
        "status": 4,
        "uid": null,
        "isBlocked": 0,
        "id": "5",
        "left": -107.900000467,
        "top": 47.598100673,
        "right": -107.891000467,
        "bottom": 47.589100673
      }
    },...    
  ]
}

I've reviewed the Mapbox Maps documentation, but I couldn't find a clear example for achieving this specific functionality. Any assistance or code snippets would be highly appreciated. Thank you!

Upvotes: 1

Views: 567

Answers (1)

Spike Spiegel
Spike Spiegel

Reputation: 199

Since their documentation only lists a small number of ingredients (mapbox_maps_flutter: ~0.5.1), I used a different package, mapbox_gl: ~0.16.0, to meet my needs.

/* view code */
MapboxMap(
    onMapCreated: controller.onMapCreated,
    zoomGesturesEnabled: true,
    accessToken:"<MAPBOX ACCESS TOKEN>",
    initialCameraPosition: const CameraPosition(
        target: LatLng(47.60498923803516, -107.06846142289754),
        zoom: 12),
)
/* view code */
* controller code */
void onMapCreated(MapboxMapController mapboxMap) async {
    // await getJson();

    //Create a Map to store colors based on status
    Map<int, String> statusColors = {
      1: convertColorToRgba(const Color.fromARGB(128, 221, 143, 137), 1),
      2: convertColorToRgba(const Color.fromARGB(128, 68, 235, 73), 1),
      3: convertColorToRgba(const Color.fromARGB(128, 14, 125, 215), 1),
      4: 'rgba(0, 0, 255, 0.0)', // Transparent color for status 4
    };

   //Add the GeoJSON source to the map
    await mapboxMap.addSource("fills", GeojsonSourceProperties(data: geojson));

   //Add the fill layer with the specified color and filter
    await mapboxMap.addFillLayer(
      "fills",
      "fills",
      FillLayerProperties(
        fillColor: [
          "step", ["get", "status"],
          statusColors[1], 1,
          statusColors[2], 2,
          statusColors[3], 3,
          statusColors[4], 4,
          'rgba(0, 0, 255, 0.0)' // Default color
        ],
        fillOpacity: 0.4,
        fillOutlineColor: 'rgba(0, 0, 0, 1)',
      ),
      filter: [
        "has",
        "status"
      ], // Add filter to only render features with a "status" property
      enableInteraction: true,
    );
    
    update();
  }
* controller code */

This code works fine; additionally, this package has some dedicated functions to achieve a specific functionality, such as onFeatureTap, and they have a sufficient community resource, for example. For any further reference, you can check out this GitHub document: https://github.com/flutter-mapbox-gl/maps/tree/b2bfef669e42397704b6f43d55b5df67b18c0fa8/example/lib

Upvotes: 1

Related Questions