<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Apply effects to features | Sample | ArcGIS Maps SDK for JavaScript</title>
<!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
<script type="module" src="https://js.arcgis.com/5.0/"></script>
<arcgis-map item-id="971eae060595416283eaac4ad54cbbda">
<arcgis-zoom slot="top-left"></arcgis-zoom>
<calcite-panel slot="top-right" id="controls" heading="Explore spatial relationships">
<calcite-block expanded label="controls block">
<calcite-segmented-control width="full" label-text="Select a layer by geometry type:">
<calcite-segmented-control-item
title="Select a point layer to see how it is spatially related to one of the predefined geometries"
</calcite-segmented-control-item>
<calcite-segmented-control-item
title="Select a line layer to see how it is spatially related to one of the predefined geometries"></calcite-segmented-control-item>
<calcite-segmented-control-item
id="polygon-layer-button"
title="Select a polygon layer to see how it is spatially related to one of the predefined geometries"></calcite-segmented-control-item> </calcite-segmented-control
<calcite-segmented-control width="full" label-text="Select a predefined geometry:">
<calcite-segmented-control-item
id="point-geometry-button"
</calcite-segmented-control-item>
<calcite-segmented-control-item
id="line-geometry-button"
title="Filter by line"></calcite-segmented-control-item>
<calcite-segmented-control-item
id="polygon-geometry-button"
title="Filter by polygon"></calcite-segmented-control-item> </calcite-segmented-control
<calcite-select id="relationship-select" label-text="Spatial relationship:">
<calcite-option value="intersects">intersects</calcite-option>
<calcite-option value="contains">contains</calcite-option>
<calcite-option value="crosses">crosses</calcite-option>
<calcite-option value="envelope-intersects">envelope-intersects</calcite-option>
<calcite-option value="overlaps">overlaps</calcite-option>
<calcite-option value="touches">touches</calcite-option>
<calcite-option value="within">within</calcite-option>
<calcite-option value="disjoint">disjoint</calcite-option> </calcite-select
label-text="Change distance:"
<calcite-select id="distance-select" label-text="Distance unit:">
<calcite-option value="meters">meters</calcite-option>
<calcite-option value="kilometers">kilometers</calcite-option>
<calcite-option value="feet">feet</calcite-option>
<calcite-option value="miles">miles</calcite-option>
<calcite-option value="nautical-miles">nautical-miles</calcite-option> </calcite-select
<calcite-button id="clearFilter" type="button" width="full"
>Clear all filter</calcite-button
const [GraphicsLayer, Graphic, geodesicBufferOperator, centroidOperator] =
"@arcgis/core/layers/GraphicsLayer.js",
"@arcgis/core/Graphic.js",
"@arcgis/core/geometry/operators/geodesicBufferOperator.js",
"@arcgis/core/geometry/operators/centroidOperator.js",
let activeLayerView = null;
const layerViewsByGeometryType = Object.create(null);
const filterGraphicsByGeometryType = Object.create(null);
const viewElement = document.querySelector("arcgis-map");
await viewElement.viewOnReady();
const map = viewElement.map;
const bufferGeometriesLayer = new GraphicsLayer();
// add the graphics layer to the top once webmap loads
map.layers.unshift(bufferGeometriesLayer);
// loop through webmap's operational layers (use for...of so awaits are respected)
for (const layer of map.layers.toArray()) {
if (layer.type !== "feature") continue;
const layerView = await viewElement.whenLayerView(layer);
layerViewsByGeometryType[layer.geometryType] = layerView;
// default to points (if present), otherwise first layer
if (!activeLayerView || layer.geometryType === "point") {
activeLayerView = layerView;
// geometry filter distance UI components
const distanceUnitSelect = document.getElementById("distance-select");
const spatialRelTypeSelect = document.getElementById("relationship-select");
const distanceSlider = document.getElementById("distance-slider");
//FeatureFilter variables
let filterGeometry = null;
let geometryRel = spatialRelTypeSelect.value;
// listen to change and input events on UI components
distanceSlider.addEventListener("calciteSliderChange", distanceVariablesChanged);
distanceUnitSelect.addEventListener("calciteSelectChange", distanceVariablesChanged);
spatialRelTypeSelect.addEventListener("calciteSelectChange", distanceVariablesChanged);
// get user entered values from distance related options
function distanceVariablesChanged() {
unit = distanceUnitSelect.value;
distance = distanceSlider.value;
geometryRel = spatialRelTypeSelect.value;
// update the buffer graphic if user is filtering by distance
async function updateBuffer() {
if (distance > 0 && filterGeometry) {
// Verify that the operator's dependencies are loaded
if (!geodesicBufferOperator.isLoaded()) {
await geodesicBufferOperator.load();
const newBufferGeometry = geodesicBufferOperator.execute(filterGeometry, distance, {
bufferGeometriesLayer.graphics.getItemAt(0).geometry = newBufferGeometry;
bufferGraphic.geometry = null;
// set the geometry filter on the visible FeatureLayerView
function updateFilter() {
geometry: filterGeometry,
spatialRelationship: geometryRel,
// set effect on excluded features make them gray and transparent
activeLayerView.featureEffect = {
excludedEffect: "grayscale(100%) opacity(30%)",
// click events for the layer type buttons
.getElementById("point-layer-button")
.addEventListener("click", layersChangedClickHandler);
.getElementById("line-layer-button")
.addEventListener("click", layersChangedClickHandler);
.getElementById("polygon-layer-button")
.addEventListener("click", layersChangedClickHandler);
// Make the selected layer view visible while setting the other layer views invisible
function layersChangedClickHandler(event) {
for (const key in layerViewsByGeometryType) {
layerViewsByGeometryType[key].visible = false;
const geometryType = event.target.value;
const layerView = layerViewsByGeometryType[geometryType];
layerView.visible = true;
activeLayerView = layerView;
// geometry buttons - use the selected geometry to set effect
const pointGeometryButton = document.getElementById("point-geometry-button");
pointGeometryButton.addEventListener("click", geometryButtonsClickHandler);
const lineGeometryButton = document.getElementById("line-geometry-button");
lineGeometryButton.addEventListener("click", geometryButtonsClickHandler);
const polygonGeometryButton = document.getElementById("polygon-geometry-button");
polygonGeometryButton.addEventListener("click", geometryButtonsClickHandler);
function geometryButtonsClickHandler(event) {
const geometryType = event.target.value;
for (const key in filterGraphicsByGeometryType) {
filterGraphicsByGeometryType[key].visible = false;
const filterGraphic = filterGraphicsByGeometryType[geometryType];
if (!filterGraphic) return;
filterGraphic.visible = true;
filterGeometry = filterGraphic.geometry;
document.getElementById("clearFilter").addEventListener("click", () => {
bufferGraphic.geometry = null;
pointGeometryButton.checked = false;
lineGeometryButton.checked = false;
polygonGeometryButton.checked = false;
for (const key in filterGraphicsByGeometryType) {
filterGraphicsByGeometryType[key].visible = false;
// add predefined point, line and polygon features
[-19155.858716270788, 6715337.237212951],
[4111.45326088908, 6716409.445683937],
[4389.731816989901, 6705532.994006807],
[-19140.631027042098, 6705304.280086235],
[-19155.858716270788, 6715337.237212951],
spatialReference: viewElement.spatialReference,
const polygonGraphic = new Graphic({
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [51, 51, 204, 0.4],
filterGraphicsByGeometryType[polygonGraphic.geometry.type] = polygonGraphic;
[polygonGraphic.geometry.extent.xmin, polygonGraphic.geometry.extent.ymin],
[polygonGraphic.geometry.extent.xmax, polygonGraphic.geometry.extent.ymax],
spatialReference: viewElement.spatialReference,
const lineGraphic = new Graphic({
color: [51, 51, 204, 0.5],
filterGraphicsByGeometryType[lineGraphic.geometry.type] = lineGraphic;
const centroid = centroidOperator.execute(polygonGraphic.geometry);
spatialReference: viewElement.spatialReference,
const pointGraphic = new Graphic({
color: [51, 51, 204, 0.9],
family: "CalciteWebCoreIcons",
filterGraphicsByGeometryType[pointGraphic.geometry.type] = pointGraphic;
bufferGraphic = new Graphic({
color: [151, 151, 204, 0.5],
bufferGeometriesLayer.addMany([bufferGraphic, polygonGraphic, lineGraphic, pointGraphic]);