arcgis-interaction

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ArcGIS Interaction

ArcGIS 交互功能

Use this skill when implementing user interactions like popups, editing, sketching, hit testing, and event handling.
在实现弹窗、编辑、绘图、点击检测和事件处理等用户交互功能时,可以使用本技能。

Popups

弹窗

Basic PopupTemplate

基础PopupTemplate配置

javascript
const layer = new FeatureLayer({
  url: "...",
  popupTemplate: {
    title: "{name}",
    content: "Population: {population}"
  }
});
javascript
const layer = new FeatureLayer({
  url: "...",
  popupTemplate: {
    title: "{name}",
    content: "Population: {population}"
  }
});

PopupTemplate with Field Formatting

带字段格式化的PopupTemplate

javascript
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
        }
      }
    ]
  }]
};
javascript
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
        }
      }
    ]
  }]
};

Multiple Content Elements

多内容元素弹窗

javascript
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"
    }
  ]
};
javascript
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"
    }
  ]
};

Custom Content Function

自定义内容函数

javascript
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;
  }
};
javascript
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;
  }
};

Arcade Expressions in Popups

弹窗中的Arcade表达式

javascript
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²"
};
javascript
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²"
};

Popup Actions

弹窗操作按钮

javascript
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
    }
  }
);
javascript
const measureAction = {
  title: "Measure Length",
  id: "measure-this",
  icon: "measure"
};

const popupTemplate = {
  title: "{name}",
  content: "{description}",
  actions: [measureAction]
};

// 监听操作按钮点击事件
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;
      // 对几何图形执行操作
    }
  }
);

Programmatic Popup Control

程序化控制弹窗

javascript
// 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;
javascript
// 在指定位置打开弹窗
view.openPopup({
  title: "Custom Popup",
  content: "Hello World",
  location: view.center
});

// 携带要素打开弹窗
view.openPopup({
  features: [graphic1, graphic2],
  location: mapPoint
});

// 关闭弹窗
view.closePopup();

// 访问弹窗属性
const selectedFeature = view.popup.selectedFeature;
const isVisible = view.popup.visible;

Popup Component

弹窗组件(HTML方式)

html
<arcgis-map basemap="streets-vector">
  <arcgis-popup slot="popup"></arcgis-popup>
</arcgis-map>
html
<arcgis-map basemap="streets-vector">
  <arcgis-popup slot="popup"></arcgis-popup>
</arcgis-map>

Hit Testing

点击检测

Basic Hit Test

基础点击检测

javascript
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);
  }
});
javascript
view.on("click", async (event) => {
  const response = await view.hitTest(event);

  if (response.results.length > 0) {
    const graphic = response.results[0].graphic;
    console.log("点击的要素:", graphic.attributes);
  }
});

Hit Test with Layer Filter

带图层过滤的点击检测

javascript
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]
  });
});
javascript
view.on("click", async (event) => {
  const response = await view.hitTest(event, {
    include: [featureLayer] // 仅检测该图层
  });

  // 或者排除指定图层
  const response2 = await view.hitTest(event, {
    exclude: [graphicsLayer]
  });
});

Pointer Move Hit Test

鼠标移动时的点击检测

javascript
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";
  }
});
javascript
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";
  }
});

Highlighting

要素高亮

Highlight Features

高亮要素

javascript
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();
javascript
const layerView = await view.whenLayerView(featureLayer);

// 高亮单个要素
const highlight = layerView.highlight(graphic);

// 高亮多个要素
const highlight = layerView.highlight([graphic1, graphic2]);

// 通过ID高亮要素
const highlight = layerView.highlight([1, 2, 3]);

// 取消高亮
highlight.remove();

Highlight on Click

点击时高亮要素

javascript
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);
  }
});
javascript
let highlightHandle;

view.on("click", async (event) => {
  // 移除之前的高亮
  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);
  }
});

Highlight Options

高亮样式配置

