Google Apps Scriptでマップ作成とKML生成【GAS】

現在、Google Spreadsheetへ住所やキーワード、ランドマーク名などを入力して、そのシートを元にマップを生成するツールを作って実際に使っていたりします。以前作っていた、GE Maniacsというサイトでは、Google Earthをネタにサイト運営をしてた関係で、こちらのサイトのツールなども利用させていただいてました。この住所やキーワードを元にマップを作る際にやっておくべき事がジオコーディングという作業で、住所等を「緯度経度」に変換しておく作業です。

実際にはマップにレンダリングする際には、緯度経度情報じゃなく住所でもそのまま投げて、サーバー側で緯度経度に変換してくれるので、問題はないのですが、都度変換されることになるので効率が悪く遅くなります。事前に緯度経度に変えておけば高速にマッピングが出来るわけです。ちなみに、メソッドにはリバースジオコーディング(緯度経度から住所を得る)のメソッドも合ったりします。

※ちなみに自分のツールは、スプレッドシート上でマップを表示させてみたり、Static Mapの画像を取得してみたりなどやってます。

今回使用するファイルとアプリケーション

※今回使用するスプレッドシートにジオコーディングキーワードに住所を入れてメニューよりジオコーディングを実施すると一括でスプレッドシートの住所一覧から緯度経度情報を返してくれます。C列~E列を消して実行するとわかります。

ジオコーディングソース

GAS側コード

  • ジオコーディングする際にUrlfetchAppでGoogle Maps APIに対して投げて取得する方法もあるのですが、UrlfetchAppは1回あたりの呼び出し時におよそ10秒ほど間を空けないとエラーになるので、懸命な手段とは言えません。
  • また、UrlfetchAppでジオコーディング結果を取得する方法は、APIキーが必要です。

HTML側コード

マッププレビューで用いてるコードです。別途Google Maps API Keyのセットアップが必要です。

  • APIキーは<HEAD>にある「https://maps.googleapis.com/maps/api/js」の参照にkey=YOUR_API_KEYという形でパラメータを追加してあげる必要があります。

Google Maps APIキーが必要となりました

有償化されました

2018年7月16日より、いよいよGoogle Maps APIを利用したサービス全てに於いて、APIキーがなければマップが表示されないように仕様変更が実施されました。それまでは、APIキーがなくともマップの表示が可能でした。APIキーは請求アカウントとキーが紐づけされていなければならず、利用自体が有償化されたことになります。

ただし、月額200ドルまでは無償枠が設けられているので、その範囲内であれば課金されないことになります。Map利用の課金枠は以下の通り。かなり複雑な料金体系になっていて、本気で使うには覚悟がいりますね・・・

項目名 月額無料枠(200ドル分) 1,000コールあたりの料金
月の利用量 0−100,000 100,000以上
Mobile Native Static Maps 無制限 $0.00 $0.00
Mobile Native Dynamic Maps 無制限 $0.00 $0.00
Embed 無制限 $0.00 $0.00
Embed Advanced 14,000 loadsまで $14.00 $11.20
Static Maps 100,000 loadsまで $2.00 $1.60
Dynamic Maps 28,000 loadsまで $7.00 $5.60
Static Street View 28,000 panosまで $7.00 $5.60
Dynamic Street View 14,000 panosまで $14.00 $11.20

※ただし上記の料金はMapのみで、ルートと場所の検索クエリに関する課金は別に存在します。詳しい料金表はこちらから。

図:APIキーなしだとこういう表示になってしまう

APIキーの取得

Google Maps APIを使う場合には、以下の手順でAPIキーを手に入れる必要があります。別途クレジットカードが必要です(といっても、上限設定をして課金されないようにセットアップもします)。

  1. Google Maps Platformにアクセスする
  2. 右上にある「使ってみる」をクリックする
  3. Enable Google Maps Platformというダイアログが出ます。今回は、とりあえず全部選択します。continueをクリック
  4. select or Create Projectでは、Google Cloud Consoleでのプロジェクト一覧が出てきます。新規作成をしてみました。nextをクリック。GASのプロジェクトに対しては適用出来ませんでした。
  5. 請求先アカウントを指定しろと言われるので、設定をします。請求先アカウントの作成をクリック。自分はすでにG Suiteユーザであるので、課金アカウントは予め作成済みでしたので、ここは飛ばします。(最初の1回は300ドル分/1年のむ)
  6. Google マッププラットフォームの有効化というダイアログが出て、とりあえず完了です。次へをクリック。
  7. しばらく待つ(結構時間掛かります)とAPIキーが出てくるので、これを控えておきます。大事なキーなので流出などしないように!!
  8. 取得したAPIキーを「https://maps.googleapis.com/maps/api/js?key=xxxxxx」といった形で追記して呼び出すようにする。
  9. You're all setと出たら完了となるので、DONEクリックして閉じる。

