カスタマイズビューで amCharts 5 を使って日本地図を表示してみよう!

目次

はじめに

今回は、amCharts 5 という描画ライブラリでカスタマイズビューに日本地図を表示し、「オンラインワークショップにどの地域から何人参加しているか」を可視化します。

amCharts とは

ホームページ: https://www.amcharts.com (External link)
amCharts は表や地図を描画する JavaScript ライブラリです。
amCharts は商用ライセンスですが、ロゴが表示される無料版も使用可能です。
詳細は 公式サイト (External link) を確認してください。

ワークショップアンケートアプリの作成

以下の画像とフィールドの設定情報を参考に kintone でアプリを作成します。

フィールドの種類 フィールドコード 備考
文字列(1行) 氏名 JavaScript内では使用しません。
ドロップダウン 都道府県 都道府県名(例:東京都、大阪府、埼玉県、北海道、愛知県 etc.)
ドロップダウン ワークショップ名 ワークショップ名(例:ワークショップA、ワークショップB、ワークショップC etc.)
JavaScript内では使用しません。

カスタマイズビューの作成

以下の画像を参考にカスタマイズビューを設定します。

  1. 一覧名を入力します。
    ここでは"mapView"とします。
  2. 表示形式は「カスタマイズ」を選択します。
  3. 一覧 ID をコピーしておきます。
  4. 「ページネーションを表示する」のチェックは外しておきます。
  5. HTML には、<div id="chartdiv"></div> のみ記載します。

JavaScriptとCSS

JavaScript

以下をコピーして JavaScript ファイルとして保存します(ファイル名は sample.js とします)。
コード内の{一覧 ID}には、カスタマイズビューを作成時に記録した一覧 ID を設定します。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * display japan map on custom view using amCharts5  sample program
 * Copyright (c) 2022 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */
