顔写真から一人を選ぶアニメーション付きのルーレットを即興で作れと言われた

決算パーティーで盛り上げるため、社員の１人をランダムに選ぶルーレットがほしいと言われ、
このようなものを作りました。

[http://animated-random-user-picker.s3-website-ap-northeast-1.amazonaws.com/](http://animated-random-user-picker.s3-website-ap-northeast-1.amazonaws.com/)
![demo360.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256466/db874d4d-ccf8-36da-924c-12b9c37e3575.gif)

レポジトリは[https://github.com/umihico/animated-random-user-picker](https://github.com/umihico/animated-random-user-picker)です。
以下の仕様をこちらで決め、２時間で制作しました。

+ Slackプロフィールアイコンを全てダウンロードして活用する　（40分）
+ 即デプロイしたいのS3でホスト、HTTPS無しOK　（10分）
+ 最小限のhtmlファイル１つにし、vueをCDNから使わせてもらう　（10分）
+ vuetifyとlodashも使いたくなったのでCDNから取る　（10分）
+ ルーレット実装　（50分）

[S3でのホストはこちらを参考にさせて頂きました。](https://qiita.com/tsukapah/items/96e8402181609518fd3d)
[vueをhtmlファイル単体で動かすのはこちらを参考にさせて頂きました。](https://qiita.com/kai_kou/items/e060b1f407f39eeb4a90)
デモ用の画像は[イラストや](www.irasutoya.com/)からお借りしています。 
皆様ありがとうございます。

[Slackから全員のプロフィール画像をとるのは別記事にしました。](https://qiita.com/umihico/items/7f3af0b20679f76e38d2)

CDNからlodash, vue, vuetifyを使っています。

```html:index.html
<html>
<head>
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
    <meta charset="UTF-8">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<div id="app">
    <v-container>
        <p><a target="_blank" href="https://github.com/umihico/animated-random-user-picker">Github</a></p>
        <p><a target="_blank" href="https://qiita.com/umihico/items/7878dbaca57b21d2bfc0">Qiita</a></p>
        <v-btn @click="shuffle">シャッフル！</v-btn>
        <v-btn @click="run">
            <template v-if="moving">ストップ</template>
            <template v-else>スタート</template>
            ！
        </v-btn>
        <v-row>
            <v-col xl="3" lg="3" md="4" sm="3" cols="12">
                <v-img max-height="200" contain v-if="picked" :src="picked"></v-img>
            </v-col>
            <v-col xl="9" lg="9" md="8" sm="9" cols="12">
                <v-row>
                    <v-col xl="1" lg="1" md="2" sm="2" cols="2" v-for="path in paths" v-bind:key="path">
                        <v-img contain :src="path" max-height="50"
                               :gradient="(picked==path) ? 'to top right, rgba(100,115,201,.60), rgba(100,115,201,.60)' : ''"
                        >
                            <div class="fill-height bottom-gradient"></div>
                        </v-img>
                    </v-col>
                </v-row>
            </v-col>
        </v-row>
        <div style="max-width:500px">
        </div>
    </v-container>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            pos: 0,
            picked: null,
            moving: false,
            paths: ["img/nigaoe_adam_smith.png",
                "img/nigaoe_amakusa_shirou.png",
                // 省略
                "img/nigaoe_yamaoka_tessyuu.png",
            ]
        },
        methods: {
            shuffle() {
                this.paths = _.shuffle(this.paths)
            },
            run() {
                this.moving = !this.moving
            }
        },
        mounted() {
            setInterval(function () {
                if (this.moving) {
                    this.pos += 1;
                    if (!this.paths[this.pos]) {
                        this.pos = 0
                    }
                    this.picked = this.paths[this.pos]
                }
            }.bind(this), 3)
        }
    })
</script>
</body>
</html>

```

S3ホストのためにファイルを公開しないといけないので、ポリシーファイルを作成します。

```json:policy.json
{
    "Version": "2012-10-17",
    "Id": "PublicRead",
    "Statement": [
        {
            "Sid": "ReadAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::animated-random-user-picker/*"
        }
    ]
}
```

ファイルの用意ができれば、以下のコマンドでデプロイできます。

```bash
$ aws s3 mb s3://animated-random-user-picker # バケット作成
$ aws s3 website s3://animated-random-user-picker --index-document index.html # 静的ウェブサイトとしてホスト
$ aws s3api put-bucket-policy --bucket animated-random-user-picker --policy file://policy.json # only once # ポリシーファイル適用
$ aws s3 sync . s3://animated-random-user-picker --exclude=.git/* # バケットにカレントディレクトリと同期させる
```

その他参考

- https://vuejs.org/v2/guide/transitions.html
- https://vuetifyjs.com/en/getting-started/quick-start/#cdn-usage 
- https://qiita.com/kahirokunn/items/b4f3ede5b2eb94711880