mcpField
A
arcgis-widgets-ui

arcgis-widgets-ui

github.com/saschabrunnerchデザイン・UI2395 回インストール29 週間前に更新
リポジトリ

arcgis-widgets-ui について

arcgis-widgets-uiは、ArcGIS Map Components、Core API widgets、Calciteを使った地図UI構築のスキルです。地図アプリのUIを開発する人向けに、コンポーネント選択、配置、イベント、設定時の注意点を解説します。

主な機能

  1. 01マップ・シーンコンポーネントの利用
  2. 02レイヤー・検索・凡例ウィジェットの設定
  3. 03スロットによるコンポーネント配置
  4. 04Calcite UIコンポーネントの統合
  5. 05ウィジェットイベントとスタイルの処理

活用シーン

  1. 01地図アプリに検索と凡例を追加
  2. 02折りたたみ式の地図ウィジェットパネルを構築
  3. 03地図画面にタイムスライダーを表示
  4. 04Calciteでアプリのレイアウトを構成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/saschabrunnerch/arcgis-maps-sdk-js-ai-context --skill arcgis-widgets-ui

インストール後、Claude Code で/arcgis-widgets-uiを入力して読み込まれたか確認します。

同梱ファイルAGENTS.md

詳細

ArcGIS ウィジェットと UI

ウィジェット、Map Components、Calcite を使ってユーザーインターフェースを構築する際に、このスキルを使用してください。

ベストプラクティス: Core API ウィジェットよりも、Map Components(arcgis-legend や arcgis-search などの Web コンポーネント)を優先してください。Esri は Web コンポーネントを主要なアプローチとして採用しています。

インポートパターン

Map Components(ESM)
import "@arcgis/map-components/dist/components/arcgis-map";
import "@arcgis/map-components/dist/components/arcgis-legend";
import "@arcgis/map-components/dist/components/arcgis-search";
import "@arcgis/map-components/dist/components/arcgis-layer-list";
import "@arcgis/map-components/dist/components/arcgis-expand";
Core API ウィジェット(ESM)
import Legend from "@arcgis/core/widgets/Legend.js";
import LayerList from "@arcgis/core/widgets/LayerList.js";
import Search from "@arcgis/core/widgets/Search.js";
import BasemapGallery from "@arcgis/core/widgets/BasemapGallery.js";
動的インポート(CDN)
const Legend = await $arcgis.import("@arcgis/core/widgets/Legend.js");
const Search = await $arcgis.import("@arcgis/core/widgets/Search.js");

注: Map Components の CSS は npm 経由で自動的に読み込まれます。Core API ウィジェットでは、@import "@arcgis/core/assets/esri/themes/light/main.css"; が必要です。

マップコンポーネントの概要

コンポーネント目的
arcgis-map2D マップコンテナー
arcgis-scene3D シーンコンテナー
arcgis-zoom拡大/縮小ボタン
arcgis-compass方位インジケーター
arcgis-home初期範囲に戻る
arcgis-locateユーザーの位置を検索
arcgis-trackユーザーの位置を追跡
arcgis-navigation-toggleパン/回転モード(3D)
arcgis-floor-filterフロアレベルで屋内マップをフィルター処理
arcgis-fullscreen全画面表示を切り替え
arcgis-scale-barマップの縮尺を表示
arcgis-legendレイヤーのシンボル凡例
arcgis-layer-listレイヤーの表示設定
arcgis-basemap-galleryベースマップを切り替え
arcgis-basemap-layer-listベースマップレイヤーのレイヤーリスト
arcgis-basemap-toggle2 つのベースマップを切り替え
arcgis-catalog-layer-listCatalogLayer のサブレイヤーを参照
arcgis-search位置検索
arcgis-placementウィジェットの配置を制御
arcgis-popupフィーチャーのポップアップ
arcgis-editorフィーチャーの編集
arcgis-featureポップアップなしでフィーチャー情報を表示
arcgis-feature-formフォームベースの属性編集
arcgis-features複数のフィーチャー情報を表示
arcgis-sketchジオメトリーを描画
arcgis-feature-table表形式のデータビュー
arcgis-time-slider時間的なナビゲーション
arcgis-expand折りたたみ可能なコンテナー
arcgis-printマップの印刷
arcgis-table-listフィーチャーテーブルの一覧表示と管理
arcgis-bookmarksブックマークに移動
arcgis-directionsターンごとのルート案内
arcgis-swipeレイヤーを比較
arcgis-coordinate-conversion座標形式
arcgis-daylight3D ライティングを制御
arcgis-weather3D 気象効果
arcgis-distance-measurement-2d2D 距離の計測
arcgis-area-measurement-2d2D 面積の計測
arcgis-direct-line-measurement-3d3D 線の計測
arcgis-area-measurement-3d3D 面積の計測
arcgis-elevation-profileパスに沿った標高プロファイル
arcgis-line-of-sight見通し解析(3D)
arcgis-slice3D データをスライス
arcgis-shadow-cast影の投影解析(3D)
arcgis-oriented-imagery-viewer指向性画像を表示
arcgis-video-player動画フィードを再生
arcgis-link-chartリンクチャートの可視化
arcgis-utility-network-traceユーティリティーネットワークのトレース
arcgis-version-managementジオデータベースのバージョンを管理

