Calcite Design Systemを使用した最近発生した地震のフィルタリング

608
0
12-07-2022 09:43 PM
Labels (2)

Calcite Design Systemを使用した最近発生した地震のフィルタリング

はじめに

これまで Calcite Design System の使用方法として、Calcite Design System チュートリアル3回連載しました。本記事では第4回目として、チュートリアルの Filter recent earthquakes を紹介します。

第1回:地図アプリの作成

第2回:ダークモードスイッチの作成

第3回:コアコンセプトの適用

第4回:近発生した地震のフィルタリング ← 本記事

Calcite Design System を使用してユーザー インター フェイス (UI) を構築します。このチュートリアルでは、複雑な問題を解決するために複製や拡張が可能な Calcite Components の概要を説明します。

ここでは、以下のことを行います。

・フィーチャ サービスから属性にアクセスするためのクエリの実行方法

・クエリで見つかったレコードの数を動的に入力するための calcite-notice を追加

・クエリから個々のレコードを表示するために calcite-card を動的に追加

Map Viewer のレコードの位置にリンクする calcite-button の作成

このチュートリアルでは vanilla JavaScript を使用していますが、これらの概念と対話の方法はフレームワークに関係なく適用できます。地図を含むチュートリアルは「地図アプリを作成する」をご覧ください。

地震の検索結果

TakahiroKAMIYA_0-1670472904180.png

 

作成にあたって必要なもの

ArcGIS 開発者アカウント

このチュートリアルで使用するサービスにアクセスするには、無料の ArcGIS 開発者アカウントまたは ArcGIS Online 組織に関連付けられたアカウントが必要です。

ステップ

新しいペンの作成

1CodePen にアクセスし、アプリケーション用の新しいペンを作成します。

HTML の追加

1.CodePen > HTML で、HTMLを追加して <body> タグのあるページを作成します。また、<main> セクシ ョンを追加します。CodePenでは、<!DOCTYPE html> タグは必要ありません。別のエディターを使用している場合や、ローカル サーバーでページを実行している場合は、必ずこのタグを HTML ページの先頭に追加してください。

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Calcite Components: Filter recent earthquakes</title>
  </head>
  <style>
  </style>
  <body>
    <main>
    </main>
  </body>
  <script>
  </script>
</html>

2.Calcite Design System Web コンポーネントにアクセスするには、<head> 要素に Calcite Components への参照を追加します。

  <head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Calcite Components: Filter recent earthquakes</title>

  <script src="https://js.arcgis.com/calcite-components/1.0.7/calcite.esm.js" type="module"></script>
  <link rel="stylesheet" href="https://js.arcgis.com/calcite-components/1.0.7/calcite.css" />

  </head>​

3.次に、アプリケーションの中身を整理します。main セクションに、地震の結果を格納するために、headingheading-level の属性を持つ calcite-shell calcite-panel を追加します。

headingとheading-level 属性は、より多くのユーザーをサポートするために、アプリケーション全体のページ階層 (page hierarchy) を配置します。これはページの最初のヘッダーなので、heading-level 値を "1 " に設定します。

    <calcite-shell>
      <!-- Panel to display records -->
      <calcite-panel heading="Earthquake results" heading-level="1" description="Search by location to display results">

      </calcite-panel>
    </calcite-shell>

レコードの表示

ユーザーが調整できるように、HTMLコンテンツの構築を続けます。コンテンツは、ユーザーがアプリケーションの操作ることで変化します。

1.calcite-panel calcite-filter を追加します。この calcite-filter は地震のフィーチャ サービスへのクエリに使用される予定です。

        <!-- Filter records -->
        <calcite-filter placeholder="Try searching Alaska"></calcite-filter>

2.次に id 属性を持つ calcite-notice を追加し、ユーザーにオンデマンドでフィードバックを提供します。

        <!-- An active class will be added to display the number of records -->
        <calcite-notice id="note">

        </calcite-notice>​

