スプレッドシートに記入された値をチャートにして定期的にメールで送信する

# 問題

Google スプレッドシートに記入された値をチャートにして、一日に一度メールで送信したい

# 解決法

スプレッドシートに対してGoogle Apps Scriptを割り当て、Chartsでチャートを作成してMailAppで送信する関数を一日に一度決まった時間に実行することで、スプレッドシートに記入された値をチャートにしてメールで通知する。

## 材料

- [Google スプレッドシート](https://gsuite.google.com/intl/ja/products/sheets/)
- [Google Apps Script](https://developers.google.com/apps-script/)

想定している使用場面やデータの形式等に関しては「[Google スプレッドシートで変化があったらメールで通知する](http://qiita.com/mayfair/items/e1d6a5d880a82b8ae398)」の続きです。

## 実装

```js:サンプル1
function onDailyTimeBasedTrigger(event) {
  // 現在ブラウザで開いているシートを取得する
  var sheet = SpreadsheetApp.getActiveSheet();

  // スクリプトのプロパティからメールの受信者を取得
  var scriptProperties = PropertiesService.getScriptProperties();
  var recipient = scriptProperties.getProperty('recipient');

  // トリガーを削除
  deleteTrigger();

  // データテーブルを作成
  var data = Charts.newDataTable();
  data.addColumn(Charts.ColumnType.STRING, 'Time');
  data.addColumn(Charts.ColumnType.NUMBER, 'Temperature');

  // アクティブなシートを取得する
  var sheet = SpreadsheetApp.getActiveSheet();

  // ヘッダ行を除いて全ての値を取得し、データテーブルに追加する
  var values = sheet.getRange(1, 1, sheet.getLastRow(), 2).getValues();
  for (var row in values) {
    data.addRow([values[row][0], values[row][1]]);
  }

  // データテーブルをビルド
  data.build();

  // チャートを生成してビルド
  var chart = Charts.newLineChart()
    .setDataTable(data)
    .setTitle('本日のレポート')
    .setDimensions(1024, 768)
    .build();

  MailApp.sendEmail(
    recipient,
    '本日のレポート',
    '本日のレポートです。', 
    { attachments: chart });
}
```

ここで、メールの宛先は［ファイル］→［プロジェクトのプロパティ］で表示されるダイアログで`recipient`という名前にプロパティに対する値としてセットします。

![スクリーンショット 2017-01-12 17.01.34.png](https://qiita-image-store.s3.amazonaws.com/0/92577/ff955585-96d9-122a-e873-3247d9c64aa0.png)
プロジェクトのプロパティの画面例

![サンプル1の実行結果例](https://qiita-image-store.s3.amazonaws.com/0/92577/e6a49e3e-3543-2418-0beb-586773949591.png)
サンプル1の実行結果例

![スクリーンショット 2017-01-08 19.32.17.png](https://qiita-image-store.s3.amazonaws.com/0/92577/f6c579ff-5442-de69-756a-e3313bc07a52.png)
トリガーの設定例

# ディスカッション

そのままチャートにするだけであれば、`Charts.setDataSourceUrl()`でスプレッドシートのURLを渡してしまうのが一番簡単です。しかしながら、データに対して何らかの処理を加えたいのであれば、この例のように一旦全てのデータを取得し、必要な処理を加えた上でチャートに与えた方が自由度は増します。例えば、一定の区間毎に最高値と最低値（例：最高気温と最低気温）を求めて表示したい場合には取得したデータをもとにチャート用のデータを生成することができます。

上記の例では、日タイマーを利用してトリガーを発生するタイミングを選択しました。しかしながら、日タイマーでは実行する時間帯を「午後5時〜6時」のように大まかにしか設定できません。このくらいの範囲で問題ない場合にはこのままで良いと思いますが、もう少し正確に設定したい場合（例：毎日午後5時にレポートを送信したい）であれば、サンプル2のようにして2段階のトリガーを用いるとよいでしょう。

1. 日タイマーを用いて1日の早い時点でトリガーをセットする
2. セットしたトリガーで実際の処理を実行する

```js:サンプル2
// トリガーをセット
function setTrigger() {
  // 現在の時刻でDateオブジェクトを生成
  var timeofday = new Date();

  // トリガーを発生したい時、分、秒にセット
  timeofday.setHours(17);
  timeofday.setMinutes(00);
  timeofday.setSeconds(00);
  ScriptApp.newTrigger("sendDailyReport").timeBased().at(timeofday).create();
}

// トリガーを削除
function deleteTrigger() {
  var triggers = ScriptApp.getProjectTriggers();
  for (var i in triggers) {
    if (triggers[i].getHandlerFunction() == "sendDailyReport") {
      ScriptApp.deleteTrigger(triggers[i]);
    }
  }
}

// 1日のレポートを送信
function sendDailyReport() {
  deleteTrigger();

  // レポート作成と送信の処理をここに
}
```

ここでセットしたトリガーは［リソース］→［現在のプロジェクトのトリガー］で確認できます。

![「現在のプロジェクトのトリガー」での表示例](https://qiita-image-store.s3.amazonaws.com/0/92577/5a22298c-fa1a-6291-2848-37f71e2806e1.png)
「現在のプロジェクトのトリガー」での表示例

# リファレンス

- [Google Apps Scriptの日毎のトリガーで時間をもっと細かく設定する](http://qiita.com/sumi-engraphia/items/465dd027e17f44da4d6a)