<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Hit test features by screen rectangle | 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.1/"></script>
grid-template-areas: "a a a" "a a a" "a a a";
grid-template-rows: 1fr auto 1fr;
grid-template-columns: 1fr auto 1fr;
<!-- Note: popup-component-enabled enables the Popup component (beta). See https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-map/#popupComponentEnabled for details. -->
<arcgis-map basemap="gray-vector" zoom="11" center="-75, 40" popup-component-enabled>
<arcgis-zoom slot="top-left"></arcgis-zoom>
<arcgis-expand slot="bottom-left">
<arcgis-legend></arcgis-legend>
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 200 200">
stroke="rgba(255, 255, 255, 0.8)"
style="filter: blur(2px)"
<rect x="3" y="3" width="194" height="194" fill="none" stroke="black" stroke-width="2"></rect>
<calcite-shell-panel slot="panel-end" position="end">
heading="Population Change 2010-2023 by Tracts"
description="Tracts in focus: 0"
<calcite-list id="hit-feature-list" selection-mode="single"></calcite-list>
const [FeatureLayer, reactiveUtils] = await $arcgis.import([
"@arcgis/core/layers/FeatureLayer.js",
"@arcgis/core/core/reactiveUtils.js",
const viewElement = document.querySelector("arcgis-map");
const featurePanelElement = document.getElementById("feature-panel");
const hitFeatureListElement = document.getElementById("hit-feature-list");
viewElement.constraints = {
await viewElement.viewOnReady();
const tempHighlight = viewElement.highlights.getItemAt(1);
tempHighlight.color = "magenta";
// Add a feature layer with population change data for tracts.
const layer = new FeatureLayer({
id: "ee82b1db9e4e409f936a1e76d8a942e6",
outFields: ["NAME", "TOTPOP_CY"],
viewElement.map.layers.add(layer);
// Enable popup docking so popup for the clicked list items will dock
// to the side and not overlap the hit test rectangle.
viewElement.popupElement.dockEnabled = true;
viewElement.popupElement.dockOptions = {
// Track highlights and the current set of features intersecting the screen rectangle.
const layerView = await viewElement.whenLayerView(layer);
await reactiveUtils.whenOnce(() => viewElement.stationary && !viewElement.updating && !layerView.updating);
// Runs area-based hit testing using the rectangle overlay and syncs map/list UI state.
async function runRectHitTest() {
const rect = document.getElementById("rect").getBoundingClientRect();
// Use screen rectangle as the hit target to find all intersecting features in view.
const hit = await viewElement.hitTest(rect, { include: [layer] });
const graphics = hit.results.filter((result) => result.graphic).map((result) => result.graphic);
currentHitGraphics = graphics;
if (graphics.length > 0) {
hitHighlight = layerView.highlight(graphics);
renderHitFeatureList(graphics);
if (featurePanelElement) {
featurePanelElement.description = `Tracts in focus: ${graphics.length}`;
// Renders the current hit results as interactive items in the side panel list.
function renderHitFeatureList(graphics) {
hitFeatureListElement.replaceChildren();
const fragment = document.createDocumentFragment();
graphics.forEach((graphic, index) => {
const name = graphic.attributes.NAME;
const totalPopulation = graphic.attributes.TOTPOP_CY;
const description = `Total population: ${totalPopulation}`;
const item = document.createElement("calcite-list-item");
item.setAttribute("label", name);
item.setAttribute("description", description);
item.setAttribute("value", String(index));
item.addEventListener("calciteListItemSelect", async (event) => {
const selectedGraphic = currentHitGraphics[index];
if (event.target.selected && selectedGraphic) {
await highlightSelectedFeature(selectedGraphic);
fragment.appendChild(item);
hitFeatureListElement.appendChild(fragment);
function clearSelectedFeature() {
viewElement.closePopup();
clickedHighlight?.remove();
// Applies a focused highlight and opens the popup for a selected list item
async function highlightSelectedFeature(graphic) {
clickedHighlight?.remove();
clickedHighlight = layerView.highlight(graphic, { name: "temporary" });
const popupLocation = graphic.geometry?.extent?.center ?? graphic.geometry;
// Refresh results only when navigation settles so the list reflects the current view.
viewElement.addEventListener("arcgisViewChange", () => {
if (!viewElement.stationary) {