3.calcite-notice では、divを追加して title スロットに配置し、後で id 属性を使って地震発生件数を入力するのに使用します。

        <!-- An active class will be added to display the number of records -->
        <calcite-notice id="note">

          <div id="number-records" slot="title">
            <!-- Content is automatically generated -->
          </div>

        </calcite-notice>​

4.地震の結果を格納するために、class 属性を持つ div を追加します。また、パネルの footer スロットに calcite-pagination を配置し、page-size 属性を追加して1ページに表示する件数を指定します。

        <!-- Container with Cards -->
        <div class="card-container">
          <!-- Content is automatically generated -->
        </div>
        <!-- Pagination -->
        <calcite-pagination slot="footer" page-size="12" style="visibility:hidden" > 
        </calcite-pagination>​

データのクエリ

ユーザーが入力した検索キーワードで地震のフィーチャ サービスを取得する JavaScript 機能を追加します。

1.まず、後で要素を参照するために calcite-filtercalcite-paginationcalcite-noticecard-container CSS クラスを参照する定数と変数を作成します。

  const filterElement = document.querySelector("calcite-filter");
  const paginationElement = document.querySelector("calcite-pagination");
  const noticeElement = document.querySelector("calcite-notice");
  const cardContainer = document.querySelector(".card-container");​

2.次に、Fetch API を使用して earthquakes サービスに問い合わせます。成功したら、Response.json() でレスポンスを解析し、map() メソッドでフィーチャを取得します。

  /* Fetch the earthquakes feature service */
  fetch("https://services9.arcgis.com/RHVPKKiFTONKtxq3/ArcGIS/rest/services/USGS_Seismic_Data_v1/FeatureServer/0/query?where=1%3D1&outFields=*&f=json")
  .then((response) => response.json())
  .then(({features}) => features.map(({attributes}) => attributes))

結果のフィルタリング

次に、解析されたレスポンスを使用して、ユーザー定義の結果をフィルタリングして表示します。

1.initFilter という named function expression を使用して、結果をフィルタリングします。上記のステップで定義した定数と変数を使用して calcite-filter コンポーネントの items プロパティを設定します。

  /* Fetch the earthquakes feature service */
  fetch("https://services9.arcgis.com/RHVPKKiFTONKtxq3/ArcGIS/rest/services/USGS_Seismic_Data_v1/FeatureServer/0/query?where=1%3D1&outFields=*&f=json")
  .then((response) => response.json())
  .then(({features}) => features.map(({attributes}) => attributes))

  .then((attributes) => initFilter(attributes));

  /* Filter the results to display */
  const initFilter = (items) => {
    filterElement.items = items;

  };

2.initFilterで、calciteFilterChange イベントのリスナーを追加して、フィルタの value の変化を監視します。次にpaginationstartItemtotalItems のプロパティを変更して、最初のページに戻ります。最後に、フィルタの valuefalsey でないときにカードを追加する条件を作成します。