図:使用するマップのタイプ。通常はMapsのみでOK

図:プロジェクトの選択画面

図:APIキーは大切に保管しておきましょう。

APIキーに制限を付ける

続けて、認証情報を作成する必要があります。新しいAPIキーを保護する必要がありますと表示されているので、クリックします。これを行わないと、誰かれ問わずキーを使われてしまいます。

  1. キー制限にて「アプリケーションの制限」を選びます。
  2. HTTPリファラー」を選びます。
  3. どこからの呼び出しにだけ応じるか?URLを追加します。通常は埋め込むウェブサイトのURLを入力します。
  4. Google Apps Scriptのウェブアプリケーションやスプレッドシート上のダイアログから呼び出す場合には、一回Keyを入れた状態で呼び出し、F12のデベロッパーコンソールを開きます。
  5. Google Maps JavaScript API error: RefererNotAllowedMapErrorというエラーがあるはず。この中にあるYour site URL to be authorized以下のURLをHTTPリファラーに登録してあげると良い。
  6. 適用してから反映するまで5分ほど時間差があるので注意!
  7. 無事に表示できるか確認する。

図:HTTPリファラーで制限する

図:GASで使うにはひと手間が必要なHTTPリファラーの取得

図:無事に表示できるようになりました。

無料枠以上に利用しないよう制限をつける

Google Cloud Console上にて、まずは一旦ダッシュボードまで戻ります。テストをしてみるとわかりますが、リクエスト数がわかるようになっています。また、17個くらいのAPIがオンになっています。多分全部は要らないので、不要なものは無効化しておくと良いでしょう。しかしこのままでは、リクエストのあるAPIによって課金されかねないので、以下の手順で制限をつけます。

  1. Maps JavaScript APIがリクエストされてるので、その右側の歯車をクリック。
  2. 次の画面で左サイドバーの「割り当て」をクリック。
  3. Map loads per dayの項目が下にあります。無制限になってるので隣の鉛筆アイコンをクリック。
  4. 出てきたダイアログにて無制限のチェックを外してあげる。
  5. 無料の割当が25000くらいなので、20000くらいで値を入れる。確認にチェックを入れて、保存をクリック。
  6. アクセス数が大したことがなければ、これで十分無料枠で毎月利用が出来ます。

図:利用者の多いサイトではさじ加減が重要

プロジェクトを移動

今回の発表直前の2019年4月8日より、Google Apps ScriptからCloud Platform Projectへ直接アクセスが出来なくなりました。これまでにデプロイしてるものについては、これまで通り「リソース」⇒「Google Cloud Platform API ダッシュボード」からアクセスが可能です。

今回の変更はスプレッドシート上で動かすスクリプトやGoogleの拡張サービスを利用しないタイプのスクリプトであれば特に問題はありませんが、「Apps Script API」や「Google Picker API」、「Cloud SQL接続」などGCP上のAPIを利用する場合には以下の手順を踏んで、Google Apps Scriptにプロジェクトを連結する必要があります。これまでは、自動的にGCP上にGoogle Apps Script用のプロジェクトが生成されていたのですが、今後は自分の組織(もしくはGCPプロジェクト)上で作成されたプロジェクトでなければならないということです。詳細はこちらのページを見てください。

連結する手順は以下の通り

  1. Google Cloud Consoleを開く
  2. 左上にある▼をクリックする
  3. ダイアログが出てくるので、新規プロジェクトを作るか?既存のプロジェクトを選択する。この時、G Suiteであれば選択元は「自分のドメイン」を選択する必要があります。
  4. プロジェクト情報パネルから「プロジェクト番号」をコピーする
  5. 対象のGoogle Apps Scriptのスクリプトエディタを開く
  6. 「リソース」⇒「Cloud Platform プロジェクト」を開く
  7. 4.で入手した番号をプロジェクトを変更のテキストボックスに入れて、プロジェクトを設定ボタンをクリックする
  8. 無事に移動が完了すればメッセージが表示されます。
  9. この時、元の自動作成されたプロジェクトはシャットダウンされて消えます。これで設定完了です。

今回のこの変更だと1つ作ったプロジェクトに集約する必要があるので、クォータについてプロジェクト毎のカウントだったので問題なかったものが、集約されることで、クォータに引っ掛かる可能性があります。