/* global KintoneRestAPIClient */
/* global am5, am5themes_Animated, am5map, am5geodata_japanHigh */
(() => {
  'use strict';

  kintone.events.on('app.record.index.show', async (event) => {
    if (event.viewId !== {一覧ID}) { // 作成したカスタマイズビューのIDを指定
      return event;
    }

    // kintone REST API Client で絞り込んだレコードを全件取得する
    const client = new KintoneRestAPIClient();
    const query = kintone.app.getQueryCondition();
    const records = await client.record.getAllRecords({app: kintone.app.getId(), condition: query, fields: ['都道府県']});

    // 都道府県ごとに参加人数(レコード数)を計算する
    const prefCounts = records.reduce((prev, record) => {
      const pref = record['都道府県'].value;
      prev[pref] ? prev[pref]++ : prev[pref] = 1;
      return prev;
    }, {});

    // 地図上にプロットするデータ
    const geoJSONData = {
      type: 'FeatureCollection',
      features: []
    };
    // 都道府県の中心マスタから使用する都道府県の分のGeoDataを作る
    Object.keys(prefGeoDataMaster).forEach(p=>{
      if (prefCounts[p]) {
        geoJSONData.features.push(makePrefGeoData(p, prefCounts[p]));
      }
    });

    // Create root
    const root = am5.Root.new('chartdiv');

    // Set themes
    root.setThemes([
      am5themes_Animated.new(root)
    ]);

    // Create chart
    const chart = root.container.children.push(
      am5map.MapChart.new(root, {
        panX: 'rotateX',
        panY: 'none',
        projection: am5map.geoEquirectangular()
      })
    );

    // Create polygon series
    chart.series.push(
      am5map.MapPolygonSeries.new(root, {
        geoJSON: am5geodata_japanHigh,
        exclude: ['AQ']
      })
    );

    // Create point series
    const pointSeries = chart.series.push(
      am5map.MapPointSeries.new(root, {
        geoJSON: geoJSONData // 都道府県
      })
    );
    pointSeries.bullets.push(() => {
      return am5.Bullet.new(root, {
        sprite: am5.Circle.new(root, {
          radius: 5, // マーカーのサイズ
          fill: am5.color(0xffbf00), // tooltipの色
          tooltipText: '{name}:{participants}人', // 都道府県:〇〇人を表示する
        })
      });
    });
    return event;
  });

  // 指定した都道府県の地図上ポイントのデータを作る
  const makePrefGeoData = (prefName, prefCount) =>{
    return {
      type: 'Feature',
      properties: {
        name: prefName,
        participants: prefCount
      },
      geometry: {
        type: 'Point',
        coordinates: prefGeoDataMaster[prefName]
      }
    };
  };

  // 都道府県の中心の緯度経度データマスタ
  const prefGeoDataMaster = {
    北海道: [142.781281, 43.420962],
    青森県: [140.726924, 40.699056],
    岩手県: [141.399429, 39.511756],
    宮城県: [140.941651, 38.381565],
    秋田県: [140.392163, 39.678886],
    山形県: [140.108578, 38.497668],
    福島県: [140.231252, 37.418743],
    茨城県: [140.385361, 36.304975],
    栃木県: [139.817955, 36.683168],
    群馬県: [138.923514, 36.481484],
    埼玉県: [139.368331, 36.003615],
    千葉県: [140.222304, 35.473969],
    東京都: [139.539242, 35.686991],
    神奈川県: [139.349213, 35.40362],
    新潟県: [138.888731, 37.368708],
    富山県: [137.287216, 36.607484],
    石川県: [136.778841, 36.772391],
    福井県: [136.184399, 35.81261],
    山梨県: [138.628685, 35.609615],
    長野県: [138.024588, 36.149935],
    岐阜県: [137.057877, 35.778724],
    静岡県: [138.312185, 35.033282],
    愛知県: [137.208724, 35.002511],
    三重県: [136.432514, 34.484291],
    滋賀県: [136.139617, 35.22592],
    京都府: [135.517902, 35.220152],
    大阪府: [135.545261, 34.598366],
    兵庫県: [134.794436, 35.068625],
    奈良県: [135.896845, 34.292803],
    和歌山県: [135.416815, 33.848677],
    鳥取県: [133.850276, 35.391534],
    島根県: [132.423277, 34.975087],
    岡山県: [133.83399, 34.861972],
    広島県: [132.792091, 34.588492],
    山口県: [131.430559, 34.226281],
    徳島県: [134.273465, 33.915461],
    香川県: [133.979044, 34.21968],
    愛媛県: [132.838719, 33.661193],
    高知県: [133.364174, 33.507085],
    福岡県: [130.682867, 33.599679],
    佐賀県: [130.118294, 33.279436],
    長崎県: [129.715641, 32.955619],
    熊本県: [130.807836, 32.58723],
    大分県: [131.411655, 33.203809],
    宮崎県: [131.353483, 32.200128],
    鹿児島県: [130.410976, 31.355836],
    沖縄県: [127.922927, 26.477084]
  };
})();

CSS

以下をコピーして CSS ファイルとして保存します(ファイル名は sample.css とします)。

1
2
3
4
5
#chartdiv {
  width: 90%;
  height: 600px;
  margin: 30px;
}

JavaScript / CSSでカスタマイズ

kintone REST API Client、amCharts 5 のライブラリおよび JavaScript プログラムおよび CSS スタイルシートを設定します。

  • PC 用の JavaScript ファイル
    • https://js.cybozu.com/kintone-rest-api-client/3.2.3/KintoneRestAPIClient.min.js
    • https://cdn.amcharts.com/lib/5/index.js
    • https://cdn.amcharts.com/lib/5/map.js
    • https://cdn.amcharts.com/lib/5/themes/Animated.js
    • https://cdn.amcharts.com/lib/5/geodata/japanHigh.js
    • sample.js(前述のコードをアップロード)
  • PC 用の CSS ファイル
    • sample.css(前述のコードをアップロード)

コードの解説

kintone REST API Client の getAllRecords() メソッドで絞り込み条件に合ったレコードを全件取得します。

11
12
13
14
    // kintone REST API Client で絞り込んだレコードを全件取得する
    const client = new KintoneRestAPIClient();
    const query = kintone.app.getQueryCondition();
    const records = await client.record.getAllRecords({app: kintone.app.getId(), condition: query, fields: ['都道府県']});

取得した records の都道府県フィールドごとの参加人数を計算します。
合計値などを計算する時によく使われる reduce() メソッドを使って集計しています。

