关于 arcgis-popup-templates
arcgis-popup-templates 是面向 ArcGIS 开发者的 Agent 技能,用于创建和定制弹出窗口,涵盖内容类型、表达式、操作、动态内容及常见配置问题。
主要功能
- 01多种弹出窗口内容类型
- 02字段格式化与替换
- 03支持 Arcade 表达式
- 04自定义弹出窗口操作
- 05动态与异步内容
- 06配置注意事项与示例
适用场景
- 01在要素弹窗中显示属性
- 02添加图表、图像或附件
- 03使用 Arcade 计算弹窗值
- 04为地图弹窗创建自定义操作
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ saschabrunnerch/ arcgis-maps-sdk-js-ai-context --skill arcgis-popup-templates安装后在 Claude Code 中输入/arcgis-popup-templates确认已加载。
详细介绍
ArcGIS 弹出窗口模板
使用此技能创建和自定义包含各种内容类型的弹出窗口模板。
导入模式
直接 ESM 导入
import PopupTemplate from "@arcgis/core/PopupTemplate.js";
import CustomContent from "@arcgis/core/popup/content/CustomContent.js";
动态导入(CDN)
const PopupTemplate = await $arcgis.import("@arcgis/core/PopupTemplate.js");
const CustomContent = await $arcgis.import(
"@arcgis/core/popup/content/CustomContent.js",
);
**注意:**此技能中的示例使用直接 ESM 导入。若要使用 CDN,请将
import X from "path"替换为const X = await $arcgis.import("path")。
PopupTemplate 概述
| 内容类型 | 用途 |
|---|---|
| TextContent | HTML 或纯文本 |
| FieldsContent | 属性表 |
| MediaContent | 图表和图像 |
| AttachmentsContent | 文件附件 |
| ExpressionContent | Arcade 表达式结果 |
| CustomContent | 自定义 HTML/JavaScript |
| RelationshipContent | 相关记录 |
PopupTemplate 属性
| 属性 | 类型 | 说明 |
|---|---|---|
title | string | Function | object | 标题,可替换字段({fieldName}) |
content | string | Array | Function | Promise | 内容定义 |
fieldInfos | FieldInfo[] | 默认字段格式 |
expressionInfos | ExpressionInfo[] | Arcade 表达式定义 |
outFields | string[] | 为弹出窗口检索的字段 |
actions | ActionButton[] | ActionToggle[] | 自定义操作按钮 |
overwriteActions | boolean | 替换默认弹出窗口操作 |
returnGeometry | boolean | 在弹出窗口结果中包含几何 |
基本 PopupTemplate
layer.popupTemplate = {
title: "{name}",
content: "Population: {population}<br>Area: {area} sq mi",
};
使用字段替换
layer.popupTemplate = {
title: "{city_name}, {state}",
content: `
<h3>Demographics</h3>
<p>Population: {population:NumberFormat(places: 0)}</p>
<p>Median Income: {median_income:NumberFormat(digitSeparator: true, places: 0)}</p>
<p>Founded: {founded_date:DateFormat(selector: 'date', datePattern: 'MMMM d, yyyy')}</p>
`,
};
内容数组(多种内容类型)
layer.popupTemplate = {
title: "{name}",
content: [
{
type: "text",
text: "<b>Overview</b><br>{description}",
},
{
type: "fields",
fieldInfos: [
{ fieldName: "population", label: "Population" },
{ fieldName: "area", label: "Area (sq mi)" },
],
},
{
type: "media",
mediaInfos: [
{
type: "pie-chart",
title: "Demographics",
value: {
fields: ["white", "black", "asian", "other"],
},
},
],
},
],
};
内容类型
TextContent
{
type: "text",
text: `
<div style="padding: 10px;">
<h2>{name}</h2>
<p>{description}</p>
<a href="{website}" target="_blank">Visit Website</a>
</div>
`
}
FieldsContent
{
type: "fields",
fieldInfos: [
{
fieldName: "name",
label: "Name"
},
{
fieldName: "population",
label: "Population",
format: {
digitSeparator: true,
places: 0
}
},
{
fieldName: "date_created",
label: "Created",
format: {
dateFormat: "short-date"
}
}
]
}
日期格式
short-date- 12/30/2024short-date-short-time- 12/30/2024, 3:30 PMshort-date-long-time- 12/30/2024, 3:30:45 PMlong-month-day-year- December 30, 2024day-short-month-year- 30 Dec 2024year- 2024
MediaContent
{
type: "media",
mediaInfos: [
{
title: "Sales by Quarter",
type: "column-chart", // bar-chart, pie-chart, line-chart, column-chart, image
value: {
fields: ["q1_sales", "q2_sales", "q3_sales", "q4_sales"],
normalizeField: "total_sales" // Optional
}
}
]
}
图表类型
| 类型 | 使用场景 |
|---|---|
bar-chart | 用于分类比较的水平条形图 |
pie-chart | 比例分布 |
line-chart | 显示系列趋势 |
column-chart | 用于比较的垂直条形图 |
image | 显示来自 URL 字段的图像 |
Image MediaInfo:
{
type: "image",
title: "Property Photo",
value: {
sourceURL: "{image_url}",
linkURL: "{detail_page_url}"
}
}
AttachmentsContent
{
type: "attachments",
displayType: "preview", // preview, list, auto
title: "Photos"
}
ExpressionContent
layer.popupTemplate = {
expressionInfos: [
{
name: "population-density",
title: "Population Density",
expression: "Round($feature.population / $feature.area, 2)",
},
{
name: "age-category",
title: "Age Category",
expression: `
var age = $feature.building_age;
if (age < 25) return "New";
if (age < 50) return "Moderate";
return "Historic";
`,
},
],
content: [
{
type: "expression",
expressionInfo: {
name: "population-density",
},
},
],
};
CustomContent
import CustomContent from "@arcgis/core/popup/content/CustomContent.js";
const customContent = new CustomContent({
outFields: ["*"],
creator: (event) => {
const div = document.createElement("div");
const graphic = event.graphic;
div.innerHTML = `
<div class="custom-popup">
<h3>${graphic.attributes.name}</h3>
<canvas id="chart-${graphic.attributes.OBJECTID}"></canvas>
</div>
`;
return div;
},
});
layer.popupTemplate = {
title: "{name}",
content: [customContent],
};
RelationshipContent
{
type: "relationship",
relationshipId: 0,
title: "Related Inspections",
displayCount: 5,
orderByFields: [
{
field: "inspection_date",
order: "desc"
}
]
}
弹出窗口组件
<arcgis-popup> 组件用于控制弹出窗口的显示。
主要属性:
| 属性 | 类型 | 描述 |
|---|---|---|
actions | Collection | 自定义操作按钮 |
content | string | Node | Widget | 弹出窗口内容 |
dock-options | object | 停靠行为配置 |
features | Graphic[] | 要显示的要素 |
heading | string | 弹出窗口标题文本 |
heading-level | number | 标题级别(1-6) |
include-default-actions-disabled | boolean | 禁用默认的缩放至操作 |
initial-display-mode | string | 初始显示模式 |
location | Point | 弹出窗口锚点位置 |
open | boolean | 弹出窗口是否打开 |
selected-feature | Graphic | 当前选中的要素 |
selected-feature-index | number | 选中要素的索引 |
主要事件:
| 事件 | 描述 |
|---|---|
arcgisTriggerAction | 点击自定义操作时触发 |
操作
为弹出窗口添加自定义按钮。
layer.popupTemplate = {
title: "{name}",
content: "...",
actions: [
{
id: "zoom-to",
title: "Zoom To",
className: "esri-icon-zoom-in-magnifying-glass",
},
{
id: "edit",
title: "Edit",
className: "esri-icon-edit",
},
],
};
// Handle action clicks using reactiveUtils
import * as reactiveUtils from "@arcgis/core/core/reactiveUtils.js";
reactiveUtils.on(
() => view.popup,
"trigger-action",
(event) => {
if (event.action.id === "zoom-to") {
view.goTo(view.popup.selectedFeature);
} else if (event.action.id === "edit") {
startEditing(view.popup.selectedFeature);
}
},
);
操作按钮类型
// Icon button
{ id: "info", title: "More Info", className: "esri-icon-description" }
// Toggle button
{ id: "highlight", title: "Highlight", type: "toggle", value: false }
使用函数动态生成内容
将内容设为函数
layer.popupTemplate = {
title: "{name}",
outFields: ["*"],
content: (feature) => {
const attributes = feature.graphic.attributes;
if (attributes.type === "residential") {
return `
<h3>Residential Property</h3>
<p>Bedrooms: ${attributes.bedrooms}</p>
<p>Bathrooms: ${attributes.bathrooms}</p>
`;
} else {
return `
<h3>Commercial Property</h3>
<p>Square Footage: ${attributes.sqft}</p>
`;
}
},
};
异步内容函数
layer.popupTemplate = {
title: "{name}",
outFields: ["*"],
content: async (feature) => {
const id = feature.graphic.attributes.OBJECTID;
const response = await fetch(`/api/details/${id}`);
const data = await response.json();
return `
<h3>${data.title}</h3>
<p>${data.description}</p>
`;
},
};
Arcade 表达式
在标题中使用
layer.popupTemplate = {
title: {
expression: `
var name = $feature.name;
var status = $feature.status;
return name + " (" + status + ")";
`,
},
content: "...",
};
字段中的表达式信息
layer.popupTemplate = {
expressionInfos: [
{
name: "formatted-date",
title: "Formatted Date",
expression: 'Text($feature.created_date, "MMMM D, YYYY")',
},
{
name: "calculated-field",
title: "Density",
expression:
"Round($feature.population / AreaGeodetic($feature, 'square-miles'), 1)",
},
],
content: [
{
type: "fields",
fieldInfos: [
{ fieldName: "expression/formatted-date", label: "Created" },
{
fieldName: "expression/calculated-field",
label: "Population Density",
},
],
},
],
};
OutFields
layer.popupTemplate = {
title: "{name}",
content: "...",
outFields: ["name", "population", "area", "created_date"],
};
// All fields
layer.popupTemplate = {
title: "{name}",
content: "...",
outFields: ["*"],
};
聚类弹出窗口
layer.featureReduction = {
type: "cluster",
clusterRadius: 80,
popupTemplate: {
title: "Cluster of {cluster_count} features",
content: [
{
type: "fields",
fieldInfos: [
{
fieldName: "cluster_count",
label: "Features in cluster",
},
{
fieldName: "cluster_avg_population",
label: "Average Population",
format: { digitSeparator: true, places: 0 },
},
],
},
],
},
fields: [
{
name: "cluster_avg_population",
alias: "Average Population",
onStatisticField: "population",
statisticType: "avg",
},
],
};
完整示例:地图组件
<!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="gray-vector" center="-73.95,40.70" zoom="11">
<arcgis-zoom slot="top-left"></arcgis-zoom>
<arcgis-legend slot="bottom-left"></arcgis-legend>
</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 template = {
title: "Marriage in {NAME} Census Tract {TRACT}",
content: [
{
type: "fields",
fieldInfos: [
{
fieldName: "B12001_calc_pctMarriedE",
label: "Married %",
format: { digitSeparator: true, places: 1 },
},
{
fieldName: "B12001_calc_pctNeverE",
label: "Never Married %",
format: { digitSeparator: true, places: 1 },
},
],
},
],
};
const featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/ACS_Marital_Status_Boundaries/FeatureServer/2",
popupTemplate: template,
});
mapElement.map.add(featureLayer);
</script>
</body>
</html>
参考示例
intro-popuptemplate- PopupTemplate 基本配置get-started-popuptemplate- PopupTemplate 入门popup-actions- 为弹出窗口添加自定义操作popup-custom-action- 使用几何运算符的自定义弹出窗口操作popup-customcontent- 自定义弹出窗口内容元素popuptemplate-arcade- 在弹出窗口中使用 Arcade 表达式popuptemplate-arcade-expression-content- Arcade 表达式内容popup-multipleelements- 弹出窗口中的多个内容元素popuptemplate-function- 基于函数的弹出窗口内容popuptemplate-promise- 基于 Promise 的弹出窗口内容popuptemplate-browse-related-records- 弹出窗口中的相关记录
常见问题
-
字段名称区分大小写:字段名称必须完全匹配。
// If field is "Population" (capital P) content: "{Population}"; // Correct content: "{population}"; // Wrong - shows literal {population} -
必须设置 OutFields:使用函数内容时,弹出窗口中用到的字段必须包含在 outFields 中。
popupTemplate: { title: "{name}", outFields: ["name", "description"], // Required for function content content: (feature) => { return feature.graphic.attributes.description; } } -
表达式引用:在 fieldInfos 中使用 Arcade 表达式时,需添加
expression/前缀。fieldInfos: [{ fieldName: "expression/my-expression", label: "Calculated" }]; -
异步内容必须有返回值:函数内容必须返回一个值或 Promise。
// Wrong - no return content: (feature) => { const div = document.createElement("div"); }; // Correct content: (feature) => { const div = document.createElement("div"); return div; }; -
GeoJSON 字段路径:GeoJSON 的字段名称必须使用
properties/前缀。// GeoJSON title: "{properties/name}"; // Regular FeatureLayer title: "{name}";
相关技能
- 有关命中测试和事件处理,请参阅
arcgis-interaction。 - 有关要素编辑工作流,请参阅
arcgis-editing。 - 有关 Arcade 表达式语法的详细信息,请参阅
arcgis-arcade。
评论
支持 Markdown