Query a feature layer (spatial)

Learn how to execute a spatial query to access polygon features from a feature service.

A feature layer can contain a large number of features stored in ArcGIS. To access a subset of these features, you can execute an SQL or spatial query, either together or individually. The results can contain the attributes, geometry, or both for each record. SQL and spatial queries are useful when a feature layer is very large and you want to access only a subset of its data.

In this tutorial, you use Mapbox GL Draw to sketch a feature on the map, and then use ArcGIS REST JS to perform a spatial query against the LA County Parcels hosted feature layer. The layer contains ±2.4 million features. The spatial query returns all of the parcels that intersect the sketched feature. A pop-up is also used to display feature attributes.

Prerequisites

You need a free ArcGIS developer account to access your dashboard and API keys. The API key must be scoped to access the services used in this tutorial.

Steps

Create a new pen

  1. To get started, either complete the Display a map tutorial or .

Set the API key

To access ArcGIS location services, you need an API key.

  1. Go to your dashboard to get an API key.

  2. In CodePen, update apiKey to use your key.

    Change line
              
    //
    
    const apiKey = "YOUR-API-KEY";
    const basemapEnum = "ArcGIS:Streets";
    const map = new mapboxgl.Map({
      container: "map", // the id of the div element
      style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
      zoom: 12, // starting zoom
      center: [-118.805, 34.027] // starting location [longitude, latitude]
    });
    

Add script references

This tutorial uses three sets of libraries. ArcGIS REST JS is used for querying the feature layer. Mapbox GL Draw provides drawing tools, allowing the user to define a point, line, or polygon of interest. Terraformer is used to convert GeoJSON features generated by Mapbox GL Draw into ArcGIS JSON geometries; a requirement to query the feature layer service.

  1. Add <script> tags to reference the libraries.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>

Add Mapbox GL Draw

To display the Mapbox GL Draw controls, create a MapboxDraw and call map.addControl. By default, other tools are included, so you need to specify the three required tools: point, line, and polygon.

  1. Create a MapboxDraw and add it to the Map.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>

Add query layers

Three layers are required to display the three types of query you can perform: circle, line, and fill. They share a single GeoJSON source, which at any time will contain one feature of either Point, LineString or Polygon geometry. Create the source with an empty GeoJSON feature collection.

A line layer can display both line features and the border of polygon features.

The circle layer should be filtered to only display point features. Otherwise, a circle will be shown at each vertex of line and polygon features. You can use a filter and the ['geometry-type'] expression. See the Mapbox GL Style Specification for more details.

Similarly, the fill layer should be filtered to only display polygon features. Otherwise, line features will be treated as polygons and filled inappropriately.

  1. Create an addQueryLayers function. Inside, add a GeoJSON source and circle, line, and fill layers

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>

Add parcel layers

Parcels returned by the query are simple polygons. You can display them with a GeoJSON source and a fill layer.

  1. Create an addParcelLayers function. Inside, add a GeoJSON source and a fill layer.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>

Add a load handler

To add layers to the map, use the load event to ensure the map is fully loaded.

  1. Add an event handler for the load event. Inside, call addQueryLayers and addParcelLayers;

    Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>

Get the draw feature

Mapbox GL Draw emits a draw.create event when you have finished drawing a feature. You can listen to this event to respond to the newly created feature.

By default, Mapbox GL Draw keeps all previously drawn features visible in its own layer. To prevent this, use deleteAll after copying the feature.

  1. Add an event handler for draw.create. Inside, store the feature in the query layer, then delete all features from Mapbox GL Draw.

    Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>
  2. Click Run at the top right to test your code. You should be able to sketch a point, line or polygon feature, and see it turn into a green feature when complete.

Execute the query

Use the ArcGIS REST JS queryFeatures method to find features in the LA County Parcels feature layer that intersect the sketched feature. Use Terraformer.geojsonToArcGIS to convert the GeoJSON from Mapbox GL Draw into the ArcGIS geometry format.

When the matching parcels are returned, you can call setData on the parcels source to display them.

  1. Create a function called executeQuery with geometry and geometryType parameters. Inside, create a new arcgisRest.ApiKey to access the feature service. Call arcgisRest.queryFeatures. Pass the geometry and geometryType. Specify GeoJSON as the return type, requesting returnGeometry and specific outFields. All of the features within the geometry will be returned with attribute information set by the outFields property.

    There are many other spatial relationships that you can specify with spatialRel. For example, you can use esriSpatialRelContains to only return parcels within the sketched polygon. See the ArcGIS REST API documentation for details.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>
  2. Add a response handler. Inside, set the returned parcels as the data for the parcels source.

    Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>
  3. In your MapboxDraw event handler, call executeQuery. Use Terraformer.geojsonToArcGIS to convert geometry into an ArcGIS JSON format.

    Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>
  4. At the top right, click Run. When you create a feature using the toolbox, a spatial query will run against the feature layer and display all land parcels within the boundary of the feature.

