BODIK APIを使ったJavascriptプログラムを書いてみます。

課題3:BODIK APIの検索結果を表で表示する

問題:BODIK APIを使って、AEDを検索し、結果を表で表示する。

基本情報

  • Javascriptでスプレッドシートを表示する場合、「AG-Grid」というライブラリを使うと便利です。
  • JavascriptでAG-Gridを使うためには、ライブラリをインポートする必要があります。
  • AG-Gridの詳細は公式HPをご参照ください。
    AG-Grid: https://www.ag-grid.com/

Javascriptで記述

最初に、Javascriptで「BODIK API」を呼び出してみましょう。今回はfeatureのproperties部分だけを抜き出して、配列に格納します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>BODIK API</title>
    <script type="text/javascript">
      let api_server = 'https://wapi.bodik.jp';
      let api = 'aed';
      let lat = 33.59334325082392;
      let lon = 130.35598920962553;
      let api_url = `${api_server}/${api}`;
      fetch(api_url)
      .then(response => response.json())
      .then(data => {
        let array = [];
        for (let feature of data['resultsets']['features']) {
          let properties = feature['properties'];
          array.push(properties);
        }
        let output = document.getElementById('output');
        output.innerHTML = JSON.stringify(array, null, 2);
      });
    </script>
  </head>
  <body>
    <h2>BODIK API program #3</h2>
    <pre id="output"></pre>
  </body>
</html>

このpropertiesの配列をスプレッドシートに表示すればいいですね。

Javascriptでスプレッドシートを表示

Javascriptでスプレッドシートを表示する方法として、AG-Gridが便利です。
AG-Gridは無料で使えるOSSですが、正しく使うためにはライセンス表記が必要になります。(今回は省略します。)

AG-Gridを使うためには、AG-GridのライブラリとCSSを参照します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>BODIK API</title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/ag-grid/30.2.0/ag-grid-community.min.js'></script>
    <link href="https://unpkg.com/gridjs/dist/theme/mermaid.min.css" rel="stylesheet">
  </head>

  <body>
    <h2>BODIK API program #3</h2>
    <div id="gripdarea" style="width:800px;height:600px">
      <div id="grid" class="ag-theme-balham" style="width:100%;height:100%"></div>
    </div>
  </body>
</html>

AG-Gridのデータ構造

PCの世界でスプレッドシートというと「CSV」を表示するイメージですが、AG-GridはJSONを表示するツールです。
次のようなCSVのデータを表示するサンプルとします。

id,name,age
0001,佐藤,25
0002,鈴木,30
0003,田中,35

データ

スプレッドシートに表示する1行分のデータをJavascriptの辞書データで定義します。その辞書データの配列をスプレッドシートのデータとします。

// データ
let row_data = [
  { 'id': '0001', 'name': '佐藤', 'age': 25 },
  { 'id': '0002', 'name': '鈴木', 'age': 30 },
  { 'id': '0003', 'name': '田中', 'age': 35 }
]

ヘッダー

スプレッドシートの列項目部分のデータをヘッダーとして与えます。ヘッダーは次のような構造です。

// ヘッダー
let header_data = [ 
  { 'field': 'id',   'headerName': 'ID' },
  { 'field': 'name', 'headerName': '名前' },
  { 'field': 'age',  'headerName': '年齢' }
]

BODIK APIと組み合わせる

BODIK APIの検索結果をAG-Gridに表示する方法を考えてみましょう。

このページの最初の例で試したように、BODIK APIが返す検索結果から、featureのproperties部分は辞書になっていますから、これを取り出して配列に格納すれば、その配列はAG-Gridに与える「データ」となります。

あとはヘッダーを作れば良いですね。次のように先頭データ(辞書)から項目名を取り出しましょう。

let header_data = [];                      // AG-Gridのヘッダー情報
let feature0 = features[0];                // 最初のデータを取り出す
let properties0 = feature0['properties'];  // propertiesを取り出す
let headers = Object.keys(properties);     // 辞書から項目名の配列を作る
for (let fld of headers) {                 // 項目名の配列から順番に取り出す
    let col = {
        'headerName': fld,
        'fld': fld
    }
    header_data.push(col);
}

次のコードでも同じ処理ができます。