javascript
// Set highlight options on the layer view
layerView.highlightOptions = {
  color: [255, 255, 0, 1],
  haloOpacity: 0.9,
  fillOpacity: 0.2
};
javascript
// 在图层视图上设置高亮选项
layerView.highlightOptions = {
  color: [255, 255, 0, 1],
  haloOpacity: 0.9,
  fillOpacity: 0.2
};

Editing

要素编辑

Editor Component (Simplest)

编辑器组件(最简方式)

html
<arcgis-map item-id="YOUR_WEBMAP_ID">
  <arcgis-editor slot="top-right"></arcgis-editor>
</arcgis-map>
html
<arcgis-map item-id="YOUR_WEBMAP_ID">
  <arcgis-editor slot="top-right"></arcgis-editor>
</arcgis-map>

Editor Widget

编辑器部件(JavaScript方式)

javascript
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");
javascript
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");

FeatureForm

FeatureForm表单

javascript
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();
javascript
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"
      }
    ]
  }
});

// 设置要编辑的要素
featureForm.feature = graphic;

// 监听表单提交事件
featureForm.on("submit", () => {
  const values = featureForm.getValues();
  // 更新要素属性
  Object.keys(values).forEach(key => {
    graphic.attributes[key] = values[key];
  });
});

// 程序化提交表单
featureForm.submit();

applyEdits API

applyEdits API

javascript
// 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);
javascript
// 添加要素
const edits = {
  addFeatures: [newGraphic]
};
const result = await featureLayer.applyEdits(edits);
console.log("已添加:", result.addFeatureResults);

// 更新要素
const edits = {
  updateFeatures: [updatedGraphic]
};
const result = await featureLayer.applyEdits(edits);

// 删除要素
const edits = {
  deleteFeatures: [graphicToDelete]
};
const result = await featureLayer.applyEdits(edits);

// 组合编辑操作
const edits = {
  addFeatures: [newGraphic1, newGraphic2],
  updateFeatures: [updatedGraphic],
  deleteFeatures: [deleteGraphic]
};
const result = await featureLayer.applyEdits(edits);

Sketching

绘图功能

Sketch Component (Simplest)

绘图组件(最简方式)

html
<arcgis-map basemap="topo-vector">
  <arcgis-sketch slot="top-right" creation-mode="update"></arcgis-sketch>
</arcgis-map>
html
<arcgis-map basemap="topo-vector">
  <arcgis-sketch slot="top-right" creation-mode="update"></arcgis-sketch>
</arcgis-map>

Sketch Widget

绘图部件(JavaScript方式)

javascript
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);
});
javascript
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" // 可选值:single, continuous
});

view.ui.add(sketch, "top-right");

// 监听绘图事件
sketch.on("create", (event) => {
  if (event.state === "complete") {
    console.log("已创建:", event.graphic);
  }
});

sketch.on("update", (event) => {
  if (event.state === "complete") {
    console.log("已更新:", event.graphics);
  }
});

sketch.on("delete", (event) => {
  console.log("已删除:", event.graphics);
});

Draw Tool (Low-level)

绘图工具(底层API)

javascript
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
});
javascript
import Draw from "@arcgis/core/views/draw/Draw.js";

const draw = new Draw({ view: view });

// 创建多边形
const action = draw.create("polygon");

action.on("vertex-add", (event) => {
  console.log("已添加顶点:", event.vertices);
});

action.on("draw-complete", (event) => {
  const polygon = {
    type: "polygon",
    rings: event.vertices,
    spatialReference: view.spatialReference
  };
  // 使用多边形创建图形
});

Event Handling

事件处理

View Events

视图事件

javascript
// 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
  }
});
javascript
// 点击事件
view.on("click", (event) => {
  console.log("地图坐标:", event.mapPoint);
  console.log("屏幕坐标:", event.x, event.y);
});