16
17
18
19
20
21
    // 都道府県ごとに参加人数(レコード数)を計算する
    const prefCounts = records.reduce((prev, record) => {
      const pref = record['都道府県'].value;
      prev[pref] ? prev[pref]++ : prev[pref] = 1;
      return prev;
    }, {});

この処理で都道府県ごとの参加人数(prefCounts)は以下のように計算されます。

1
2
3
4
5
6
7
8
prefCounts = {
  北海道: 2,
  愛知県: 4,
  大阪府: 3,
  福岡県: 2,
  沖縄県: 1,
  東京都: 1
};

地図上にプロットするデータ(geoJSONData)を作ります。

23
24
25
26
27
28
29
30
31
32
33
    // 地図上にプロットするデータ
    const geoJSONData = {
      type: 'FeatureCollection',
      features: []
    };
    // 都道府県の中心マスタから使用する都道府県の分のGeoDataを作る
    Object.keys(prefGeoDataMaster).forEach(p=>{
      if (prefCounts[p]) {
        geoJSONData.features.push(makePrefGeoData(p, prefCounts[p]));
      }
    });

この処理で geoJSONData は以下のようになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
geoJSONData = {
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      properties: {
        name: '北海道',
        participants: '2'
      },
      geometry: {
        type: 'Point',
        coordinates: [142.781281, 43.420962]
      }
    },
    {
      type: 'Feature',
      properties: {
        name: '東京都',
        participants: ''
      },
      geometry: {
        type: 'Point',
        coordinates: [139.539242, 35.686991]
      }
    },
    {
      type: 'Feature',
      properties: {
        name: '愛知県',
        participants: '4'
      },
      geometry: {
        type: 'Point',
        coordinates: [137.208724, 35.002511]
      }
    },
    {
      type: 'Feature',
      properties: {
        name: '大阪府',
        participants: '3'
      },
      geometry: {
        type: 'Point',
        coordinates: [135.545261, 34.598366]
      }
    },
    {
      type: 'Feature',
      properties: {
        name: '福岡県',
        participants: '2'
      },
      geometry: {
        type: 'Point',
        coordinates: [130.682867, 33.599679]
      }
    },
    {
      type: 'Feature',
      properties: {
        name: '沖縄県',
        participants: '1'
      },
      geometry: {
        type: 'Point',
        coordinates: [127.922927, 26.477084]
      }
    }
  ]
};

地図の geoJSON プロパティに geoJSONData を入れて、マーカーのサイズや色、ツールチップの設定をします。

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    // Create point series
    const pointSeries = chart.series.push(
      am5map.MapPointSeries.new(root, {
        geoJSON: geoJSONData // 都道府県
      })
    );
    pointSeries.bullets.push(() => {
      return am5.Bullet.new(root, {
        sprite: am5.Circle.new(root, {
          radius: 5, // マーカーのサイズ
          fill: am5.color(0xffbf00), // tooltipの色
          tooltipText: '{name}:{participants}人', // 都道府県:〇〇人を表示する
        })
      });
    });

ツールチップの {name}{participants} は、geoJSONData の properties 内のプロパティです。

71
          tooltipText: '{name}:{participants}人', // 都道府県:〇〇人を表示する

動作の確認

以下の画像を参考にサンプルデータを追加してください。

カスタマイズビュー名「mapView」を選択します。
以下のように日本地図が表示されれば成功です。
マーカーにカーソルを合わせると都道府県名および参加者数が表示されます。
ワークショップ名で絞り込むこともできます。

おわりに

今回は、amCharts 5 というグラフ描画ライブラリを使い、都道府県の緯度経度情報とレコードの情報を関連付け、日本地図上に参加者数情報を表示しました。
このように、カスタマイズビューとグラフ描画ライブラリを組み合わせて、kintone アプリのレコードをいろいろな形で表現できます。
たとえば、予算配分を可視化できるカスタマイズを紹介する記事、「 amChartsのTreemapを使って、予算配分を可視化してみよう!」もありますので、興味がある方ぜひ確認してください。

information

この Tips は、2023 年 1 月版 kintone で動作を確認しています。