let header_data = [];                      // AG-Gridのヘッダー情報
let feature0 = features[0];                // 最初のデータを取り出す
let properties0 = feature0['properties'];  // propertiesを取り出す
for (let fld in properties0) {             // 辞書の項目を順番に取り出す
    let col = {
        'headerName': fld,
        'fld': fld
    }
    header_data.push(col);
}

では、BODIK APIの検索結果をAG-Gridに表示してみましょう。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>BODIK API</title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/ag-grid/30.2.0/ag-grid-community.min.js'></script>
    <link href="https://unpkg.com/gridjs/dist/theme/mermaid.min.css" rel="stylesheet">
    <script type="text/javascript">
      //  BODIK APIを呼び出す
      let api_server = 'https://wapi.bodik.jp';
      let api = 'aed';
      let api_url = `${api_server}/${api}?maxResults=100`;
      fetch(api_url)
      .then(response => response.json())
      .then(data => {
        let features = data['resultsets']['features']
        show_data(features);   // AG-Gridに表示する部分を関数として切り出す。
      });

      function show_data(features) {
        try {
          // 最初のデータから項目名を抜き出す
          let item0 = features[0]['properties'];
          let headers = Object.keys(item0);

          // 表の列名を作成する
          let header_data = [];
          for (let fld of headers) {
            let col = {
              'headerName': fld,
              'field': fld
            };
            header_data.push(col);
          }

          // 表のデータ配列を作成する
          let row_data = [];
          for (let feature of features) {
            row_data.push(feature['properties'])
          }

          // 表を表示する
          let grid_options = {
            'columnDefs': header_data,
            'rowData': row_data
          }
          let grid = document.getElementById('grid');
          new agGrid.Grid(grid, grid_options);

        } catch(error) {
          alert('show_data:' + error);
        }
      }
    </script>
  </head>
  <body>
    <h2>BODIK API program #3</h2>
    <div id="gripdarea" style="width:800px;height:600px">
      <div id="grid" class="ag-theme-balham" style="width:100%;height:100%"></div>
    </div>
  </body>
</html>

行の選択処理

行をクリックしたときに、その選択された行のデータを表示してみます。
行選択のイベントハンドラを追加します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>BODIK API</title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/ag-grid/30.2.0/ag-grid-community.min.js'></script>
    <link href="https://unpkg.com/gridjs/dist/theme/mermaid.min.css" rel="stylesheet">
    <script type="text/javascript">
      let grid_options = null;    // 関数間で共有するので、グローバル変数とする

      //  BODIK APIを呼び出す
      let api_server = 'https://wapi.bodik.jp';
      let api = 'aed';
      let api_url = `${api_server}/${api}?maxResults=100`;
      fetch(api_url)
      .then(response => response.json())
      .then(data => {
        let features = data['resultsets']['features']
        show_data(features);
      });

      function show_data(features) {
        try {
          // 最初のデータから項目名を抜き出す
          let item0 = features[0]['properties'];
          let headers = Object.keys(item0);

          // 表の列名を作成する
          let header_data = [];
          for (let fld of headers) {
            let col = {
              'headerName': fld,
              'field': fld
            };
            header_data.push(col);
          }

          // 表のデータ配列を作成する
          let row_data = [];
          for (let feature of features) {
            row_data.push(feature['properties'])
          }

          // 表を表示する
          grid_options = {
            'columnDefs': header_data,
            'rowData': row_data,
            'rowSelection': 'single',                   // 行選択を有効にする
            'onSelectionChanged': onSelectionChanged    // 行選択のイベントハンドラを指定
          }
          let grid = document.getElementById('grid');
          new agGrid.Grid(grid, grid_options);

        } catch(error) {
          alert('show_data:' + error);
        }
      }

      // 行選択のイベントハンドラ
      function onSelectionChanged() {
        try {
          const selectedRow = grid_options.api.getSelectedRows();
          let selected = selectedRow[0];
          alert(JSON.stringify(selected));
        } catch(error) {
          alert('onSelectionChanged:' + error);
        }
      }
    </script>
  </head>
  <body>
    <h2>BODIK API program #3</h2>
    <div id="gripdarea" style="width:800px;height:600px">
      <div id="grid" class="ag-theme-balham" style="width:100%;height:100%"></div>
    </div>
  </body>
</html>

お疲れ様でした。