arcgis-popup-templates について
arcgis-popup-templatesは、ArcGISのポップアップを作成・カスタマイズする開発者向けのエージェントスキルです。コンテンツ形式、式、アクション、動的コンテンツ、設定時の注意点を扱います。
主な機能
- 01複数のポップアップコンテンツ形式
- 02フィールドの書式設定と置換
- 03Arcade式のサポート
- 04カスタムポップアップアクション
- 05動的および非同期コンテンツ
- 06設定上の注意点と例
活用シーン
- 01フィーチャーポップアップで属性を表示
- 02チャート、画像、添付ファイルの追加
- 03Arcadeによるポップアップ値の計算
- 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 対応