how to apply 'generateId:true' on composite source features?

Viewed 470

I want to find out buildings inside a runtime-drawed polygon. And fill with green color.

I try to archive it with feature state and case expression. When I find out those features that inside the polygon in some way, I still can't execute the map.setFeatureState, cause the first parameter need (feature object) need a specified id, however, the feature that created by composite source hasn't set id, also looks there is no way to set 'generateId:true'.

Is there any alternate way to achieve the purpose?

in the follow snippet,there is a polygon draw tool on the top-right,draw a polygon and double click to end of draw, then you will find the error alerted in the console.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Static Template</title>

  <script src="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.js"></script>
  <link href="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css" rel="stylesheet" />

  <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@turf/turf@5/turf.min.js"></script>
  <link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.css" type="text/css" />

  <style>
    body {
      margin: 0;
      padding: 0;
    }
    
    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>

<body>
  <div id="map"></div>
  <script>
    mapboxgl.accessToken =
      "pk.eyJ1IjoibWluem9qaWFuIiwiYSI6ImNrbGFsem92MjAxaHAycG1sbGg3MXFsODAifQ.Kclz1IBxyU0iDiVgIjhSYQ";
    var map = new mapboxgl.Map({
      container: "map",
      style: "mapbox://styles/mapbox/streets-v11"
    });

    var map = new mapboxgl.Map({
      style: "mapbox://styles/mapbox/light-v10",
      center: [-73.991, 40.735],
      zoom: 15.5,
      pitch: 45,
      bearing: -17.6,
      container: "map",
      antialias: true
    });

    var draw = new MapboxDraw({
      displayControlsDefault: false,
      controls: {
        polygon: true,
        trash: true
      }
    });
    map.addControl(draw);

    map.on("draw.create", updateArea);
    map.on("draw.delete", updateArea);
    map.on("draw.update", updateArea);

    function updateArea(e) {
      if (map.getLayer("maine")) map.removeLayer("maine");

      if (map.getSource("data-area")) map.removeSource("data-area");

      map.addSource("data-area", {
        type: "geojson",
        data: draw.getAll()
      });

      //get features in polygon
      lastInAreaFeatures = map
        .queryRenderedFeatures({
          layers: ["3d-buildings"]
        })
        .filter(function(t) {
          return turf.booleanContains(
            turf.polygon(draw.getAll().features[0].geometry.coordinates),
            t.geometry.type == "MultiPolygon" ?
            turf.polygon([t.geometry.coordinates[0][0]]) :
            turf.polygon([t.geometry.coordinates[0]])
          );
        });
      //try to update state,and set in-area equals true. so that the condition paint logic will work in the bellow "3d-buildings" layer
      //////however,the follow code can't work because the id of feature is undefined
      ///// 'Error: The feature id parameter must be provided.' will alerted in console
      lastInAreaFeatures.forEach(function(f) {
        map.setFeatureState(f, {
          "in-area": true
        });
      });
      console.log(lastInAreaFeatures);

      draw.deleteAll();
    }
    var lastInAreaFeatures;

    // The 'building' layer in the mapbox-streets vector source contains building-height
    // data from OpenStreetMap.
    map.on("load", function() {
      map.addLayer({
        id: "3d-buildings",
        source: "composite",
        "source-layer": "building",
        filter: ["==", "extrude", "true"],
        type: "fill-extrusion",
        minzoom: 15,
        paint: {
          "fill-extrusion-color": [
            "case", ["==", ["feature-state", "in-area"], true],
            "green",
            "#aaa"
          ],
          "fill-extrusion-height": [
            "interpolate", ["linear"],
            ["zoom"],
            15,
            0,
            15.05, ["get", "height"]
          ],
          "fill-extrusion-base": [
            "interpolate", ["linear"],
            ["zoom"],
            15,
            0,
            15.05, ["get", "min_height"]
          ],
          "fill-extrusion-opacity": 0.6
        }
      });
    });
  </script>
</body>

</html>

0 Answers
Related