図:プロジェクト番号をコピーしておきます

図:プロジェクトを他のプロジェクトに紐付けしました。

図:GCPの拡張サービスを使うには手順が必要になった

Fusion Tablesを使うという選択肢は・・・

自分は1回使っただけで、Google Apps Scriptで使うにはパフォーマンスが悪く、マッピングに関しても、正直自由度が低いということで使っていなかったFusion Tables。G Suitesの見捨てられていたサービスの1つで、データベースを担当!?するような存在でした。結局は殆どメンテされる事もなく、半ば放置されていたので消えるだろうなぁと思っていたら、2019年8月に消えることが確定しました。

SQLみたいな形でデータを取得できる点だけが評価できましたが、パフォーマンスがとっても悪く、スプレッドシートのほうが全然使いやすいので、想定していた通り終焉の日が来ました。ということで、マップ関係ではFusion Tablesを使うのは辞めましょう。せっかく、ライブラリもありましたが。。。そういえば、Google Baseなんてのもありましたね・・・

Mapsに関係なく、Fusion Tables使っちゃってる人は早めに他に移行しましょう。というか、制限が厳しいアプリだったので、まともに使っていた人がいるとは思えないのですが。。。

OpenStreet Mapで実装してみる

今回のスプレッドシートには、オマケとして別プロジェクトにてGoogle MapsではなくOpenStreet Mapのバージョンも含めています。ただ地図を表示するだけなので、マーカーなどの装備を追加していませんが、どうしても、Google Mapsの有償には手が出しにくいという人は、こちらで装備をするのも良いのではないかと思います。

こちらもスプレッドシートで連携して、起動時にポイントデータを流し込めますし、無償で使える地図です。Google Mapsからしたら見劣りはしますが、逆にシンプルで自分で作り込む地図としては良い下地になるかと思います。ソースコードは以下のような感じになります。APIはこちらのページから確認可能です。

ソースコード

表示してみた事例

ネットワークリンク配信してみる

ネットワークリンクとは、Google Earth上でビューを移動した時に、現在見ているエリア等に応じてサーバから情報をリアルタイム要求する為の、KMLの機能の一つ。表示されているエリアやその高さなどに応じてピンやオブジェクトを含んだデータを取得出来るので、非常によく利用されている機能の一つ。

ビューを移動すると東西南北のポイント(緯度経度)に関する情報をサーバに送ってくれるので、それを元にデータを返す仕組みを今回Google Apps Scriptで生成してやろうというのがミッションです。

KML側のコード

上記のKMLは移動後に1秒後にhrefに設定したURLに対して情報を要求します。URLの最後には必ず「?」を付けることを忘れずに。URLはGAS側のウェブアプリケーションURLを指定します。其のため、ネットワークリンク用にdoGet()が必要になります。

GAS側のコード

  • 緯度経度の範囲情報は、Google Earth側から受信したe.parameter.BBOXにて、カンマ区切りで取得可能です。
  • 受信した緯度経度範囲の情報をスプレッドシートのGPSデータに記述しています。
  • 緯度経度範囲内にあるプレイスマークだけをmapsheetからフィルタしてKMLを生成しています。
  • makeplacemark関数にてmapsheetからのデータよりKMLを生成しています。
  • 最後にContentServiceにてKMLを出力しています。mimetypeとしてContentService.MimeType.XMLをセットしています。
  • 更にカスタマイズすればラインデータやポリゴンデータなど、また、バルーンの中にデータを表示など可能です。

Navicon連携

Naviconとは、スマフォ用のアプリである「Navicon」の事で、Google Mapsなどのアプリから共有でNaviconに送り込む→Naviconからカーナビにデータを送り込む→カーナビに目的地がセットされるという非常に便利なアプリケーションで、Navicon対応カーナビであれば面倒なカーナビ上での操作をせずに、スマフォから目的地セットが出来てしまいます。

例:navicon用のURL

NaviconにはWeb APIが用意されており、スプレッドシート上の住所をNavicon APIに渡すとアプリを開くためのURL Schemeが返ってくるので、これを元にGoogle Apps Scriptでウェブアプリを構築すれば、自前のドライブ行き先リストを作れてしまいます。URL Schemeはnavicon://といったような特殊なURLになっており、タップするとNaviconが起動するようになります。スマフォでGoogle Apps Scriptで作ったウェブアプリにアクセスして、タップすればOKというわけです。