フィルタの [`filteredItems`](xref://site.self/filter/#component-api-properties-filteredItems) プロパティには、[`value`](xref://site.self/filter/#component-api-properties-value)がない場合にすべての項目が格納されます。検索機能を作るには、ユーザーがクエリ用語を入力したときだけ、カードを追加する必要があります。

  /* Filter the results to display */
  const initFilter = (items) => {
    filterElement.items = items;

    document.addEventListener("calciteFilterChange", () => {
      paginationElement.startItem = 1;
      paginationElement.totalItems = 0;

      // When a Filter value is present
      // Create Cards, update Pagination, and number of responses
      if (filterElement.value) {

      }
    });

  };

3.次にcalciteFilterChange 内で、フィルタリングされた地震の totalItems が指定した pageSize 値よりも大きい場合に calcite-pagination コンポーネントを表示します。

calcite-pagination コンポーネントの CSS プロパティの visibility  "hidden" に設定します。結果が ページ以上ある場合は、CSS プロパティの値を ”visible” に変更します。

  /* Filter the results to display */
  const initFilter = (items) => {
    filterElement.items = items;

    document.addEventListener("calciteFilterChange", () => {
      paginationElement.startItem = 1;
      paginationElement.totalItems = 0;

      paginationElement.style.visibility = "hidden";

      // When a Filter value is present
      // Create Cards, update Pagination, and number of responses
      if (filterElement.value) {

        // If additional pages are populated, display Pagination
        if (paginationElement.total > paginationElement.pageSize) {
          paginationElement.style.visibility = "visible";
        }

      }
    });

  };​

地震を表示

地震を表示するために、各結果の属性を calcite-card に格納します。また、calcite-button を追加し、アクセスすると、地震の位置が Map Viewer で表示されるようにします。

1.フィルタリングされた地震を、card-container クラスに属する calcite-card コンポーネントに、createCard という名前の関数式で配置します。

  /* Create Cards and their content */
  const createCard = (item) => {
    const titleName = item.place.replace(/[;']/g,"");
    // Populate Card content
    if (cardContainer.childElementCount < paginationElement.pageSize) {
      const cardString =
      `<calcite-card id="card-${item.OBJECTID}">
        <span slot="title">
          <b>${item.place}</b>
        </span>
        <span slot="subtitle">
          Occurred on: ${new Date(item.eventTime)}
        </span>
        <calcite-chip
          appearance="outline-fill"
          scale="s"
          kind="inverse"
          icon="graph-time-series"
        >
          Magnitude: ${item.mag}
        </calcite-chip>
        <calcite-button
          label="Open ${titleName} in map"
          icon-end="launch"
          slot="footer-end"
          target="_blank"
          width="full"
          href="https://www.arcgis.com/apps/mapviewer/index.html?` +
            `marker=${item.longitude};${item.latitude};` + // Marker (lng, lat)
            `4326;` + // Coordinate system
            titleName + `;` +
            `https://clipart.world/wp-content/uploads/2021/07/Target-clipart-transparent.png;` + // Marker image
            `Magnitude: ${item.mag}&` +
            `level=6"
        >
          Open in map
        </calcite-button>
        </calcite-card>`;
      const cardElement = document
      .createRange()
      .createContextualFragment(cardString);
      cardContainer.appendChild(cardElement);
    }
  };

2.カードを作成するには、フィルタ value に一致する各フィーチャの calciteFilterChange イベントリスナーで createCard を呼び出します。結果を含む cardContainer の内容をクリアします。

 /* Filter the results to display */
  const initFilter = (items) => {
    filterElement.items = items;

    document.addEventListener("calciteFilterChange", () => {
      paginationElement.startItem = 1;
      paginationElement.totalItems = 0;

      paginationElement.style.visibility = "hidden";

      cardContainer.innerHTML = "";

      // When a Filter value is present
      // Create Cards, update Pagination, and number of responses
      if (filterElement.value) {

        filterElement.filteredItems.forEach((item) => createCard(item));
        paginationElement.totalItems = filterElement.filteredItems.length;

        // If additional pages are populated, display Pagination
        if (paginationElement.totalItems > paginationElement.pageSize) {
          paginationElement.style.visibility = "visible";
        }

      }
    });

  };

3.次に、ユーザーに対して地震の結果件数を表示します。関数 showNumberOfResponses を作成し、calcite-notice のタイトルにレスポンス件数を転記します。ユーザーがコンテンツにアクセスできるように、Notice open 属性を "true" に設定します。レスポンス数に応じて innerHTMLkindicon 属性が変更されます。

  /* Display the number of responses in a Notice */
  function showNumberOfResponses(responseNumber) {
    const note = document.getElementById("note");
    const numberRecordsNote = document.getElementById("number-records");
    // If 0 responses, add "Sorry" to the Notice text
    // Add the Notice color and icon
    if (responseNumber === 0) {
      responseNumber = `Sorry, ${responseNumber}`
      note.kind = "danger";
      note.icon = "exclamation-mark-triangle";
    } else {
      note.kind = "brand";
      note.icon = "information";
    }
    // Notice text
    numberRecordsNote.innerHTML = `${responseNumber} records found.`;
    noticeElement.open = true;
  }

4.カードの作成と同様に、calciteFilterChange イベントリスナーのコールバック関数にshowNumberOfResponses 関数の呼び出しを追加します。フィルタリングされた値が存在しない場合、通知の open 属性を「false」に、calcite-paginationvisibility を「hidden」に設定します。

  /* Filter the results to display */
  const initFilter = (items) => {
    filterElement.items = items;

    document.addEventListener("calciteFilterChange", () => {
      paginationElement.startItem = 1;
      paginationElement.totalItems = 0;

      // Prevent display of elements if no Filter value is present
      noticeElement.open = false;

      paginationElement.style.visibility = "hidden";

      cardContainer.innerHTML = "";

      // When a Filter value is present
      // Create Cards, update Pagination, and number of responses
      if (filterElement.value) {

        filterElement.filteredItems.forEach((item) => createCard(item));
        paginationElement.totalItems = filterElement.filteredItems.length;

        showNumberOfResponses(filterElement.filteredItems.length);

        // If additional pages are populated, display Pagination
        if (paginationElement.totalItems > paginationElement.pageSize) {
          paginationElement.style.visibility = "visible";
        }

      }
    });

  };

5.pagination の calcitePaginationChange イベントにリスナーを追加し、ユーザーがページを変更するときに後続のフィルタリング アイテムを表示できるようにします。filteredItems のサブセットを pagination startItemプロパティから始まり、startItem プロパティと pageSize プロパティの合計で終わるように表示します。

  /* Update Cards when interacting with Pagination */
  document.addEventListener("calcitePaginationChange", ({ target }) => {

    const displayItems = filterElement.filteredItems.slice(
      target.startItem - 1,
      target.startItem - 1 + target.pageSize
    );

  });

6.最後に、calcite-pagination を操作する際に、カードを更新します。cardContainer の内容を以前のフィルタリング結果でクリアし、calcitePaginationChange イベントリスナーで createCard を呼び出します。

  /* Update Cards when interacting with Pagination */
  document.addEventListener("calcitePaginationChange", ({ target }) => {

    cardContainer.innerHTML = "";

    const displayItems = filterElement.filteredItems.slice(
      target.startItem - 1,
      target.startItem - 1 + target.pageSize
    );

    displayItems.forEach((item) => createCard(item));

  });

スタイリングの追加

これでアプリケーションの機能は完成です。CSS のスタイリングを使って、インターフェイスのデザインを最終調整します。

1.card-container クラスに、CSS grid layoutcalcite-chip の震度表示色、calcite-notice の位置指定を用いたスタイルを追加します。

  <style>

    .card-container {
      margin: 0.75rem;
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
      grid-gap: 1rem;
      justify-content: space-evenly;
    }
    calcite-chip {
      color: var(--calcite-ui-danger);
    }
    calcite-notice {
      position: relative;
      margin: 0.75rem;
    }

  </style>​

アプリを実行する

CodePenで、コードを実行すると、アプリケーションが表示されます。

まとめ

今回は、Calcite Design System を使用したチュートリアルの Filter recent earthquakes のサンプルを翻訳して紹介しました。ArcGIS 開発リソース集にも Calcite Design System の開発に役立つガイド集を公開していますので、ご活用ください。

関連リンク

Calcite Design System チュートリアル集

Tutorials | Calcite Design System | ArcGIS Developers

ArcGIS Developers

ArcGIS Developers

ArcGIS 開発リソース集

ArcGIS Developers 開発リソース集 (esrijapan.github.io)

Labels (2)
Version history
Last update:
‎03-03-2023 01:26 AM
Updated by: