Loading...
Loading...
Handle user interaction with map features including popups, editing, sketching, and event handling. Use for creating interactive map applications with feature selection, editing workflows, and custom interactions.
npx skill4agent add saschabrunnerch/arcgis-maps-sdk-js-ai-context arcgis-interactionconst layer = new FeatureLayer({
url: "...",
popupTemplate: {
title: "{name}",
content: "Population: {population}"
}
});const popupTemplate = {
title: "Feature: {name}",
content: [{
type: "fields",
fieldInfos: [
{
fieldName: "population",
label: "Population",
format: {
digitSeparator: true,
places: 0
}
},
{
fieldName: "date_created",
label: "Created",
format: {
dateFormat: "short-date"
}
},
{
fieldName: "area_sqkm",
label: "Area (km²)",
format: {
places: 2
}
}
]
}]
};const popupTemplate = {
title: "{name}",
content: [
{
type: "text",
text: "<b>Description:</b> {description}"
},
{
type: "fields",
fieldInfos: [...]
},
{
type: "media",
mediaInfos: [{
type: "image",
value: {
sourceURL: "{image_url}"
}
}]
},
{
type: "attachments"
}
]
};const popupTemplate = {
title: "{name}",
content: (feature) => {
const div = document.createElement("div");
div.innerHTML = `
<p>Custom content for ${feature.graphic.attributes.name}</p>
<button id="customBtn">Click me</button>
`;
return div;
}
};const popupTemplate = {
title: "{name}",
expressionInfos: [{
name: "density",
title: "Population Density",
expression: "Round($feature.population / $feature.area_sqkm, 2)"
}],
content: "Population Density: {expression/density} people/km²"
};const measureAction = {
title: "Measure Length",
id: "measure-this",
icon: "measure"
};
const popupTemplate = {
title: "{name}",
content: "{description}",
actions: [measureAction]
};
// Listen for action clicks
import reactiveUtils from "@arcgis/core/core/reactiveUtils.js";
reactiveUtils.on(
() => view.popup,
"trigger-action",
(event) => {
if (event.action.id === "measure-this") {
const geometry = view.popup.selectedFeature.geometry;
// Do something with the geometry
}
}
);// Open popup at location
view.openPopup({
title: "Custom Popup",
content: "Hello World",
location: view.center
});
// Open popup with features
view.openPopup({
features: [graphic1, graphic2],
location: mapPoint
});
// Close popup
view.closePopup();
// Access popup properties
const selectedFeature = view.popup.selectedFeature;
const isVisible = view.popup.visible;<arcgis-map basemap="streets-vector">
<arcgis-popup slot="popup"></arcgis-popup>
</arcgis-map>view.on("click", async (event) => {
const response = await view.hitTest(event);
if (response.results.length > 0) {
const graphic = response.results[0].graphic;
console.log("Clicked feature:", graphic.attributes);
}
});view.on("click", async (event) => {
const response = await view.hitTest(event, {
include: [featureLayer] // Only test this layer
});
// Or exclude layers
const response2 = await view.hitTest(event, {
exclude: [graphicsLayer]
});
});view.on("pointer-move", async (event) => {
const response = await view.hitTest(event, {
include: featureLayer
});
if (response.results.length > 0) {
document.body.style.cursor = "pointer";
} else {
document.body.style.cursor = "default";
}
});const layerView = await view.whenLayerView(featureLayer);
// Highlight a single feature
const highlight = layerView.highlight(graphic);
// Highlight multiple features
const highlight = layerView.highlight([graphic1, graphic2]);
// Highlight by object IDs
const highlight = layerView.highlight([1, 2, 3]);
// Remove highlight
highlight.remove();let highlightHandle;
view.on("click", async (event) => {
// Remove previous highlight
if (highlightHandle) {
highlightHandle.remove();
}
const response = await view.hitTest(event, { include: featureLayer });
if (response.results.length > 0) {
const graphic = response.results[0].graphic;
const layerView = await view.whenLayerView(featureLayer);
highlightHandle = layerView.highlight(graphic);
}
});// Set highlight options on the layer view
layerView.highlightOptions = {
color: [255, 255, 0, 1],
haloOpacity: 0.9,
fillOpacity: 0.2
};<arcgis-map item-id="YOUR_WEBMAP_ID">
<arcgis-editor slot="top-right"></arcgis-editor>
</arcgis-map>import Editor from "@arcgis/core/widgets/Editor.js";
const editor = new Editor({
view: view,
layerInfos: [{
layer: featureLayer,
formTemplate: {
elements: [
{ type: "field", fieldName: "name" },
{ type: "field", fieldName: "description" }
]
}
}]
});
view.ui.add(editor, "top-right");import FeatureForm from "@arcgis/core/widgets/FeatureForm.js";
const featureForm = new FeatureForm({
container: "formDiv",
layer: featureLayer,
formTemplate: {
title: "Edit Feature",
elements: [
{
type: "field",
fieldName: "name",
label: "Name"
},
{
type: "field",
fieldName: "type",
label: "Type"
}
]
}
});
// Set feature to edit
featureForm.feature = graphic;
// Listen for submit
featureForm.on("submit", () => {
const values = featureForm.getValues();
// Update feature attributes
Object.keys(values).forEach(key => {
graphic.attributes[key] = values[key];
});
});
// Submit programmatically
featureForm.submit();// Add features
const edits = {
addFeatures: [newGraphic]
};
const result = await featureLayer.applyEdits(edits);
console.log("Added:", result.addFeatureResults);
// Update features
const edits = {
updateFeatures: [updatedGraphic]
};
const result = await featureLayer.applyEdits(edits);
// Delete features
const edits = {
deleteFeatures: [graphicToDelete]
};
const result = await featureLayer.applyEdits(edits);
// Combined edits
const edits = {
addFeatures: [newGraphic1, newGraphic2],
updateFeatures: [updatedGraphic],
deleteFeatures: [deleteGraphic]
};
const result = await featureLayer.applyEdits(edits);<arcgis-map basemap="topo-vector">
<arcgis-sketch slot="top-right" creation-mode="update"></arcgis-sketch>
</arcgis-map>import Sketch from "@arcgis/core/widgets/Sketch.js";
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer.js";
const graphicsLayer = new GraphicsLayer();
map.add(graphicsLayer);
const sketch = new Sketch({
view: view,
layer: graphicsLayer,
creationMode: "update" // or "single", "continuous"
});
view.ui.add(sketch, "top-right");
// Listen for events
sketch.on("create", (event) => {
if (event.state === "complete") {
console.log("Created:", event.graphic);
}
});
sketch.on("update", (event) => {
if (event.state === "complete") {
console.log("Updated:", event.graphics);
}
});
sketch.on("delete", (event) => {
console.log("Deleted:", event.graphics);
});import Draw from "@arcgis/core/views/draw/Draw.js";
const draw = new Draw({ view: view });
// Create a polygon
const action = draw.create("polygon");
action.on("vertex-add", (event) => {
console.log("Vertex added:", event.vertices);
});
action.on("draw-complete", (event) => {
const polygon = {
type: "polygon",
rings: event.vertices,
spatialReference: view.spatialReference
};
// Create graphic with polygon
});// Click
view.on("click", (event) => {
console.log("Map point:", event.mapPoint);
console.log("Screen point:", event.x, event.y);
});
// Double-click
view.on("double-click", (event) => {
event.stopPropagation(); // Prevent default zoom
});
// Pointer move
view.on("pointer-move", (event) => {
const point = view.toMap(event);
console.log("Coordinates:", point.longitude, point.latitude);
});
// Drag
view.on("drag", (event) => {
if (event.action === "start") { }
if (event.action === "update") { }
if (event.action === "end") { }
});
// Key events
view.on("key-down", (event) => {
if (event.key === "Escape") {
// Cancel operation
}
});// Watch single property
view.watch("zoom", (newZoom) => {
console.log("Zoom changed to:", newZoom);
});
// Watch multiple properties
view.watch(["center", "zoom"], ([center, zoom]) => {
console.log("View changed:", center, zoom);
});
// Watch stationary (after navigation completes)
view.watch("stationary", (isStationary) => {
if (isStationary) {
console.log("Navigation complete");
}
});
// One-time watch
import { when } from "@arcgis/core/core/reactiveUtils.js";
await when(() => view.stationary === true);
console.log("View is now stationary");// Layer view updating
const layerView = await view.whenLayerView(featureLayer);
layerView.watch("updating", (updating) => {
if (updating) {
console.log("Layer is updating...");
} else {
console.log("Layer update complete");
}
});// Search widget
searchWidget.on("select-result", (event) => {
console.log("Selected:", event.result);
});
// Sketch widget
sketchWidget.on("create", (event) => {
if (event.state === "complete") {
console.log("Sketch complete");
}
});// Screen to map coordinates
const mapPoint = view.toMap({ x: screenX, y: screenY });
// Map to screen coordinates
const screenPoint = view.toScreen(mapPoint);typeas const// Use 'as const' for popup content types
layer.popupTemplate = {
title: "{name}",
content: [{
type: "fields",
fieldInfos: [
{ fieldName: "name", label: "Name" }
]
}]
} as const;
// Use 'as const' for symbol configurations
const graphic = new Graphic({
geometry: point,
symbol: {
type: "simple-marker",
color: "red",
size: 12
} as const
});Tip: See arcgis-core-maps skill for detailed guidance on autocasting vs explicit classes.
popupEnabled: trueremove()