🐶

Googleスライドを使ったビンゴカードの作り方

2021/12/06に公開

ただ解説するだけじゃちょっとつまらないので脳内を可視化する感じで書いてみました。
こういうツールをGASで実装するとき @howdy39 は何を考えているのかを解説しようかなと。

あらすじ

会社でリモートでビンゴをやろうということになったのだが、このやり方が面白い。
どういうやりかたかというと数字の代わりに社のSlackで使われている絵文字で作るというものだった。
肝心のビンゴカードの作り方としてはGoogleスライドにビンゴの台紙と絵文字の一覧があってそこから自分で好きな絵文字を選んでカードを作ってね。みたいな方式。

その発想がでてくるセンスがうらやましいと思ったが、いっぱいあるなかから選ぶのって悩んでしまう人いっぱいいるだろうなと思って自動生成するコードを書くか、と思ったのでした。

何でつくるか

スライドやスプレッドシートをはじめとしたGoogle Workspace系でごにょごにょしたいときはAPIを自分でたたくかGASでたたくかの二択です。
できることは API > GAS のケースがほとんどで、昔はGASでしか出来ないこともあったのですが最近はAPIが充実しているので、出来ることベースだとGASは下位互換とみていいでしょう。

そこまで聞くとじゃあAPI叩こうとなるのですが、そう話しは単純ではなくGASの方は認証済みの状態で叩くので実装が圧倒的にラクなのですよね。
なので筆者の場合、GASが有効ならGASでやる。有効でないならAPIでやるみたいな優先順位で作ります。
※今回の場合、GASで十分出来そうだったのでGASです。

設計する

とりあえず実装してませんか?
適当に作ってもうまくいかないです。設計はとても大事です。
私の場合、設計とPoCを同時並行で進めるイメージでやってます。

まず最初に考えた最終的なゴール(要件)はこんな感じです

  • ランダムで作られた24絵文字のビンゴカードをつくる(中央は固定)
    • ※ 絵文字は全部で65種
  • 利用者は100名程度を想定

ランダムで作る際に、人ごとにビンゴカードを作るか(都度生成)、大量に事前にビンゴカードを作っとくかの2つの方法を考えました。

都度生成方式はスライドのメニューバーにボタンを作ってそこを押すことでビンゴカードのスライド生成して、マイドライブかどっかに置いてあげるみたいな感じですね。
Google Apps Scriptを使った独自メニューの作り方 - Qiita

大量に事前に作っとく方式は一つのスライドにどかっと用意してあげて好きなの選んで。みたいな感じです。

今回は後者の大量に事前に作っとく方式を採用しました。
前者の方はメニューバーのボタンを押して〜をやらせる際にGASの認可が動いてしまうのですよね。
GASに慣れた人なら、最初の一回は認可でもう一回叩けば動くというのがわかるのですが使う人全員がGASに慣れてるわけじゃないのでここをサポートするの大変そうだなと。
一方後者であれば、そのままスライドを利用して貰う、スライドの画像をダウンロードしてもらう、スライドをコピーして貰うとかGASの知識不要で使えます。
デメリットとしてスライドが多少重くなるのと、ビンゴカードかぶりが発生する可能性があったりするのですがまぁそこは許容でいいかなと。
※ 今後もなんども使うツールなら前者の方で実装した方がいいとおもいます

どうやってビンゴカードを生成するか

必要なのは次の2つの機能です。

  • 台紙のスライドを複製する
  • 複製したスライドに24の絵文字を任意の場所に配置できる

スライドの複製はSlide#duplicate()というドンピシャなメソッドが見つかったので問題なくクリア。

後者の絵文字の貼り付けがちょっとやっかいでした。
最初に考えたのは24のオブジェクトを事前に台紙スライドに貼っといて画像の中身を置き換えるものです。
しかしそれっぽいメソッドがない。。。

その次に考えたのは65の画像をDriveにおいといてそこから読み込んで貼り付けるというものでしたが、これはSlide#insertImage()で実装可能だったものの実行が遅すぎて今回みたいな大量の画像を扱う場合には向いていなかったです。

で結局どうしたかというと画像オブジェクトを事前にスライドに配置しといて複製して台紙に貼り付けるというものです。
Slide#insertPageLementを使うことでinsert元のオブジェクトを残したまま、複製されたPageElmentオブジェクト(絵文字)が作られます。
またPageElementPageElement#setLeft()PageElement#setTop()をつかうことでスライド内での位置が調整できます。

これらを組み合わせればビンゴカードが作れそうというのがわかったので実装してきます。

スライドはこんな感じ

1枚目に全部の絵文字画像を貼り付けたスライドを作る
2枚目に台紙を作る
3枚目からは自動で作られるビンゴカードです

コードはこんな感じ

30行ぐらいしかないので大体雰囲気でわかると思います。
※ シャッフル部分は適当にググって引っ張ったコードです
※ 69, 96, 89とかのマジックナンバーはビンゴカードの台紙に合わせて位置を微調整しただけです

const imageSlide = SlidesApp.getActivePresentation().getSlides()[0];
const bingoBaseSlide = SlidesApp.getActivePresentation().getSlides()[1];

function generateBingoCards() {
  for(let i = 0; i < 100; i++) {
  const newSlide = bingoBaseSlide.duplicate();
  generateBingoCard(newSlide);
  }
}

function generateBingoCard(slide) {
  const elements = fisherYatesShuffle(imageSlide.getPageElements());
  const rootLeft = 69;
  const rootTop = 96;

  let fileIndex = 0;
  const j = 0;
  for (let i = 0; i < 5; i++) {
    for (let j = 0; j < 5; j++) {
      if(i === 2 && j === 2) {
        continue;
      }
      const e = elements[fileIndex++];
      slide.insertPageElement(e).setLeft(rootLeft + j * 96).setTop(rootTop + i * 89)
    }
  }
}

function fisherYatesShuffle(arr){
  for(var i =arr.length-1 ; i>0 ;i--){
    var j = Math.floor( Math.random() * (i + 1) ); //random index
    [arr[i],arr[j]]=[arr[j],arr[i]]; // swap
  }
  return arr;
}

おわりに

GASは便利なのでみんな使いこなしていこうな。

Discussion