关于 arcgis-editing
arcgis-editing 是面向 ArcGIS 开发者的编辑技能,涵盖 Editor、表单、要素修改和版本管理。它还提供附件、子类型及相关记录的操作参考。
主要功能
- 01配置 Editor 和图层编辑能力
- 02构建并验证要素表单
- 03使用 applyEdits 修改要素
- 04管理子类型与分支版本
- 05查询和处理附件及相关记录
适用场景
- 01为地图应用添加要素创建和编辑界面
- 02按图层配置属性、几何和附件编辑
- 03在分支版本中开展协作编辑
- 04以代码批量添加或更新要素
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ saschabrunnerch/ arcgis-maps-sdk-js-ai-context --skill arcgis-editing安装后在 Claude Code 中输入/arcgis-editing确认已加载。
附带文件AGENTS.md
详细介绍
ArcGIS 编辑
使用此技能编辑要素,包括配置 Editor、表单模板、子类型、附件、版本管理和程序化编辑。
导入模式
直接 ESM 导入
import Editor from "@arcgis/core/widgets/Editor.js";
import FeatureForm from "@arcgis/core/widgets/FeatureForm.js";
import FormTemplate from "@arcgis/core/form/FormTemplate.js";
动态导入(CDN)
const Editor = await $arcgis.import("@arcgis/core/widgets/Editor.js");
const FeatureForm = await $arcgis.import("@arcgis/core/widgets/FeatureForm.js");
const FormTemplate = await $arcgis.import("@arcgis/core/form/FormTemplate.js");
注意: 此技能中的示例使用直接 ESM 导入。若要使用 CDN,请将
import X from "path"替换为const X = await $arcgis.import("path")。
Editor 组件
添加编辑功能最简单的方式是使用 <arcgis-editor> 组件。
基本用法
<arcgis-map item-id="YOUR_EDITABLE_WEBMAP_ID">
<arcgis-editor slot="top-right"></arcgis-editor>
</arcgis-map>
主要属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
heading-level | number | 用于无障碍访问的标题级别 | |
hide-create-features-section | boolean | false | 隐藏创建要素面板 |
hide-edit-features-section | boolean | false | 隐藏编辑要素面板 |
hide-labels-toggle | boolean | false | 隐藏标签切换开关 |
hide-merge-button | boolean | false | 隐藏合并要素按钮 |
hide-settings-menu | boolean | false | 隐藏设置菜单 |
hide-sketch | boolean | false | 隐藏草图工具 |
hide-split-button | boolean | false | 隐藏拆分要素按钮 |
hide-tooltips-toggle | boolean | false | 隐藏工具提示切换开关 |
hide-undo-redo-buttons | boolean | false | 隐藏撤消/重做按钮 |
hide-zoom-to-button | boolean | false | 隐藏缩放至按钮 |
label | string | 组件标签 | |
layer-infos | LayerInfo[] | 图层编辑配置 | |
snapping-options | SnappingOptions | 捕捉配置 | |
sync-view-selection | boolean | false | 将选择与视图同步 |
主要事件
| 事件 | 说明 |
|---|---|
arcgisSketchCreate | 创建要素草图时触发 |
arcgisSketchUpdate | 更新要素草图时触发 |
arcgisPropertyChange | activeWorkflow 或 state 更改时触发 |
arcgisReady | 组件就绪时触发 |
主要方法
| 方法 | 说明 |
|---|---|
cancelWorkflow() | 取消当前编辑工作流 |
deleteFeatureFromWorkflow() | 删除正在编辑的要素 |
startCreateFeaturesWorkflowAtFeatureTypeSelection() | 开始创建要素 |
startUpdateWorkflowAtFeatureEdit(feature) | 开始编辑指定要素 |
startUpdateWorkflowAtFeatureSelection() | 开始选择要更新的要素 |
配置 Editor 组件
<arcgis-map basemap="streets-navigation-vector">
<arcgis-editor slot="top-right"></arcgis-editor>
</arcgis-map>
<script type="module">
const FeatureLayer = await $arcgis.import(
"@arcgis/core/layers/FeatureLayer.js",
);
const mapElement = document.querySelector("arcgis-map");
const view = await mapElement.view;
await view.when();
const layer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
});
mapElement.map.add(layer);
const editor = document.querySelector("arcgis-editor");
editor.layerInfos = [
{
layer: layer,
formTemplate: {
title: "Edit Feature",
elements: [
{ type: "field", fieldName: "name", label: "Name" },
{ type: "field", fieldName: "category", label: "Category" },
],
},
addEnabled: true,
updateEnabled: true,
deleteEnabled: false,
},
];
</script>
Editor 微件(Core API)
可配置的 Editor
import Editor from "@arcgis/core/widgets/Editor.js";
const editor = new Editor({
view: view,
layerInfos: [
{
layer: featureLayer,
formTemplate: {
title: "Feature Details",
description: "Enter feature information",
elements: [
{
type: "field",
fieldName: "name",
label: "Name",
description: "Enter the feature name",
},
{
type: "field",
fieldName: "category",
label: "Category",
},
],
},
addEnabled: true,
updateEnabled: true,
deleteEnabled: false,
},
],
});
view.ui.add(editor, "top-right");
LayerInfo 配置
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
layer | FeatureLayer | 必填 | 要编辑的图层 |
formTemplate | FormTemplate | 表单配置 | |
enabled | boolean | true | 启用图层编辑 |
addEnabled | boolean | true | 允许创建要素 |
updateEnabled | boolean | true | 允许更新要素 |
deleteEnabled | boolean | true | 允许删除要素 |
geometryUpdatesEnabled | boolean | true | 允许编辑几何 |
attributeUpdatesEnabled | boolean | true | 允许编辑属性 |
attachmentsOnCreateEnabled | boolean | true | 创建要素时允许添加附件 |
attachmentsOnUpdateEnabled | boolean | true | 更新要素时允许添加附件 |
要素表单
独立要素表单
import FeatureForm from "@arcgis/core/widgets/FeatureForm.js";
const form = new FeatureForm({
container: "formDiv",
layer: featureLayer,
formTemplate: {
title: "Edit Feature",
elements: [
{
type: "field",
fieldName: "name",
label: "Name",
},
{
type: "group",
label: "Location Details",
elements: [
{ type: "field", fieldName: "address" },
{ type: "field", fieldName: "city" },
{ type: "field", fieldName: "zip" },
],
},
],
},
});
// Set feature to edit
form.feature = graphic;
// Listen for submit
form.on("submit", async () => {
if (form.valid) {
const values = form.getValues();
graphic.attributes = { ...graphic.attributes, ...values };
await featureLayer.applyEdits({
updateFeatures: [graphic],
});
}
});
要素表单组件
<arcgis-feature-form></arcgis-feature-form>
<script type="module">
const featureForm = document.querySelector("arcgis-feature-form");
// Configure the form
featureForm.formTemplate = {
title: "Edit Feature",
elements: [
{ type: "field", fieldName: "name", label: "Name" },
{ type: "field", fieldName: "status", label: "Status" },
],
};
// Set feature to edit
featureForm.feature = selectedGraphic;
// Listen for value changes
featureForm.addEventListener("arcgisValueChange", (event) => {
console.log("Field changed:", event.detail.fieldName, event.detail.value);
});
// Listen for submit
featureForm.addEventListener("arcgisSubmit", (event) => {
console.log("Form submitted");
});
</script>
带分组元素的表单
const formTemplate = {
title: "Asset Details",
elements: [
{
type: "group",
label: "Basic Information",
elements: [
{ type: "field", fieldName: "asset_id" },
{ type: "field", fieldName: "asset_name" },
{ type: "field", fieldName: "asset_type" },
],
},
{
type: "group",
label: "Maintenance",
initialState: "collapsed",
elements: [
{ type: "field", fieldName: "last_inspection" },
{ type: "field", fieldName: "next_inspection" },
{ type: "field", fieldName: "condition" },
],
},
],
};
基于表达式的可见性
const formTemplate = {
expressionInfos: [
{
name: "type-requires-subtype",
expression: "$feature.type == 'complex'",
},
],
elements: [
{
type: "field",
fieldName: "type",
},
{
type: "field",
fieldName: "subtype",
visibilityExpression: "type-requires-subtype",
},
],
};
表单验证
const form = new FeatureForm({
layer: featureLayer,
formTemplate: {
elements: [
{
type: "field",
fieldName: "email",
label: "Email",
requiredExpression: "email-required",
},
],
expressionInfos: [
{
name: "email-required",
expression: "$feature.contact_method == 'email'",
},
],
},
});
// Available expression types on FieldElement:
// - visibilityExpression: controls field visibility
// - editableExpression: controls whether field is editable
// - requiredExpression: controls whether field is required
// - valueExpression: computes a calculated value for the field
if (form.valid) {
// Submit
}
以编程方式编辑(applyEdits)
// Add features
const addResult = await featureLayer.applyEdits({
addFeatures: [
{
attributes: {
name: "New Feature",
category: "Type A",
},
geometry: {
type: "point",
longitude: -118.805,
latitude: 34.027,
},
},
],
});
// Update features
const updateResult = await featureLayer.applyEdits({
updateFeatures: [
{
attributes: {
OBJECTID: 123,
name: "Updated Name",
},
},
],
});
// Delete features
const deleteResult = await featureLayer.applyEdits({
deleteFeatures: [{ objectId: 123 }],
});
// Check results
addResult.addFeatureResults.forEach((result) => {
if (result.error) {
console.error("Add failed:", result.error.message);
} else {
console.log("Added feature OID:", result.objectId);
}
});
子类型
使用子类型
const layer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
});
await layer.load();
const subtypeField = layer.subtypeField;
const subtypes = layer.subtypes;
subtypes.forEach((subtype) => {
console.log("Code:", subtype.code);
console.log("Name:", subtype.name);
console.log("Default values:", subtype.defaultValues);
});
子类型组图层
import SubtypeGroupLayer from "@arcgis/core/layers/SubtypeGroupLayer.js";
const subtypeLayer = new SubtypeGroupLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
});
await subtypeLayer.load();
// Access sublayers by subtype
subtypeLayer.sublayers.forEach((sublayer) => {
console.log("Subtype:", sublayer.subtypeCode, sublayer.title);
// Each sublayer can have different renderer/popup
});
支持子类型的 Editor
const editor = new Editor({
view: view,
layerInfos: [
{
layer: subtypeGroupLayer,
addEnabled: true,
updateEnabled: true,
},
],
});
版本控制
分支版本控制概述
分支版本控制允许多个用户同时编辑相同的数据,并在协调之前避免冲突。
import VersionManagementService from "@arcgis/core/versionManagement/VersionManagementService.js";
const vms = new VersionManagementService({
url: "https://services.arcgis.com/.../VersionManagementServer",
});
await vms.load();
console.log("Default version:", vms.defaultVersionIdentifier);
获取版本信息
const versions = await vms.getVersionInfos();
versions.forEach((v) => {
console.log("Version:", v.versionName);
console.log(" Owner:", v.versionOwner);
console.log(" Access:", v.access); // public, protected, private
console.log(" Parent:", v.parentVersionName);
});
创建、更改和删除版本
// Create new version
const newVersion = await vms.createVersion({
versionName: "MyEditVersion",
description: "Version for editing project X",
access: "private",
parentVersionName: "sde.DEFAULT",
});
// Alter version properties
await vms.alterVersion({
versionName: "sde.MyEditVersion",
description: "Updated description",
access: "protected",
});
// Delete a version
await vms.deleteVersion({
versionName: "sde.MyEditVersion",
});
切换版本
// Set version on layer at creation
const featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
gdbVersion: "sde.MyEditVersion",
});
// Or change version dynamically
await featureLayer.load();
featureLayer.gdbVersion = "sde.AnotherVersion";
await featureLayer.refresh();
编辑会话与协调
const versionIdentifier = version.versionIdentifier;
// Start editing session
await vms.startEditing({ versionIdentifier });
// Apply edits to feature layer
await featureLayer.applyEdits(edits);
// Reconcile with parent
const reconcileResult = await vms.reconcile({
versionIdentifier: versionIdentifier,
abortIfConflicts: false,
conflictDetection: "by-attribute",
conflictResolution: "favorEditVersion",
withPost: false,
});
if (!reconcileResult.hasConflicts) {
await vms.post({ versionIdentifier });
}
// Stop editing
await vms.stopEditing({
versionIdentifier: versionIdentifier,
saveEdits: true,
});
完整的版本工作流
async function editInVersion(vms, featureLayer, edits) {
const version = await vms.createVersion({
versionName: `Edit_${Date.now()}`,
description: "Temporary edit version",
access: "private",
});
const versionIdentifier = version.versionIdentifier;
try {
featureLayer.gdbVersion = version.versionName;
await featureLayer.refresh();
await vms.startEditing({ versionIdentifier });
await featureLayer.applyEdits(edits);
const result = await vms.reconcile({
versionIdentifier,
abortIfConflicts: false,
conflictResolution: "favorEditVersion",
withPost: false,
});
if (result.hasConflicts) {
throw new Error("Conflicts detected during reconcile");
}
await vms.post({ versionIdentifier });
await vms.stopEditing({ versionIdentifier, saveEdits: true });
} finally {
featureLayer.gdbVersion = vms.defaultVersionIdentifier;
await featureLayer.refresh();
await vms.deleteVersion({ versionName: version.versionName });
}
}
相关记录
查询相关记录
const relatedRecords = await layer.queryRelatedFeatures({
outFields: ["*"],
relationshipId: 0,
objectIds: [selectedFeature.attributes.OBJECTID],
});
const results = relatedRecords[selectedFeature.attributes.OBJECTID];
results.features.forEach((related) => {
console.log("Related:", related.attributes);
});
附件
在 Editor 中启用附件
const editor = new Editor({
view: view,
layerInfos: [
{
layer: featureLayer,
attachmentsOnCreateEnabled: true,
attachmentsOnUpdateEnabled: true,
},
],
});
以编程方式处理附件
// Query attachments
const attachments = await layer.queryAttachments({
objectIds: [featureOID],
});
// Add attachment
const formData = new FormData();
formData.append("attachment", fileBlob, "photo.jpg");
await layer.addAttachment(featureOID, formData);
// Delete attachment
await layer.deleteAttachments(featureOID, [attachmentId]);
完整示例:地图组件
<!DOCTYPE html>
<html>
<head>
<script src="https://js.arcgis.com/5.0/"></script>
<script
type="module"
src="https://js.arcgis.com/5.0/map-components/"
></script>
<style>
html,
body {
height: 100%;
margin: 0;
}
</style>
</head>
<body>
<arcgis-map
basemap="streets-navigation-vector"
center="-118.805,34.027"
zoom="13"
>
<arcgis-zoom slot="top-left"></arcgis-zoom>
<arcgis-editor slot="top-right"></arcgis-editor>
</arcgis-map>
<script type="module">
const FeatureLayer = await $arcgis.import(
"@arcgis/core/layers/FeatureLayer.js",
);
const mapElement = document.querySelector("arcgis-map");
const view = await mapElement.view;
await view.when();
const layer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
});
mapElement.map.add(layer);
const editor = document.querySelector("arcgis-editor");
editor.layerInfos = [
{
layer: layer,
formTemplate: {
title: "Edit Feature",
elements: [
{
type: "group",
label: "Details",
elements: [
{ type: "field", fieldName: "name", label: "Name" },
{ type: "field", fieldName: "type", label: "Type" },
{ type: "field", fieldName: "status", label: "Status" },
],
},
],
},
attachmentsOnCreateEnabled: true,
attachmentsOnUpdateEnabled: true,
},
];
</script>
</body>
</html>
参考示例
editor-basic- Editor 组件的基本用法widgets-editor-configurable- 带有 layerInfos 的可配置 Editor 微件widgets-editor-subtypes- 使用子类型组图层进行编辑widgets-editor-form-elements- Editor 中的表单元素配置editing-applyedits- 使用 applyEdits 以编程方式编辑editing-groupedfeatureform- 分组要素表单布局editing-featureform-fieldvisibility- 控制字段可见性changing-version- 切换地理数据库版本
常见问题
-
编辑权限:在检查编辑能力之前就对图层调用
applyEdits,会导致静默失败。// Anti-pattern: calling applyEdits without checking capabilities const layer = new FeatureLayer({ url: "https://services.arcgis.com/.../FeatureServer/0", }); await layer.applyEdits({ addFeatures: [newFeature] });// Correct: check capabilities before editing const layer = new FeatureLayer({ url: "https://services.arcgis.com/.../FeatureServer/0", }); await layer.load(); if ( layer.editingEnabled && layer.capabilities?.editing?.supportsAddingFeatures ) { await layer.applyEdits({ addFeatures: [newFeature] }); } else { console.error("Layer does not support adding features"); }影响:
applyEdits调用会因难以理解的服务器错误而失败,或静默返回容易被忽略的错误结果。 -
版本锁定:编辑分支版本数据时未妥善管理会话,会导致版本锁定。
// Anti-pattern: editing without version management session layer.gdbVersion = "editor1.design_v1"; await layer.applyEdits({ updateFeatures: [updatedFeature] }); // Version remains locked, blocking other users// Correct: use proper version management session await vms.startEditing({ versionIdentifier }); layer.gdbVersion = "editor1.design_v1"; await layer.applyEdits({ updateFeatures: [updatedFeature] }); await vms.stopEditing({ versionIdentifier, saveEdits: true });影响: 编辑后版本仍处于锁定状态,导致其他用户无法访问或编辑该版本。
-
检查 applyEdits 结果:始终检查结果对象中的各个要素错误。
const result = await layer.applyEdits({ addFeatures: [feature1, feature2] }); result.addFeatureResults.forEach((res) => { if (res.error) { console.error("Failed to add feature:", res.error.message); } }); -
表单表达式名称:必须通过名称字符串引用表达式,而不是使用表达式文本。
expressionInfos: [{ name: "my-expr", expression: "$feature.type == 'A'" }], elements: [{ visibilityExpression: "my-expr" // String reference to name }] -
子类型字段:必须与服务中的子类型配置完全一致。
相关技能
- 请参阅
arcgis-tables-forms,了解 FeatureTable 和 FormTemplate 输入类型。 - 请参阅
arcgis-interaction,了解命中测试和草图绘制。 - 请参阅
arcgis-layers,了解 FeatureLayer 配置。 - 请参阅
arcgis-core-maps,了解自动类型转换指南。
评论
支持 Markdown