はじめに
こんにちは。株式会社Kaienでエンジニアをしている伊村です。
GoogleマップのAPIを使って、kintoneに登録された支援機関(クリニックや病院など)を地図で表示できるようにしました。この記事ではその実装方法を紹介します。
何を作ったか(概要)
クリニックや病院などの情報を管理している「支援機関マスタ」というkintoneアプリに、「支援機関マップ」機能を実装しました。
レコード詳細画面のボタンを押すと、その支援機関を中心に半径数kmの地図がダイアログで開き、周辺の支援機関がカテゴリ(種類)に応じて色分けされたピンで表示されます。地名や施設名で検索すれば、任意の地点を中心に表示し直すこともできます。
使ったGoogle APIとその役割
| API | 用途 |
|---|---|
| Maps JavaScript API | 地図本体の表示、カスタムピン(Advanced Marker)の描画 |
| Geocoding API | 「住所文字列」→「緯度・経度」への変換 |
| Places API(Find Place from Text) | 「地名・施設名などのフリーワード」→「緯度・経度」への変換(検索機能用) |
実装のポイント
1. 地図を表示する
まず、地図そのものをブラウザ上に表示するために、Google Maps JavaScript APIを読み込みます。この読み込みは、マップダイアログを開くたびに実行されます。同じ画面内で何度もダイアログを開き直すこともあるため、その都度スクリプトを読み込み直すのではなく、一度読み込んだあとは再利用するようにしました。
let googleMapsLoadingPromise: Promise<void> | null = null;
export const loadGoogleMapsApi = (apiKey: string, libraries?: string): Promise<void> => {
if (typeof google !== 'undefined' && google.maps) {
return Promise.resolve();
}
if (googleMapsLoadingPromise) {
return googleMapsLoadingPromise;
}
googleMapsLoadingPromise = new Promise((resolve, reject) => {
const callbackName = '__kintoneGoogleMapsApiCallback__';
(window as any)[callbackName] = () => resolve();
const librariesParam = libraries ? `&libraries=${libraries}` : '';
const script = document.createElement('script');
script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}${librariesParam}&loading=async&callback=${callbackName}`;
script.async = true;
script.onerror = () => {
googleMapsLoadingPromise = null;
reject(new Error('Google Maps APIの読み込みに失敗しました。'));
};
document.head.appendChild(script);
});
return googleMapsLoadingPromise;
};
これを呼び出すと、そのあとはgoogle.maps.Mapを使って地図をページ内に描画できるようになります。
loadGoogleMapsApiにはAPIキーをそのまま渡していますが、Google Maps JavaScript APIはブラウザから読み込む性質上、キーは誰でも見えてしまいます。そのため、Google Cloud Console側で利用ドメインとAPIの種類を制限し、キーが見えても悪用されにくいようにしてください。
2. 住所を緯度・経度に変換して保存しておく
地図にピンを立てるには、支援機関ごとの緯度・経度が必要です。そこで、レコードを保存するタイミングで「住所」フィールドの値をGoogleのGeocoding APIに渡し、変換した緯度・経度を専用のフィールドへ自動で保存するようにしました。
kintone.events.on(['app.record.create.submit', 'app.record.edit.submit'], async (event) => {
await applyGeocodingToRecord(
event.record,
event.type === 'app.record.edit.submit' ? addressBeforeEdit : null,
);
return event;
});
3. 地図上に支援機関をピンで表示する
保存しておいた緯度・経度をもとに、地図上にピンを表示します。それぞれの支援機関についてカテゴリ(種類)ごとに色分けし、ひと目で見分けられるようにしました。
const pin = new google.maps.marker.PinElement({
background: color,
borderColor: '#ffffff',
glyphColor: '#ffffff',
});
const marker = new google.maps.marker.AdvancedMarkerElement({
position: { lat: point.lat, lng: point.lng },
map,
title: point.label,
content: pin.element,
});
また、「特定の支援機関の近隣」だけでなく、「東京駅の近くにはどんな支援機関があるか」のように、任意の地点を起点に確認したいというニーズもありました。そこでマップダイアログの上部に、地名・施設名で検索した地点を中心にマップを表示し直せる検索フォームを用意しました。ここでは住所ではなく曖昧な文字列(施設名など)を扱いたいので、GeocodingではなくPlaces APIを使って検索しています。
まとめ
kintoneでも、JavaScriptカスタマイズを使えばGoogleマップのAPIと組み合わせて、こうした地図機能を作ることができます。同じような機能を検討している方の参考になれば幸いです。