Add a pop-up

You can add a pop-up to view attributes of a parcel when you click on it.

  1. Add a click event handler to the parcels-fill layer. Inside, construct the pop-up content from the attributes of the clicked parcel.

    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "parcels-fill",
              source: "parcels",
              type: "fill",
    
              paint: {
                "fill-color": "hsl(200, 80%, 50%)",
                "fill-opacity": 0.5,
                "fill-outline-color": "white"
              }
            });
          }
    
          map.on("load", () => {
    
            addParcelLayers();
    
            addQueryLayers();
          });
    
          map.on("draw.create", (e) => {
            const feature = e.features[0];
            map.getSource("query").setData(feature);
            draw.deleteAll();
    
            const geometry = Terraformer.geojsonToArcGIS(feature.geometry);
            let geometryType = "esriGeometry" + feature.geometry.type;
            if (feature.geometry.type === "LineString") {
              geometryType = "esriGeometryPolyline";
            }
            executeQuery(geometry, geometryType);
    
          });
    
          function executeQuery(geometry, geometryType) {
    
            arcgisRest
              .queryFeatures({
                url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
                geometry: geometry,
                geometryType: geometryType,
                spatialRel: "esriSpatialRelIntersects",
                f: "geojson",
                returnGeometry: true,
                outFields: ["APN", "UseType", "TaxRateCity", " Roll_LandValue"]
              })
    
              .then((response) => {
                map.getSource("parcels").setData(response);
              });
    
          }
    
          map.on("click", "parcels-fill", (e) => {
            const p = e.features[0].properties;
            const message =
              `<b>Parcel ${p.APN}</b>` +
              `Type: ${p.UseType} <br>` +
              `Land value: $${p.Roll_LandValue.toLocaleString()} <br>` +
              `Tax Rate City: ${p.TaxRateCity}`;
    
            new mapboxgl.Popup()
              .setHTML(message)
              .setLngLat(e.lngLat)
              .addTo(map);
    
          });
    
        </script>
      </body>
    </html>
  2. Create a Popup. Use Popup.setHTML to set the content. Update the position of the pop-up using Popup.setLngLat, and add it to the map using Popup.addTo.

    Add line.Add line.Add line.Add line.
                                                                                                                                                                                        
    <!DOCTYPE html>
    <html>
    
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
    
        <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" />
        <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.js"></script>
    
        <script src="https://unpkg.com/@esri/arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
        <script src="https://unpkg.com/@esri/arcgis-rest-feature-layer@3.0.0/dist/umd/feature-layer.umd.js"></script>
    
        <script src="https://unpkg.com/@terraformer/arcgis@2.0.7/dist/t-arcgis.umd.js"></script>
    
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
          }
        </style>
      </head>
    
      <body>
        <div id="map"></div>
        <script>
    
          const apiKey = "YOUR-API-KEY";
    
          const basemapEnum = "ArcGIS:Streets";
    
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&apiKey=${apiKey}`,
            zoom: 12, // starting zoom
    
            center: [-118.80543, 34.03] // starting location [longitude, latitude]
    
          });
    
          const draw = new MapboxDraw({
            displayControlsDefault: false, // Don't add any tools other than those below
            controls: {
              point: true,
              line_string: true,
              polygon: true
            }
          });
    
          map.addControl(draw, "top-left");
    
          function addQueryLayers() {
            map.addSource("query", {
              type: "geojson",
              data: {
                type: "FeatureCollection",
                features: []
              }
            });
            map.addLayer({
              id: "query-line",
              type: "line",
              source: "query",
              paint: {
                "line-color": "hsl(140, 0%, 30%)",
                "line-width": 2,
                "line-dasharray": [2,2]
              }
            });
            map.addLayer({
              id: "query-fill",
              type: "fill",
              source: "query",
              paint: {
                "fill-color": "hsl(140, 0%, 50%)",
                "fill-opacity": 0.2
              },
              filter: ["==", ["geometry-type"], "Polygon"]
            });
    
            map.addLayer({
              id: "query-circle",
              type: "circle",
              source: "query",
              paint: {
                "circle-color": "hsl(140, 0%, 30%)"
              },
              filter: ["==", ["geometry-type"], "Point"]
            });
          }
    
          function addParcelLayers() {
            map.addSource("parcels", {
              type: "geojson",
              data: {
                type: