mcpField
A
arcgis-popup-templates

arcgis-popup-templates

github.com/saschabrunnerch设计与 UI2383 次安装29 周前更新
代码仓库

关于 arcgis-popup-templates

arcgis-popup-templates 是面向 ArcGIS 开发者的 Agent 技能,用于创建和定制弹出窗口,涵盖内容类型、表达式、操作、动态内容及常见配置问题。

主要功能

  1. 01多种弹出窗口内容类型
  2. 02字段格式化与替换
  3. 03支持 Arcade 表达式
  4. 04自定义弹出窗口操作
  5. 05动态与异步内容
  6. 06配置注意事项与示例

适用场景

  1. 01在要素弹窗中显示属性
  2. 02添加图表、图像或附件
  3. 03使用 Arcade 计算弹窗值
  4. 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 概述

内容类型用途
TextContentHTML 或纯文本
FieldsContent属性表
MediaContent图表和图像
AttachmentsContent文件附件
ExpressionContentArcade 表达式结果
CustomContent自定义 HTML/JavaScript
RelationshipContent相关记录
PopupTemplate 属性
属性类型说明
titlestring | Function | object标题,可替换字段({fieldName})
contentstring | Array | Function | Promise内容定义
fieldInfosFieldInfo[]默认字段格式
expressionInfosExpressionInfo[]Arcade 表达式定义
outFieldsstring[]为弹出窗口检索的字段
actionsActionButton[] | ActionToggle[]自定义操作按钮
overwriteActionsboolean替换默认弹出窗口操作
returnGeometryboolean在弹出窗口结果中包含几何

基本 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/2024
  • short-date-short-time - 12/30/2024, 3:30 PM
  • short-date-long-time - 12/30/2024, 3:30:45 PM
  • long-month-day-year - December 30, 2024
  • day-short-month-year - 30 Dec 2024
  • year - 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> 组件用于控制弹出窗口的显示。

主要属性:

属性类型描述
actionsCollection自定义操作按钮
contentstring | Node | Widget弹出窗口内容
dock-optionsobject停靠行为配置
featuresGraphic[]要显示的要素
headingstring弹出窗口标题文本
heading-levelnumber标题级别(1-6)
include-default-actions-disabledboolean禁用默认的缩放至操作
initial-display-modestring初始显示模式
locationPoint弹出窗口锚点位置
openboolean弹出窗口是否打开
selected-featureGraphic当前选中的要素
selected-feature-indexnumber选中要素的索引

主要事件:

事件描述
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 - 弹出窗口中的相关记录

常见问题

  1. 字段名称区分大小写:字段名称必须完全匹配。

    // If field is "Population" (capital P)
    content: "{Population}"; // Correct
    content: "{population}"; // Wrong - shows literal {population}
    
  2. 必须设置 OutFields:使用函数内容时,弹出窗口中用到的字段必须包含在 outFields 中。

    popupTemplate: {
      title: "{name}",
      outFields: ["name", "description"],  // Required for function content
      content: (feature) => {
        return feature.graphic.attributes.description;
      }
    }
    
  3. 表达式引用:在 fieldInfos 中使用 Arcade 表达式时,需添加 expression/ 前缀。

    fieldInfos: [{ fieldName: "expression/my-expression", label: "Calculated" }];
    
  4. 异步内容必须有返回值:函数内容必须返回一个值或 Promise。

    // Wrong - no return
    content: (feature) => {
      const div = document.createElement("div");
    };
    
    // Correct
    content: (feature) => {
      const div = document.createElement("div");
      return div;
    };
    
  5. GeoJSON 字段路径:GeoJSON 的字段名称必须使用 properties/ 前缀。

    // GeoJSON
    title: "{properties/name}";
    // Regular FeatureLayer
    title: "{name}";
    

相关技能

  • 有关命中测试和事件处理,请参阅 arcgis-interaction。
  • 有关要素编辑工作流,请参阅 arcgis-editing。
  • 有关 Arcade 表达式语法的详细信息,请参阅 arcgis-arcade。

评论

支持 Markdown