スロットベースの配置

<arcgis-map basemap="streets-vector">
  
  <arcgis-zoom slot="top-left"></arcgis-zoom>
  <arcgis-home slot="top-left"></arcgis-home>
  <arcgis-compass slot="top-left"></arcgis-compass>

  <arcgis-search slot="top-right"></arcgis-search>
  <arcgis-layer-list slot="top-right"></arcgis-layer-list>

  <arcgis-legend slot="bottom-left"></arcgis-legend>
  <arcgis-scale-bar slot="bottom-right"></arcgis-scale-bar>

  
  <arcgis-popup slot="popup"></arcgis-popup>
</arcgis-map>

利用可能なスロット:top-left、top-right、bottom-left、bottom-right、top-start、top-end、bottom-start、bottom-end、popup

同じスロットに配置されたウィジェットは、DOM の順序で垂直に積み重なります。

Expand コンポーネント

折りたたみ可能にするには、ウィジェットを arcgis-expand で囲みます:

<arcgis-map basemap="streets-vector">
  <arcgis-expand slot="top-right" expand-tooltip="Show Legend" mode="floating">
    <arcgis-legend></arcgis-legend>
  </arcgis-expand>

  <arcgis-expand slot="top-left" expanded>
    <arcgis-layer-list></arcgis-layer-list>
  </arcgis-expand>
</arcgis-map>

参照要素(外部コンポーネント)

コンポーネントをマップの外に配置し、参照します:

<calcite-shell>
  <calcite-shell-panel slot="panel-start">
    <arcgis-legend reference-element="arcgis-map"></arcgis-legend>
  </calcite-shell-panel>

  <arcgis-map id="arcgis-map" basemap="topo-vector">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
  </arcgis-map>
</calcite-shell>

よく使われるウィジェット

Legend

<arcgis-legend slot="bottom-left"></arcgis-legend>
// Core API
import Legend from "@arcgis/core/widgets/Legend.js";

const legend = new Legend({
  view: view,
  layerInfos: [
    {
      layer: featureLayer,
      title: "Custom Title",
    },
  ],
});

view.ui.add(legend, "bottom-left");
LayerList

<arcgis-layer-list slot="top-right"></arcgis-layer-list>
// Core API with actions
import LayerList from "@arcgis/core/widgets/LayerList.js";

const layerList = new LayerList({
  view: view,
  listItemCreatedFunction: (event) => {
    const item = event.item;
    item.actionsSections = [
      [
        {
          title: "Zoom to layer",
          icon: "zoom-to-object",
          id: "zoom-to",
        },
      ],
    ];
  },
});

layerList.on("trigger-action", (event) => {
  if (event.action.id === "zoom-to") {
    view.goTo(event.item.layer.fullExtent);
  }
});

view.ui.add(layerList, "top-right");
BasemapGallery

<arcgis-basemap-gallery slot="top-right"></arcgis-basemap-gallery>
// Core API
import BasemapGallery from "@arcgis/core/widgets/BasemapGallery.js";

const basemapGallery = new BasemapGallery({ view: view });
view.ui.add(basemapGallery, "top-right");
Search

<arcgis-search slot="top-right"></arcgis-search>
// Core API with custom sources
import Search from "@arcgis/core/widgets/Search.js";

const search = new Search({
  view: view,
  sources: [
    {
      layer: featureLayer,
      searchFields: ["name", "address"],
      displayField: "name",
      exactMatch: false,
      outFields: ["*"],
      name: "My Layer",
      placeholder: "Search features",
    },
  ],
});

view.ui.add(search, "top-right");

// Events
search.on("select-result", (event) => {
  console.log("Selected:", event.result);
});
FeatureTable

<arcgis-feature-table reference-element="arcgis-map"></arcgis-feature-table>
// Core API
import FeatureTable from "@arcgis/core/widgets/FeatureTable.js";

