Hello,
I am very new to using the ArcGIS JavaScript API plugin and JavaScript in general so, to learn, I have been playing around with the sample code, specifically that for the SketchViewModel, here: https://developers.arcgis.com/javascript/latest/sample-code/layers-scenelayer-feature-masking/
My issue:
Currently, I am experimenting with converting the SketchViewModel example above, which works with 3D SceneView data, to one which is able to filter through feature layers in a 2D WebMap. However, am having difficulty looping it over each feature layer (of which there are 2) in my webmap:
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Filter webmap with FeatureFilter | Test | ArcGIS Maps SDK for JavaScript 4.28</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#infoDiv {
background-color: white;
padding: 10px;
width: 260px;
margin: 5px;
position: absolute;
bottom: 15px;
right: 10px;
font-size: 14px;
display: none;
}
.geometry-options {
display: flex;
flex-direction: row;
}
.geometry-button {
flex: 1;
border-style: solid;
border-width: 1px;
border-image: none;
}
.geometry-button-selected {
background: #4c4c4c;
color: #fff;
}
.options {
max-width: 260px;
width: 100%;
height: 25px;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.28/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.28/"></script>
<script>
require([
"esri/WebMap",
"esri/views/MapView",
"esri/layers/GraphicsLayer",
"esri/widgets/Sketch/SketchViewModel",
"esri/widgets/Slider",
"esri/layers/support/FeatureFilter",
"esri/geometry/geometryEngine",
"esri/Graphic"
], (WebMap, MapView, GraphicsLayer, SketchViewModel, Slider, FeatureFilter, geometryEngine, Graphic) => {
// Load webmap and display it in a webmap
const map = new WebMap({
portalItem: {
id: "1a3366d6e59945289a141e3ae62698b6"
}
});
// create the mapview
const view = new MapView({
container: "viewDiv",
map: map,
popupEnabled: false
});
// add a GraphicsLayer for the sketches and the buffer
const sketchLayer = new GraphicsLayer();
const bufferLayer = new GraphicsLayer();
view.map.addMany([bufferLayer, sketchLayer]);
// create the layerView's to add the filter
let featureLayerView = null;
map.load().then(() => {
// loop through webmap's operational layers
map.layers.forEach((layer) => {
view
.whenLayerView(layer)
.then((layerView) => {
if (layer.type === "feature") {
featureLayerView = layerView;
}
})
.catch(console.error);
});
});
const bufferNumSlider = new Slider({
container: "bufferNum",
min: 0,
max: 1000,
steps: 1,
visibleElements: {
labels: true,
},
precision: 0,
labelFormatFunction: (value, type) => {
return `${value.toString()}m`;
},
values: [0]
});
let bufferSize = 0;
bufferNumSlider.on(["thumb-change", "thumb-drag"], bufferVariablesChanged);
function bufferVariablesChanged(event) {
bufferSize = event.value;
updateFilter();
}
// use SketchViewModel to draw polygons that are used as a filter
let sketchGeometry = null;
const sketchViewModel = new SketchViewModel({
layer: sketchLayer,
view: view,
pointSymbol: {
type: "simple-marker",
style: "circle",
size: 10,
color: [255, 255, 255, 0.8],
outline: {
color: [211, 132, 80, 0.7],
size: 10
}
},
polylineSymbol: {
type: "simple-line",
color: [211, 132, 80, 0.7],
width: 6
},
polygonSymbol: {
type: "simple-fill",
symbolLayers: [
{
type: "fill",
material: {
color: [255, 255, 255, 0.8]
},
outline: {
color: [211, 132, 80, 0.7],
size: "10px"
}
}
]
},
defaultCreateOptions: { hasZ: false }
});
sketchViewModel.on(["create"], (event) => {
// update the filter every time the user finishes drawing the filtergeometry
if (event.state == "complete") {
sketchGeometry = event.graphic.geometry;
updateFilter();
}
});
sketchViewModel.on(["update"], (event) => {
const eventInfo = event.toolEventInfo;
// update the filter every time the user moves the filtergeometry
if (event.toolEventInfo && event.toolEventInfo.type.includes("stop")) {
sketchGeometry = event.graphics[0].geometry;
updateFilter();
}
});
// select the layer to filter on
let featureLayerViewFilterSelected = true;
document.getElementById("featureLayerViewFilter").addEventListener("change", (event) => {
featureLayerViewFilterSelected = !!event.target.checked;
updateFilter();
});
// draw geometry buttons - use the selected geometry to sktech
document.getElementById("point-geometry-button").onclick = geometryButtonsClickHandler;
document.getElementById("line-geometry-button").onclick = geometryButtonsClickHandler;
document.getElementById("polygon-geometry-button").onclick = geometryButtonsClickHandler;
function geometryButtonsClickHandler(event) {
const geometryType = event.target.value;
clearFilter();
sketchViewModel.create(geometryType);
}
// get the selected spatialRelationship
let selectedFilter = "disjoint";
document.getElementById("relationship-select").addEventListener("change", (event) => {
const select = event.target;
selectedFilter = select.options[select.selectedIndex].value;
updateFilter();
});
// remove the filter
document.getElementById("clearFilter").addEventListener("click", clearFilter);
function clearFilter() {
sketchGeometry = null;
filterGeometry = null;
sketchLayer.removeAll();
bufferLayer.removeAll();
featureLayerView.filter = null;
}
// set the geometry filter on the visible FeatureLayerView
function updateFilter() {
updateFilterGeometry();
const featureFilter = {
// autocasts to FeatureFilter
geometry: filterGeometry,
spatialRelationship: selectedFilter
};
if (featureLayerView) {
if (featureLayerViewFilterSelected) {
featureLayerView.filter = featureFilter;
} else {
featureLayerView.filter = null;
}
}
}
// update the filter geometry depending on bufferSize
let filterGeometry = null;
function updateFilterGeometry() {
// add a polygon graphic for the bufferSize
if (sketchGeometry) {
if (bufferSize > 0) {
const bufferGeometry = geometryEngine.geodesicBuffer(sketchGeometry, bufferSize, "meters");
if (bufferLayer.graphics.length === 0) {
bufferLayer.add(
new Graphic({
geometry: bufferGeometry,
symbol: sketchViewModel.polygonSymbol
})
);
} else {
bufferLayer.graphics.getItemAt(0).geometry = bufferGeometry;
}
filterGeometry = bufferGeometry;
} else {
bufferLayer.removeAll();
filterGeometry = sketchGeometry;
}
}
}
document.getElementById("infoDiv").style.display = "block";
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="infoDiv" class="esri-widget">
<br id="featureLayerViewFilter" />Draw a geometry to filter by:
<div class="geometry-options">
<button
class="esri-widget--button esri-icon-map-pin geometry-button"
id="point-geometry-button"
value="point"
title="Filter by point"
></button>
<button
class="esri-widget--button esri-icon-polyline geometry-button"
id="line-geometry-button"
value="polyline"
title="Filter by line"
></button>
<button
class="esri-widget--button esri-icon-polygon geometry-button"
id="polygon-geometry-button"
value="polygon"
title="Filter by polygon"
></button>
</div>
<br />
<label for="relationship-select">Spatial relationship:</label>
<select id="relationship-select" class="options">
<option value="intersects">intersects</option>
<option value="contains">contains</option>
<option value="disjoint" selected>disjoint</option> </select
><br /><br />
<button class="esri-button" id="clearFilter" type="button">
Clear filter
</button>
</div>
</body>
</html>
I would be very appreciative if anybody could give me some guidance on where i've gone wrong. For example, if i've configured the forEach function incorrectly.
Thank you.