Google Spreadsheetで簡易食品データベースとカロリー計算機

#食事の管理と計算を簡易化したい
在宅で順調にデブったので人生初の食事管理に取り組んでみたのですが、食品のカロリーや栄養素を教えてくれるサイトやサービスが微妙に自分に合わなかったのでシンプルな計算機をSpreadsheetとGASで自作しました。自分に合わなかったのは以下のような点です。

- 一人前表示だったり、グラム表示だったり、微妙に各サービスによって単位が違う
- 100gあたりのカロリー表示が多く、毎回食べた量から計算しないといけない
- 食品が見つからないこともある
- 頻繁に食べるものを自分で登録しておけない
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/374cf727-cbd4-f1dc-ea57-6c6fec1b3133.gif" width="480">

#作ったもの
要は食事したときはおおよそ「これをこれだけ食った」しか認識・記憶できないので、まずこれ。

- 食べたものと食べた量を入力したらあとは自動でやってくれる

次に入力の手間を省きたいのでこれ。

- 食品を自分で自由にリスト登録できる

頭のいい人は画像認識とかAIとかでやってください。

#技術要素
- セルにドロップダウンリストを作る
- Spreadsheetのデータを取得してGoogleAppScriptで使う
- シートのデータを配列に入れる、取り出す

#結果
- いちいち食品のカロリーを調べなくて済むようになった、時短
- 自分だけの食品データベースを作れてわかりやすくなった、拡張性ばっちり
- 記録が継続しやすく、体重変化等と合わせると改めて自分の代謝量などが把握できるように

#実装
1. データベース（リスト）作成
「List」とシート名をつけて、適当に食べたものなどをもりもりいれます。B列には1グラム当たりのカロリーを入れていきます。だいたいの栄養系のサイトは100gあたりのカロリー表示なので、それらを100で割った値です。
<img width="371" alt="2020-05-31_10h39_14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/58c327e9-9f09-c77e-5485-0d9316b836c6.png">

2. プルダウンメニュー作成
食事記録用のシート、例えば「202005」を作成して、食品のプルダウンを表示したいセルを右クリック、「データの入力規則」を選択。
<img width="323" alt="2020-05-31_10h41_02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/69cc0601-dbe8-487f-621f-35dccc29cbd5.png">
セルにプルダウンリストを表示にチェックを入れ、その上の「条件：リストを範囲で指定」一番右の田の字をクリックします。
<img width="386" alt="2020-05-31_10h43_21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/c43e5bca-5909-7b01-cba1-858f3da69874.png">
すると、「データ範囲の選択」ダイアログが出るので、その状態で気にせず作成済みのシート「List」に移動。リスト表示したい食品名を範囲選択してOK、保存でドロップダウンリストを作成できます。
<img width="386" alt="2020-05-31_10h43_21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/610635e9-8b2d-b1d8-4ac9-f0ee0160d5a1.gif">

3. プログラム作成

- 準備

ツール>スクリプトエディタを選択、エディタ画面を表示します。
<img width="297" alt="2020-05-31_10h58_53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/45a009f2-81b8-2ea6-e317-7b612eb0307d.png">
プルダウンの選択やグラム入力をトリガーとして計算を走らせたいので、スクリプトエディタ上部のメニューから「トリガー」ボタンをクリック。
<img width="335" alt="2020-05-31_11h04_52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/7ea1d7e0-ccc4-18e4-9822-834457de9fa2.png">
「トリガーを追加」ボタン>イベントの種類を選択>変更時とすることで、シート上の値が変更されたタイミングでスクリプトが実行されるようになります。
<img width="500" alt="2020-05-31_11h08_15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/b7ba5f77-7dcf-7d66-fbf5-9f4b238028bc.png">
次にSpreadsheetに対してScriptからのアクセスを許可を確認するダイアログがでますので以下の手順でオーソライズしていきます。まずGoogleにログイン。ログインに使うアカウントを選択。
<img width="378" alt="2020-05-31_11h12_21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/8ee1b8ed-9d47-2852-61dd-01a7f61768df.png">
次に今作成中のScriptのシートへのアクセス許可を与えていきます。詳細をクリック。
<img width="379" alt="2020-05-31_11h12_49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/f76d57ed-fb8c-2a97-ebef-0681b92399a4.png">
「calorie（作成中のScript）に移動」をクリック。
<img width="380" alt="2020-05-31_11h22_12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/fc51b92b-3c6f-3d8b-d876-d38ebcad5c9e.png">
こんな感じで「ScriptからシートにアクセスしますけどOK？」という意味合いのダイアログがでるので許可。これでシートとScriptが連動して動くようになります。食品を入力したり、グラム数を入力したタイミングでScriptが実行されます。
<img width="380" alt="2020-05-31_11h22_29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/d089a84e-cec0-72b2-716a-a3aba1efbfeb.png">

- コード

```javascript:code.gs
function myFunction() { 
  //変更したセルの値の取得
  var ss = SpreadsheetApp.getActiveSheet(); 
  var currentRow = ss.getActiveCell().getRow(); 
  var currentColumn = ss.getActiveCell().getColumn();
  var currentCell = ss.getActiveCell().getValue();   

  //グラム数を入力したときの値を取得
  var amount=ss.getRange('C'+ currentRow);
  amount=amount.getValue();

  //計算後に入力されるカロリーのセルを定義
  var calorieCell=ss.getRange('D'+ currentRow);

  //Listシートのデータを配列に入れる
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var list = spreadsheet.getSheetByName('List');
  var lastRow = list.getLastRow();
  var value = list.getDataRange().getValues();

  //取得した二次元配列内の検索用に食品名だけの配列も作る
  var name = list.getRange(1, 1, lastRow).getValues();
  name=name.flat();//二次元配列を一次元化。ここで結構ハマった。
  
  //プルダウンから選択した食品のカロリーをListシートの中から検索
  var food=ss.getRange('B'+ currentRow);
  food=food.getValue();
  foodIndex=name.indexOf(food);
  foodIndex=parseInt(foodIndex);
  var calorieValue=value[foodIndex][1];

  //グラム数と1グラム当たりのカロリーを乗算
  var calorieSum=amount*calorieValue;
  
  //見出し行や食品名・グラムのセル以外の変更を除外
  if(currentRow>1){
    if(currentColumn==2.0 || currentColumn==3.0){
    calorieCell.setValue(calorieSum);//計算結果がカロリーのセルに入る
    }
  } 
}
```

#まとめ
Spreadsheetで簡単に拡張できるカロリー計算機ができました。プログラムに興味のない方はコピペで。Listの方にPCFカラム、ビタミン・ミネラルのカラムを作っても面白いと思います。