const featureTable = new FeatureTable({
  view: view,
  layer: featureLayer,
  container: "tableDiv",
  visibleElements: {
    header: true,
    columnMenus: true,
    selectionColumn: true,
  },
  tableTemplate: {
    columnTemplates: [
      { fieldName: "name", label: "Name" },
      { fieldName: "population", label: "Population" },
    ],
  },
});

// Watch selection via highlightIds
featureTable.highlightIds.on("change", (event) => {
  console.log("Selected IDs:", featureTable.highlightIds.toArray());
});
TimeSlider

<arcgis-time-slider
  slot="bottom-right"
  layout="auto"
  mode="time-window"
  time-visible
  loop
>
</arcgis-time-slider>

<script type="module">
  const timeSlider = document.querySelector("arcgis-time-slider");
  const mapEl = document.querySelector("arcgis-map");
  await mapEl.viewOnReady();

  await layer.load();
  timeSlider.fullTimeExtent = layer.timeInfo.fullTimeExtent;
  timeSlider.stops = { interval: layer.timeInfo.interval };
</script>
// Core API
import TimeSlider from "@arcgis/core/widgets/TimeSlider.js";

const timeSlider = new TimeSlider({
  view: view,
  mode: "time-window", // instant, time-window, cumulative-from-start, cumulative-from-end
  fullTimeExtent: layer.timeInfo.fullTimeExtent,
  stops: {
    interval: { value: 1, unit: "hours" },
  },
  playRate: 1000,
  loop: true,
});

view.ui.add(timeSlider, "bottom-right");

// Events
import * as reactiveUtils from "@arcgis/core/core/reactiveUtils.js";

reactiveUtils.watch(
  () => timeSlider.timeExtent,
  (timeExtent) => {
    console.log("Time changed:", timeExtent.start, timeExtent.end);
  },
);

コアウィジェットのアプローチ

ビューへのウィジェットの追加
import Legend from "@arcgis/core/widgets/Legend.js";

const legend = new Legend({ view: view });

// Add to view UI
view.ui.add(legend, "bottom-left");

// Add multiple widgets
view.ui.add([
  { component: legend, position: "bottom-left" },
  { component: search, position: "top-right" },
]);

// Add at specific index (order in position)
view.ui.add(legend, { position: "bottom-left", index: 0 });

// Remove widget
view.ui.remove(legend);
カスタムコンテナ内のウィジェット
<div id="legendDiv"></div>

<script type="module">
  import Legend from "@arcgis/core/widgets/Legend.js";

  const legend = new Legend({
    view: view,
    container: "legendDiv",
  });
</script>

Calcite Design System の統合

Calcite を使った基本的なレイアウト
<!DOCTYPE html>
<html>
  <head>
    <link
      rel="stylesheet"
      href="https://js.arcgis.com/5.0/@arcgis/core/assets/esri/themes/light/main.css"
    />
    <script src="https://js.arcgis.com/5.0/"></script>
    <script
      type="module"
      src="https://js.arcgis.com/map-components/5.0/arcgis-map-components.esm.js"
    ></script>
    <style>
      html,
      body {
        height: 100%;
        margin: 0;
      }
    </style>
  </head>
  <body class="calcite-mode-light">
    <calcite-shell>
      
      <calcite-navigation slot="header">
        <calcite-navigation-logo
          slot="logo"
          heading="My Map App"
        ></calcite-navigation-logo>
      </calcite-navigation>

      
      <calcite-shell-panel slot="panel-start">
        <calcite-panel heading="Layers">
          <arcgis-layer-list reference-element="map"></arcgis-layer-list>
        </calcite-panel>
      </calcite-shell-panel>

      
      <arcgis-map id="map" basemap="streets-vector">
        <arcgis-zoom slot="top-left"></arcgis-zoom>
      </arcgis-map>

      
      <calcite-shell-panel slot="panel-end">
        <calcite-panel heading="Legend">
          <arcgis-legend reference-element="map"></arcgis-legend>
        </calcite-panel>
      </calcite-shell-panel>
    </calcite-shell>
  </body>
</html>
Calcite アクションバー
<calcite-shell>
  <calcite-shell-panel slot="panel-start">
    <calcite-action-bar slot="action-bar">
      <calcite-action
        icon="layers"
        text="Layers"
        data-panel="layers"
      ></calcite-action>
      <calcite-action
        icon="legend"
        text="Legend"
        data-panel="legend"
      ></calcite-action>
      <calcite-action
        icon="bookmark"
        text="Bookmarks"
        data-panel="bookmarks"
      ></calcite-action>
    </calcite-action-bar>

    <calcite-panel id="layers" heading="Layers">
      <arcgis-layer-list reference-element="map"></arcgis-layer-list>
    </calcite-panel>

    <calcite-panel id="legend" heading="Legend" hidden>
      <arcgis-legend reference-element="map"></arcgis-legend>
    </calcite-panel>
  </calcite-shell-panel>

  <arcgis-map id="map" basemap="topo-vector"></arcgis-map>
