arcgis-interaction
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseArcGIS 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 properties. For TypeScript safety, use :
typeas consttypescript
// 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.
弹窗和符号配置通过属性自动类型转换。为了TypeScript类型安全,使用:
typeas consttypescript
// 为弹窗内容类型使用'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
常见问题
-
Popup not showing: Ensure layer has(default)
popupEnabled: true -
Hit test returns nothing: Check if layers are included/excluded correctly
-
Highlight not visible: Make sure to store the highlight handle and callbefore creating new highlights
remove() -
applyEdits fails: Ensure layer is editable and user has edit permissions
-
Events fire multiple times: Remove event handlers when no longer needed
-
弹窗不显示:确保图层的属性为true(默认值)
popupEnabled -
点击检测无结果:检查图层的包含/排除配置是否正确
-
高亮效果不可见:确保保存高亮句柄,并在创建新高亮前调用
remove() -
applyEdits执行失败:确保图层可编辑且用户拥有编辑权限
-
事件多次触发:不再需要事件处理程序时及时移除