有償版プランだとタップでNavicon画面を出さずにダイレクトにカーナビに送り込めるようになりますが、結構高額なので企業ユースなどで訪問先顧客リストをGoogleスプレッドシートに作成しておき、カーナビで管理せずに顧客管理の一貫で運用可能になります。

図:URLクリックでNaviconが起動する

事前準備

Navicon APIそのものは無償で利用可能です。セキュアタイプが有償でカーナビにダイレクトに送り込める機能が利用できます。以下の手順でアカウントを作成し、2つのキーを取得します。今回は無償版で進めます。

  1. アカウントを作成しログインする
  2. こちらにアクセスし、オープンタイプの自動発行をクリック
  3. この時点でAPI Keyを取得出来ます。
  4. 次に右上のマイページをクリックして、用途管理をクリック
  5. 新規登録でNaviconを選択し、新規追加をクリック(MapQRコードも作れるみたい)
  6. 用途の必須項目だけ入力して、保存する
  7. すると、用途IDを取得出来ます。
  8. 今回使用するスプレッドシートのメニューより、作業用→設定項目を開く
  9. サイドバーの下のほうにある「API Keyの指定」と「用途IDの指定」でそれぞれ入力登録する
  10. 住所緯度経度変換を実行すると、住所がある場合にはNavicon APIリクエストされてnavicon URLが発行されてスプレッドシートに書き込まれます。

ソースコード

Navicon APIリクエスト

allgeocode関数のコードを修正します。以下のような形にします。

  • nvrequrlはNavicon APIのリクエストエンドポイントURLです。
  • navgenerate関数にて地点名と住所を取得したらAPIリクエストを実行し、naviconのURL Schemeを取得します。
  • 取得したらnavicon URLの列に一気に書き込みます。
  • 但し、UrlfetchAppは10秒間に4リクエスト以上送り込むと429エラーとなることが多いので、Utilities.sleepにて1リクエスト毎に3秒間ウェイトを入れています。
  • Navicon APIは1回につき、5地点送り込めるようです。
  • また、10000回/月の利用上限がついています。有償版は制限がありません。

Naviconリスト表示

Vue + Vuetifyにてスプレッドシートのデータを一覧表示するようにしました。スクリプトのプロジェクトにてNaviconリストを開き、ウェブアプリケーションとして公開すると使えるようになっています(別途このスプレッドシートのIDをコード内の変数:gasheetに記述が必要です)

GAS側コード

  • スマフォ表示用に.addMetaTagを使用してHTML Serviceにてウェブアプリケーションを生成しています
  • gettabledata関数にてスプレッドシートのデータをJSON形式にして返しています。
HTML側コード

  • 今回はスマフォ用インターフェースはVue.jsおよびVuetifyにて構築しています。
  • gettabledata関数にてデータを取得し、vm.recdataでdatatableに値を追加しています。
  • アクションのバルーンアイコンをクリックするとNaviconのURL Schemeが呼び出されて、Naviconが起動する仕掛けです。この場合、新窓で開くようにします。

サンプル:ウェブアプリケーション化してみた

使い方と結果

搭載してる機能

マッププレビュー機能では、以下の機能を搭載しています。

  • Google Drive内の指定のフォルダの画像類をプレイスマークのアイコンとして利用出来るようにしています。
  • トラフィックレイヤーを追加する
  • マップに検索窓を用意して、検索した場所にジャンプする機能
  • センターマーカーを装備
  • 特定の列の数式をマッピング時に自動的に補完する機能(vfatmerge関数)
  • Google Earthからのリクエストから緯度経度情報を取得しスプレッドシートに書き込む機能

セットアップ

また、セットアップが必要です。メニューより「作業用」⇒「セットアップ」を実行します。スプレッドシートのIDがスクリプトプロパティに格納され、プログラム側で利用されます。

またアイコンフォルダの指定では、Google Pickerを利用しているので、Google Cloud ConsoleよりAPIキーを取得してコードに追加する必要があります。追加しないとPicker APIが動きません。マーカーアイコンの追加でこれらの情報を利用しています。

マップ表示プレビュー

APIキーを設定していれば、マッププレビューが見られます。また、今回のスプレッドシートには更に別にmap表示専用というプロジェクトも入れてあります。このスプレッドシートのIDを入れてあげて、map.htmlの中にAPIキーを追記してあげれば、フルスクリーンでマップ表示が可能になっています。

別のプロジェクトなので、HTTPリファラーが別になりますので、制限を掛けている場合には追加で登録してあげましょう。

図:この状態でブログに埋め込むことも可能

ネットワークリンクを表示

