【GAS】スプレッドシートから日めくり献立カレンダーを生成する

## 1. やりたいこと

こんな献立表を読み込んで

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917871/94192cf4-5c38-a442-ef9d-28d276045744.png)

こんなスライドたちを生成する（スライドのテンプレートは手動で作る）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917871/00f40b36-be01-61bd-61fb-fa45b5dbf900.png)
## 2. 準備

### テンプレートスライドの作成

テンプレートになるスライドを作成しておく
今回はこんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917871/d4b77245-7bd2-06d4-e476-4760395fb2d3.png)

### スプレッドシートの読み込み

献立表スプレッドシートにAppsScriptを追加して書いていく
シート名を指定して、献立が書いてあるシートを取得する（ここでは'menu'）

```js
  const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = spreadSheet.getSheetByName('menu');
```

### 献立リストの取得

B2からH4セルに書かれている献立を取得する

```js
  var range = sheet.getRange('B2:H4');
  var menulist = range.getValues();
```

とれた中身はこうなる

```text: menulist
[ [ 'トースト、アボカド、ゆで卵、フルーツサラダ',
    'ギリシャヨーグルト、グラノーラ、ブルーベリー',
    'オートミール、バナナ、ナッツ',
    'トースト、ピーナッツバター、リンゴスライス',
    'スムージー（ほうれん草、マンゴー、ヨーグルト）',
    'フレンチトースト、ベリーソース、紅茶',
    'トマトとチーズのオムレツ、トースト' ],
  [ '鶏むね肉のグリルと玄米、野菜スープ',
    'サンドイッチ（ターキーとチーズ）、ミネストローネ',
    'スパゲッティ・ボロネーゼ、サラダ',
    '鮭の塩焼き、ご飯、きんぴらごぼう',
    '鶏胸肉のサラダ、全粒粉パン',
    'ビーフシチュー、バゲット',
    '天ぷらそば、ほうれん草のおひたし' ],
  [ 'サーモンの照り焼き、ほうれん草のおひたし、味噌汁',
    '豚しゃぶサラダ、ご飯、豆腐とわかめの味噌汁',
    'チキンカレー、サラダ、ナン',
    'きのこリゾット、野菜スープ',
    '焼き餃子、野菜炒め、中華スープ',
    '寿司（巻き寿司や握り寿司）、お吸い物',
    '豚の角煮、ご飯、味噌汁' ] ]
```

B1からH1の日付も取得しておく

```js
  var range = sheet.getRange('B1:H1');
  var datelist = range.getValues();
```

こちらの中身はこうなる

```text: datelist
[ [ '2024/12/01',
    '2024/12/02',
    '2024/12/03',
    '2024/12/04',
    '2024/12/05',
    '2024/12/06',
    '2024/12/07' ] ]
```

### プレゼンテーションの読み込み

スライドを触っていく
スプレッドシートからの操作なので、IDを指定して開く必要がある

プレゼンテーションのURL `https://docs.google.com/presentation/d/xxxxx/edit` の xxxxx がIDになる

```js
  const presentationId = 'xxxxxx';
  const presentation = SlidesApp.openById(presentationId);
```

### テンプレートスライドの取得

getSlides()でスライドのリストを取得し、1枚目のテンプレートスライドを取り出す

```js
  const slides = presentation.getSlides();
  const templateSlide = slides[0];
```

## 3. まず1枚だけ生成してみる

### テンプレートスライドのコピー

スライドを編集するためにコピーする
(スライドオブジェクト).duplicate()でスライドを複製できる

duplicate()は複製されたスライドオブジェクトを返してくれる

```js
  var slide = templateSlide.duplicate();
```

参考： duplicate() | Class Slide | Apps Script | Google for Developers

https://developers.google.com/apps-script/reference/slides/slide?hl=ja#duplicate()

### テキストボックスに書き込む

テキストボックスはシェイプオブジェクトに分類されるらしい

(スライドオブジェクト).getShapes()でスライド上のシェイプを取得できる

```js
  var shapes = slide.getShapes();
```

shapesのどの要素が各テキストボックスがにあたるか分からないので、シェイプがもっているテキストで判定する

(シェイプオブジェクト).getText().asString()でテキスト文字列を取得でき、getText().setText()でテキストを書き込める
一致判定のため改行コードを削除しておくことに気を付ける

```js
  for (i=0; i<shapes.length; i++) {
    var text = shapes[i].getText();
    switch (text.asString().replace('\n','')) {
      case 'YYYY/MM/DD':
        text.setText('2024/12/01');
        break;
      case 'あさごはんのメニュー':
        text.setText('トースト、アボカド、ゆで卵、フルーツサラダ');
        break;
      case 'ひるごはんのメニュー':
        text.setText('鶏むね肉のグリルと玄米、野菜スープ');
        break;
      case 'ゆうごはんのメニュー':
        text.setText('サーモンの照り焼き、ほうれん草のおひたし、味噌汁');
        break;
    }
  }
```

実行するとこのようになスライドが生成される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917871/8ad97415-405d-b6cb-69b1-796bf7a6db9d.png)

## 4. 1週間分ループさせる

3.の操作をループさせて、日付の個数分スライドができるようにする

```js
  for (i=0; i<datelist[0].length; i++) {

    var slide = templateSlide.duplicate();
    var shapes = slide.getShapes();

    var date = datelist[0][i];
    var asa_gohan  = menulist[0][i];
    var hiru_gohan = menulist[1][i];
    var yuu_gohan  = menulist[2][i];

    for (j=0; j<shapes.length; j++) {
      var text = shapes[j].getText();
      switch (text.asString().replace('\n',''))
      {
        case 'YYYY/MM/DD':
          text.setText(date);
          break;
        case 'あさごはんのメニュー':
          text.setText(asa_gohan);
          break;
        case 'ひるごはんのメニュー':
          text.setText(hiru_gohan);
          break;
        case 'ゆうごはんのメニュー':
          text.setText(yuu_gohan);
          break;
      }
    }
  }
```
一週間分の献立表スライドが生成される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917871/00f40b36-be01-61bd-61fb-fa45b5dbf900.png)

:::note warn
順々に一枚目のスライドをコピーしていくので、日付が降順に生成されてしまう。昇順に並べたい場合はループを逆向きにするなど対応が必要
:::


## 5. まとめ

全体としては以下のようなスクリプトになる

```js
function myFunction() {
  
  const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = spreadSheet.getSheetByName('menu');

  var range = sheet.getRange('B2:H4');
  var menulist = range.getValues();
  var range = sheet.getRange('B1:H1');
  var datelist = range.getValues();

  const presentationId = 'xxxxx';
  const presentation = SlidesApp.openById(presentationId);
  const slides = presentation.getSlides();
  const templateSlide = slides[0];

  for (i=0; i<datelist[0].length; i++) {

    var slide = templateSlide.duplicate();
    var shapes = slide.getShapes();

    var date = datelist[0][i];
    var asa_gohan  = menulist[0][i];
    var hiru_gohan = menulist[1][i];
    var yuu_gohan  = menulist[2][i];

    for (j=0; j<shapes.length; j++) {
      var text = shapes[j].getText();
      switch (text.asString().replace('\n',''))
      {
        case 'YYYY/MM/DD':
          text.setText(date);
          break;
        case 'あさごはんのメニュー':
          text.setText(asa_gohan);
          break;
        case 'ひるごはんのメニュー':
          text.setText(hiru_gohan);
          break;
        case 'ゆうごはんのメニュー':
          text.setText(yuu_gohan);
          break;
      }
    }
  }
}
```