GoogleDriveSpreadSheet上の住所一覧を地図にプロット

## 事の発端 ##
区から成人歯科健康診査のお知らせが届きました。診療費を補助してもらえる大変ありがたい精度なのですが、診療機関一覧は名前、住所、電話番号しか載ってません。できれば家から近い診療所にかかりたいと思い、一つ一つ地図にプロットしていたのですがいかんせん面倒くさい。そこで、GoogleDriveのSpreadSheetとGoogle Apps Scriptでこんなアプリを作ってみました。

## アプリ作成 ##
### スプレッドシート ###
こんなスプレッドシートを書きます。ここでは新宿周辺のローソンの店舗を例にしてみました。
![スクリーンショット 2014-06-20 21.29.46.png](https://qiita-image-store.s3.amazonaws.com/0/29682/93f2a05e-5b5d-53a5-150e-f63f7794ad9d.png)

### スクリプト ###
スプレッドシート上の「ツール」メニュー→「スクリプトエディタ」を選択してスクリプトエディタを開きます。
![スクリーンショット 2014-06-20 21.29.58.png](https://qiita-image-store.s3.amazonaws.com/0/29682/fdbc72eb-465e-14de-94dd-a4a362ab842e.png)

空のプロジェクトを作成してスクリプトエディタ上に以下のコードを記述して、適当な名前でプロジェクトを保存してください。

```js:コード.gs
var WIDTH_CELL          = "B1";
var HEIGHT_CELL         = "B2";
var ZOOM_CELL           = "B3";
var CENTER_CELL         = "B4";
var DATA_START_ROW = 7;
var VISIBLE_COLUMN = 3;

// スプレッドシートを開いた時に自動的に実行される関数
function onOpen() {
  // メニューを作成
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [
    {
      name : "地図を作成",
      functionName : "createMap"
    },
    {
      name : "地図を削除",
      functionName : "resetMap"
    }
  ];
  spreadsheet.addMenu("地図作成メニュー", entries);
};

// 地図を作成メニューで実行する関数
function createMap(argSheet) {
  // 現在のシートを得る
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // 各セルのパラメータを元に地図を作成
  var map = Maps.newStaticMap()
       .setLanguage("ja")
       .setSize(sheet.getRange(WIDTH_CELL).getValue(), sheet.getRange(HEIGHT_CELL).getValue())
       .setZoom(sheet.getRange(ZOOM_CELL).getValue())
       .setCenter(sheet.getRange(CENTER_CELL).getValue());

  // 住所にマーカーをプロットする
  var lastRow = sheet.getLastRow();
  for (var row = DATA_START_ROW; row <= lastRow; row++) {
    if (sheet.getRange(row, VISIBLE_COLUMN).getValue() == "") {
      continue;
    }
    map.addMarker(sheet.getRange(row, 2).getValue());
  }  
  
  // 地図をシートに挿入
  sheet.insertImage(map.getMapUrl(), 5, 1);
};

// 地図を削除メニューで実行する関数
function resetMap() {
  var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  
  // 現在のシートの名前を保存しておく
  var currentSheet = spreadSheet.getActiveSheet();
  var sheetName = currentSheet.getName();
  
  // 新しいシートを作成して値をコピーする
  var newSheet = spreadSheet.insertSheet();
  currentSheet.getRange("A:D").copyTo(newSheet.getRange("A:D"));
  
  // 現在のシートを削除
  spreadSheet.deleteSheet(currentSheet);
  
  // シートの名を復旧
  newSheet.setName(sheetName);
  
  // 新しいシートをアクティブにする
  newSheet.activate();
}
```

## 実行 ##
### 地図を作成 ###
スプレッドシートに戻り、ブラウザを更新してください。少しするとメニューバーに「地図作成メニュー」が出現します。

![スクリーンショット 2014-06-20 21.34.11.png](https://qiita-image-store.s3.amazonaws.com/0/29682/f1620e6c-5765-d710-12bb-e38f76e2e3f9.png)


「地図作成」メニュー→「地図を作成」を選びます。少しすると、指定した住所にマーカーが表示された地図が表示されます(最初は認証を求められるかも)。

![スクリーンショット 2014-06-20 21.37.05.png](https://qiita-image-store.s3.amazonaws.com/0/29682/de8013a8-dc79-7623-91ab-fbf2cc20d374.png)


### パラメータ変更 ###
スプレッドシート上の「横幅」、「縦幅」、「倍率」、「中心」の値で、それぞれ地図の横幅、縦幅、倍率、中心を変更できます。「地図に表示」列の「◯」の有無でプロットする、しないを切り替えることができます。

試しに「倍率」を変更してメニューから先程と同様に「地図を作成」を実行すると、倍率が変わります。

### 地図を削除 ###
先ほどの動作では地図を更新しているように
見えますが、実は元地図の上に新しい地図を重ねているだけです。試しに表示されている地図を削除してみてください。最初の地図が残っているのがわかると思います。

なぜこんなことになっているかというと、GoogleAppsScriptに画像削除のAPIが(探した限り)見当たらなかったからです。なので地図の作成を続けているとどんどん古い地図が溜まっていってしまいます。

そこで地図削除機能の登場です。「地図作成」メニュー→「地図を削除」を選択してください。地図が消えるはずです。
この機能は新しいシートに値部分だけを丸々コピーして元シートは削除するという荒業で実現しています。

## 反省点 ##
### グリグリしたかった ###
Google App Scriptから作成できるマップは「静的」なマップです。Goole EarthやGoogle Mapsのようにマウスでグリグリ動かせません。ちょっと使いづらいですね。

### リアルタイムで更新したかった ###
現状だと、パラメータなどを変更したら毎回メニューを選択して更新する必要があります。一応、「トリガー」という機能で値が更新されたら地図を更新するということもできたのですが、GAS自体がそんなに早くないというのと、画像を削除できないので重くなる一方だったのでやめました。

### Google Maps APIを使ったほうが良かったと思う ###
以上のことから、こういう用途では[Google Maps API](https://developers.google.com/maps/?hl=ja)を使ったほうが良かったのかなと思います。よく知らないんですけどね。しかし、まぁGASの勉強になったので良かったです。

### Qiita初投稿 ###
全然関係ないですがこの投稿が自分のQiita初投稿で、あれやこれやと画像をアップロードしてみたのですが、あっという間に月の上限を超えてしまい全部アップロードできず・・・結局重要な数枚のみ残しました。未加工で思い画像をバシバシアップロードしちゃまずいんですね。色々なところに落とし穴はあるものです。