GPS2KMLのネットワークリンクのKMLをGoogle Earthに読み込ませて、恵比寿駅に飛ぶと、Google Apps Scriptから出力されたKMLデータが返されて表示されます。現在見ている緯度経度の範囲内にあるプレイスマークのみを絞って表示するので、負荷を低減できるようになっています。

スプレッドシートのデータを利用しているので拡張すればより面白いデータをGoogleスプレッドシートに記述するだけで配信が可能になります。PHPといったサーバー不要でデータ配信が出来るので非常にオススメです。

※バージョンが古いとアイコンが表示されなくなったりするので、最新のGoogle Earthを使いましょう。

※2020/1/31のモバイル版Google Earthのアップデートによって、Android版でもネットワークリンクに対応し、本スクリプトでのプレイスマーク表示ができるようになりました。

図:ネットワークリンクで恵比寿周辺に行くと現れるようになった

図:スマフォ版でも表示できるようになりました

Visualization APIのMap Chartを使ってみる

Google Maps APIとは別に、Visualization APIにはMap Chartと呼ばれるチャート作成機能があります。作成手順がGoogle Maps APIとはずいぶん異なるのですが、表示されるマップはGoogle Maps v3そのものです。ただし、呼び出すJSが異なる為、Google Maps APIのメソッド類は使用する事はできません。

また、Visualization APIにおける Map Chartの呼び出し方が独特で、またリファレンスの記載場所が異なる(というより、Map Chartにあるコードでは動かない)ので、以下のように呼び出しをしなければなりません。要Google Maps API Keyです。

ソースコード

  • 新旧両方のVisualization APIの読み込みが必要なので、loader.jsとjsapiの2つを冒頭で読み込ませてます。
  • オプション設定を細かく設定する事で、マーカーアイコン等を指定する事が可能です。
  • 配列ではなく、DataTableの形式でVisualization APIにデータを渡す必要があります。

ポイント

  • geocoderに投げるとJSON形式で返ってきます。但し、複数返すことも可能なので(例えばキーワードなど)、そこは注意。住所ならば1個しか返ってこないはずなので、result[0]で指定し、rezult.geometry.location.latと指定すれば緯度が取得、lonとすれば経度が取得できます。
  • Googleのジオコーディングサービスは必ずしも住所を入れれば確実な緯度経度に変換されて返って来るわけではありません。日本の住所は非常に複雑なので、精度の低いアバウトな緯度経度で返ってきたり、エラーになって返ってこなかったりします。
  • 建物名などはジオコーディングのキーワードに入れてはなりません。エラーになります。
  • どうしてもエラーになる住所の場合には、その場所をピンポイントにヒットできるキーワードを考えます。ランドマーク名やGoogle検索ワードなどがそれです。一度googleでそれを検索しポイントを教えてくれるかどうかを調べてみると良いでしょう。
  • 【施設名:市までの住所】といった検索ワードも有効です。これはGoogle Maps上で検索したプレイスマークがこのような仕組みを利用しています。
  • 【カテゴリー名:施設名】なんて検索ワードも使えたりしますが、カテゴリー名はマップ上で調べておかないといけません。
  • マップの精度として小数点以下7桁です。それより桁数が小さいと精度が落ちてアバウトなマッピングになってしまいます。
  • マッピングで利用するのは緯度経度の情報なので、片方だけではマッピング出来ません。
  • mapsheetシートの説明文の列は、HTMLコードがそのまま使えます。セルの中にHTMLでコードを記述するとバルーンの中に表示がされます。
  • サイドバーメニューのマーカーアイコンセクションでアイコン登録用のダイアログ表示が出来ます。指定したフォルダ内の画像を自動的にリストアップし、画像をクリックするとURLボックスにURLが組み立てられて入る仕組みになっています。
  • Google Driveの画像に直リンクする為には、https://drive.google.com/uc?export=view&id=というURLに続けて画像ファイルのIDをつなげれば良いです。これで、参照することが出来ます。
  • ESCキーとマップ上でのクリックでバルーンが閉じるようにちょっとだけイベント追加して細工を加えています。
  • Google Maps API v3を使うためには、このURLのようにライブラリへの参照が必要です。
  • 情報ウィンドウのサイズは、#infodivにてCSSで制御することが可能です。
  • 個人的にはこれに追加のマップや、fckeditor入力画面とマップ上でプレイスマークの追加とスプレッドシートへの登録、リバースジオコーディングの実装などをやりたいと思っています。
  • マーカーアイコンは32×32のサイズでスケールするようにオプション指定しています。

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)