</calcite-shell>

<script>
  document.querySelectorAll("calcite-action").forEach((action) => {
    action.addEventListener("click", () => {
      const panelId = action.dataset.panel;
      document.querySelectorAll("calcite-panel").forEach((panel) => {
        panel.hidden = panel.id !== panelId;
      });
    });
  });
</script>
よく使われる Calcite コンポーネント
コンポーネント用途
calcite-shellアプリのレイアウトコンテナ
calcite-shell-panelサイドパネル
calcite-panelコンテンツパネル
calcite-navigationヘッダー/フッター
calcite-action-barアイコンボタンバー
calcite-actionアイコンボタン
calcite-button標準ボタン
calcite-inputテキスト入力
calcite-listリストコンテナ
calcite-list-itemリスト項目
calcite-cardカードコンテナ
calcite-modalモーダルダイアログ
calcite-alertアラートメッセージ
calcite-loader読み込みインジケーター
テーマ設定

<body class="calcite-mode-light">
  
  <body class="calcite-mode-dark">
    
    <style>
      :root {
        --calcite-color-brand: #007ac2;
        --calcite-color-brand-hover: #005a8e;
        --calcite-color-text-1: #323232;
      }
    </style>
  </body>
</body>

ウィジェットイベント

// Search select
search.on("select-result", (event) => {
  console.log(event.result);
});

// LayerList trigger action
layerList.on("trigger-action", (event) => {
  console.log(event.action, event.item);
});

// FeatureTable selection
featureTable.highlightIds.on("change", (event) => {
  console.log(event.added, event.removed);
});

参考サンプル

  • legend - レイヤーのシンボル表現に使う Legend ウィジェット
  • widgets-layerlist - レイヤー管理に使う LayerList ウィジェット
  • widgets-search-multiplesource - 複数のソースを持つ Search ウィジェット
  • widgets-featuretable - FeatureTable ウィジェットの統合
  • basemap-gallery - ベースマップの切り替えに使う BasemapGallery
  • widgets-timeslider - 時間データに使う TimeSlider ウィジェット

よくある落とし穴

  1. reference-element がない:<arcgis-map> タグの外に配置されたコンポーネントは、明示的な参照がないとビューを見つけられません。

    
    <arcgis-map id="myMap" basemap="topo-vector"></arcgis-map>
    <arcgis-search></arcgis-search>
    
    
    
    <arcgis-map id="myMap" basemap="topo-vector"></arcgis-map>
    <arcgis-search reference-element="myMap"></arcgis-search>
    

    影響: コンポーネントは関連付けられたビューを検出できません。レンダリングされないか、エラーが発生します。

  2. スロット名は厳密です:正確なスロット名(topleft ではなく top-left)を使用してください。

  3. Calcite の CSS が読み込まれない:Calcite コンポーネントを使用する前に、Calcite スクリプトが読み込まれていることを確認してください。

  4. ウィジェットコンテナの競合:同じウィジェットを DOM コンテナと view.ui の両方に追加しないでください。

    // Anti-pattern: widget in both container and view.ui
    const legend = new Legend({ view: view, container: "legendDiv" });
    view.ui.add(legend, "bottom-right"); // Conflicts
    
    // Correct: pick one placement strategy
    const legend = new Legend({ view: view });
    view.ui.add(legend, "bottom-right");
    

    影響: ウィジェットが二重にレンダリングされたり、レイアウトが崩れたりします。

  5. ダーク/ライトモードの不一致:body に calcite-mode-light または calcite-mode-dark クラスを追加してください。

  6. コア API ウィジェットの CSS がない:コア API ウィジェット(Map Components ではないもの)を使用する場合は、@arcgis/core/assets/esri/themes/light/main.css をインポートする必要があります。Map Components は CSS を自動的に処理します。

関連スキル

  • 特殊なウィジェット(BuildingExplorer、FloorFilter、Track、Locate など)については、arcgis-widgets-advanced を参照してください
  • 計測、印刷、ルート検索、スワイプツールについては、arcgis-map-tools を参照してください
  • Editor および Sketch ウィジェットについては、arcgis-editing を参照してください
  • FeatureTable と FeatureForm の詳細については、arcgis-tables-forms を参照してください

コメント