// 双击事件
view.on("double-click", (event) => {
  event.stopPropagation(); // 阻止默认缩放行为
});

// 鼠标移动事件
view.on("pointer-move", (event) => {
  const point = view.toMap(event);
  console.log("经纬度:", point.longitude, point.latitude);
});

// 拖拽事件
view.on("drag", (event) => {
  if (event.action === "start") { }
  if (event.action === "update") { }
  if (event.action === "end") { }
});

// 键盘事件
view.on("key-down", (event) => {
  if (event.key === "Escape") {
    // 取消当前操作
  }
});

Property Watching

属性监听

javascript
// 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");
javascript
// 监听单个属性
view.watch("zoom", (newZoom) => {
  console.log("缩放级别已变更为:", newZoom);
});

// 监听多个属性
view.watch(["center", "zoom"], ([center, zoom]) => {
  console.log("视图已变更:", center, zoom);
});

// 监听视图静止状态(导航完成后)
view.watch("stationary", (isStationary) => {
  if (isStationary) {
    console.log("导航已完成");
  }
});

// 一次性监听
import { when } from "@arcgis/core/core/reactiveUtils.js";

await when(() => view.stationary === true);
console.log("视图已静止");

Layer Events

图层事件

javascript
// 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");
  }
});
javascript
// 图层视图更新事件
const layerView = await view.whenLayerView(featureLayer);

layerView.watch("updating", (updating) => {
  if (updating) {
    console.log("图层正在更新...");
  } else {
    console.log("图层更新完成");
  }
});

Widget Events

部件事件

javascript
// 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");
  }
});
javascript
// 搜索部件事件
searchWidget.on("select-result", (event) => {
  console.log("已选中结果:", event.result);
});

// 绘图部件事件
sketchWidget.on("create", (event) => {
  if (event.state === "complete") {
    console.log("绘图完成");
  }
});

Coordinate Conversion

坐标转换

javascript
// Screen to map coordinates
const mapPoint = view.toMap({ x: screenX, y: screenY });

// Map to screen coordinates
const screenPoint = view.toScreen(mapPoint);
javascript
// 屏幕坐标转地图坐标
const mapPoint = view.toMap({ x: screenX, y: screenY });

// 地图坐标转屏幕坐标
const screenPoint = view.toScreen(mapPoint);

TypeScript Usage

TypeScript 使用方式

Popup and symbol configurations use autocasting with
type
properties. For TypeScript safety, use
as const
:
typescript
// 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.
弹窗和符号配置通过
type
属性自动类型转换。为了TypeScript类型安全,使用
as const
typescript
// 为弹窗内容类型使用'as const'
layer.popupTemplate = {
  title: "{name}",
  content: [{
    type: "fields",
    fieldInfos: [
      { fieldName: "name", label: "Name" }
    ]
  }]
} as const;

// 为符号配置使用'as const'
const graphic = new Graphic({
  geometry: point,
  symbol: {
    type: "simple-marker",
    color: "red",
    size: 12
  } as const
});
提示: 有关自动类型转换与显式类的详细说明,请参考arcgis-core-maps 技能

Common Pitfalls

常见问题

  1. Popup not showing: Ensure layer has
    popupEnabled: true
    (default)
  2. Hit test returns nothing: Check if layers are included/excluded correctly
  3. Highlight not visible: Make sure to store the highlight handle and call
    remove()
    before creating new highlights
  4. applyEdits fails: Ensure layer is editable and user has edit permissions
  5. Events fire multiple times: Remove event handlers when no longer needed
  1. 弹窗不显示:确保图层的
    popupEnabled
    属性为true(默认值)
  2. 点击检测无结果:检查图层的包含/排除配置是否正确
  3. 高亮效果不可见:确保保存高亮句柄,并在创建新高亮前调用
    remove()
  4. applyEdits执行失败:确保图层可编辑且用户拥有编辑权限
  5. 事件多次触发:不再需要事件处理程序时及时移除