飲み過ぎを自覚できます（JSライブラリを使えば簡単に！）

# 飲み過ぎを自覚できます
筆者は30代半ばになりますが、歳のせいかアルコールが抜けなくなってきました。
読者の皆様におきましても、あぁ～今日はちょっと飲み過ぎちゃったななんて経験はあるのではないでしょうか。
飲み過ぎたという漠然とした後悔は感じつつも、果たして<b>どのくらい飲み過ぎてしまったのか</b>を意識できている方はいますか？少なくとも私は意識できていません（笑）
一般的に、1日に3単位（純アルコール量 60ｇ）以上摂取した場合を飲み過ぎと言うらしいです。
何はともあれシステムエンジニアの端くれとして、<b>飲み過ぎを可視化</b>してみようと思います。

# 飲んだアルコールをカウントするだけ
代表的な飲み物（ビール、日本酒、焼酎、ワイン、ウィスキー、梅酒）をラインナップし、それぞれに設置しているカウントボタン押下で計上します。するとリアルタイムにグラフに反映されます。飲み過ぎ基準の3単位（純アルコール量 60ｇ）のラインを危険閾値として表示しています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820631/4d4b3c1e-81b5-d377-7fc2-c4aa5520024d.png" width=70%>
<h3>★実際のWebアプリはこちら　⇒　<a href="https://alcohol-intake.netlify.app/">アルコール換算</a></h3>

# 飲み過ぎを自覚するために必要なモノ
世の中いろいろと便利になってきていて、タダでスピーディーにWebアプリを開発できる時代になりました。
今回はその恩恵を存分に享受して、難しことはあまり考えずにサクッとWebアプリを作ってしまおうと思います。
<br>
<b>・CodePen</b>
ブラウザ上でHTML,CSS,JavaScriptのコードを記述し、リアルタイムで表示を確認しながら開発をすることができるサービスです。
<a href="https://qiita.com/fumu238/items/f73274aa1a188eb15794">CodePenの使い方(知らない人向け)</a><br>
<b>・JSライブラリ</b><br>
<details><summary>Vue.js</summary>
フロント側で内部処理させた結果をリアルタイムにページ上に表示させることができる。<br>
<a href="https://qiita.com/moyegogo1020/items/7cf9daaacc6bac1b3c33">１０分で基礎がわかるVue.js-入門</a>
</details>
<details><summary>Chart.js</summary>
折れ線グラフ、棒グラフ、円グラフ、レーダーチャートなどのグラフが簡単に描くことができる。<br>
<a href="https://qiita.com/aoi-takumi/items/f8856772a944c8b66982">chart.jsの使い方！chart.jsでおしゃれなグラフを表示する方法（入門編）</a>
</details>
<details><summary>chartjs-plugin-annotation</summary>
Chart.jsのグラフに横線を入れることができる。Chart.jsには様々なプラグインが用意されている。
グラフ内にデータ以外の線を引いたり、四角で囲ったりするにはプラグイン「chartjs-plugin-annotation」を使用する。<br>
<a href="https://qiita.com/michieru/items/da7a6527a9136ea6ec9f">Chart.jsで横棒を表示するだけのサンプル</a>
</details>
<b>・Netlify</b><br>
CodePenでエクスポートしたプロジェクトとNetlilfyにデプロイすることでWebアプリを公開できる。<br>
<a href="https://qiita.com/niihara_megumu/items/db8c53f0f5de9f377976">超便利ホスティングサービス Netlify</a>

# Webアプリソースコード
<details><summary>html</summary>

```html:index.html
<!DOCTYPE html>
<html lang="ja" >
<head>
  <meta charset="UTF-8">
  <title>Alcohol intake</title>
  <meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="./style.css">

</head>
<body>
<!-- partial:index.partial.html -->
<head>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.bundle.min.js" integrity="sha256-eA+ych7t31OjiXs3fYU0iWjn9HvXMiCLmunP2Gpghok=" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation@0.5.7/chartjs-plugin-annotation.min.js" integrity="sha256-Olnajf3o9kfkFGloISwP1TslJiWUDd7IYmfC+GdCKd4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
</head>
<h1>アルコール換算</h1>
<p id="p1">アルコール摂取量の基準とされるお酒の1単位とは、純アルコールに換算して20gです。<br>
  多量飲酒とは 、1日に純アルコール量 60ｇ以上摂取した場合を言い、多量飲酒習慣により肝障害や高血圧、 脳卒中、糖尿病などの生活習慣病をひき起こし、進行させる危険性が高くなります。
</p>
<h2>お酒を入力してみましょう！ グラフが表示されます！</h2>
<div id="vue-app">
  ・ビール（中ジョッキ：320ml）：<button @click="voteP">＋１</button> <button @click="voteM">－１</button>　※アルコール：5%<br>
　　アルコール摂取量：<span>{{ vueCounter }}</span>g
</div>
<br>
<div id="vue-app2">
  ・日本酒（１合）：<button @click="voteP">＋１</button> <button @click="voteM">－１</button>　※アルコール：15%<br>
 　　 アルコール摂取量：<span>{{ vueCounter2 }}</span>g
</div>
<br>
<div id="vue-app3">
  ・焼酎（１合）：<button @click="voteP">＋１</button> <button @click="voteM">－１</button>　※アルコール：20%<br>
 　　 アルコール摂取量：<span>{{ vueCounter3 }}</span>g
</div>
<br>
<div id="vue-app4">
  ・ワイン（グラス：120ml）：<button @click="voteP">＋１</button> <button @click="voteM">－１</button>　※アルコール：12%<br>
 　　 アルコール摂取量：<span>{{ vueCounter4 }}</span>g
</div>
<br>
<div id="vue-app5">
  ・ウィスキー（シングル）：<button @click="voteP">＋１</button> <button @click="voteM">－１</button>　※アルコール：40%<br>
 　　 アルコール摂取量：<span>{{ vueCounter5 }}</span>g
</div>
<br>
<div id="vue-app6">
  ・梅酒（１合）：<button @click="voteP">＋１</button> <button @click="voteM">－１</button>　※アルコール：15%<br>
 　　 アルコール摂取量：<span>{{ vueCounter6 }}</span>g
</div>
<br>
******************************************
<div id="vue-appTotal">
  アルコール摂取量（単位換算）<button @click="vote">計算</button>：<span>{{ vueCounterTotal }}</span>
</div>
<canvas id="chart">
  Canvas not supported...
</canvas>
<!-- partial -->
  <script  src="./script.js"></script>

</body>
</html>
```
</details>

<details><summary>css</summary>

```css:style.css
h1 {
  color: #505050;/*文字色*/
  padding: 0.5em;/*文字周りの余白*/
  display: inline-block;/*おまじない*/
  line-height: 1.3;/*行高*/
  background: #dbebf8;/*背景色*/
  vertical-align: middle;
  border-radius: 25px 0px 0px 25px;/*左側の角を丸く*/
}

h1:before {
  content: '●';
  color: white;
  margin-right: 8px;
}

h2 {
	position: relative;
	padding: 1rem 2rem;
	border-radius: 10px;
	background: #27acd9;
	color: #fff;
}
h2:after {
	position: absolute;
	content: '';
	width: 0;
	height: 0;
	bottom: -10px;
	left: 1.5em;
	border-width: 10px 10px 0 10px;
	border-style: solid;
	border-color: #27acd9 transparent transparent transparent;
}

p {
	position: relative;
	padding: 1rem 2rem;
	border: solid 2px #27acd9;
}
p:after {
	position: absolute;
	content: "アルコール換算について";
	top: -10px;
	left: 15px;
	background: #fff;
	font-size: 0.75rem;
	color: #27acd9;
	padding: 0 10px;
}
```
</details>

<details><summary>JavaScript</summary>

```javascript:script.js
//window.onload = function () {
// Vue.jsの場合
var amount = 0;

const app = new Vue({
  el: '#vue-app',
  data: { vueCounter: 0, intCnt: 0,}, // アルコール量と回数を保持する
  methods: {
    voteP: function () {
      this.intCnt++; // クリック回数を増やす
      this.vueCounter = this.intCnt * 13;
      amount = amount + 0.65;
      draw();
      console.log('amount: ',amount);
      console.log('ビール１杯削除', this.vueCounter);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
    voteM: function () {
      this.intCnt--; // クリック回数を減らす
      this.vueCounter = this.intCnt * 13;
      amount = amount - 0.65;
      draw();
      console.log('amount: ',amount);
      console.log('ビール１杯追加', this.vueCounter);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
  },
});

const app2 = new Vue({
  el: '#vue-app2',
  data: { vueCounter2: 0, intCnt2: 0,}, // アルコール量と回数を保持する
  methods: {
    voteP: function () {
      this.intCnt2++; // クリック回数を増やす
      this.vueCounter2 = this.intCnt2 * 20;
      amount = amount + 1;
      draw();
      console.log('amount: ',amount);
      console.log('日本酒１杯追加', this.vueCounter2);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
    voteM: function () {
      this.intCnt2--; // クリック回数を減らす
      this.vueCounter2 = this.intCnt2 * 20;
      amount = amount - 1;
      draw();
      console.log('amount: ',amount);
      console.log('日本酒１杯削除', this.vueCounter2);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
  },
});

const app3 = new Vue({
  el: '#vue-app3',
  data: { vueCounter3: 0, intCnt3: 0,}, // アルコール量と回数を保持する
  methods: {
    voteP: function () {
      this.intCnt3++; // クリック回数を増やす
      this.vueCounter3 = this.intCnt3 * 29;
      amount = amount + 1.45;
      draw();
      console.log('amount: ',amount);
      console.log('焼酎１杯追加', this.vueCounter3);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
    voteM: function () {
      this.intCnt3--; // クリック回数を減らす
      this.vueCounter3 = this.intCnt3 * 29;
      amount = amount - 1.45;
      draw();
      console.log('amount: ',amount);
      console.log('焼酎１杯削除', this.vueCounter3);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
  },
});

const app4 = new Vue({
  el: '#vue-app4',
  data: { vueCounter4: 0, intCnt4: 0,}, // アルコール量と回数を保持する
  methods: {
    voteP: function () {
      this.intCnt4++; // クリック回数を増やす
      this.vueCounter4 = this.intCnt4 * 12;
      amount = amount + 0.6;
      draw();
      console.log('amount: ',amount);
      console.log('ワイン１杯追加', this.vueCounter4);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
    voteM: function () {
      this.intCnt4--; // クリック回数を減らす
      this.vueCounter4 = this.intCnt4 * 12;
      amount = amount - 0.6;
      draw();
      console.log('amount: ',amount);
      console.log('ワイン１杯削除', this.vueCounter4);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
  },
});

const app5 = new Vue({
  el: '#vue-app5',
  data: { vueCounter5: 0, intCnt5: 0,}, // アルコール量と回数を保持する
  methods: {
    voteP: function () {
      this.intCnt5++; // クリック回数を増やす
      this.vueCounter5 = this.intCnt5 * 10;
      amount = amount + 0.5;
      draw();
      console.log('amount: ',amount);
      console.log('ウィスキー１杯追加', this.vueCounter5);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
    voteM: function () {
      this.intCnt5--; // クリック回数を減らす
      this.vueCounter5 = this.intCnt5 * 10;
      amount = amount - 0.5;
      draw();
      console.log('amount: ',amount);
      console.log('ウィスキー１杯削除', this.vueCounter5);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
  },
});

const app6 = new Vue({
  el: '#vue-app6',
  data: { vueCounter6: 0, intCnt6: 0,}, // アルコール量と回数を保持する
  methods: {
    voteP: function () {
      this.intCnt6++; // クリック回数を増やす
      this.vueCounter6 = this.intCnt6 * 22;
      amount = amount + 1.1;
      draw();
      console.log('amount: ',amount);
      console.log('梅酒１杯追加', this.vueCounter6);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
    voteM: function () {
      this.intCnt6--; // クリック回数を減らす
      this.vueCounter6 = this.intCnt6 * 22;
      amount = amount - 1.1;
      draw();
      console.log('amount: ',amount);
      console.log('梅酒１杯削除', this.vueCounter6);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
  },
});

const appTotal = new Vue({
  el: '#vue-appTotal',
  data: { vueCounterTotal: 0,},
  methods: {
    vote: function () {
      this.vueCounterTotal = amount;
      console.log('amount: ',amount);
      // データが変化すると、DOMも勝手に更新される。便利！
    },
  },
});
function draw(){
        var ctx = document.getElementById('chart').getContext('2d');
        var myChart = new Chart(ctx, {
            // The type of chart we want to create
            type: 'bar',

            // The data for our dataset
            data: {
                labels: ['アルコール摂取量'],
                datasets: [{
                    label: 'アルコール摂取量',
                    backgroundColor: 'rgba(255, 99, 132, 0.5)',
                    borderColor: 'rgb(255, 99, 132)',
                    fill: false,
                    data: [amount,0,10]
                }]
            },

            // Configuration options go here
            options: {
              title: {
                display: true,
                text: "アルコール摂取量"
              },
                annotation: {
                    drawTime: 'afterDatasetsDraw',
                    annotations: [
                        {
                            id: 'hline',
                            type: 'line',
                            mode: 'horizontal',
                            scaleID: 'y-axis-0',
                            value: 3,
                            borderColor: 'black',
                            borderWidth: 3,
                            label: {
                                backgroundColor: "red",
                                content: "危険",
                                enabled: true
                            },
                        },
                    ]
                }
            }
        });
       }
    //}
```
</details>

# 自覚しました
せっかく作ったので、最近の実績を計上してみます。
飲み過ぎ基準の約2倍でした。どうりで二日酔いになるはずです。。。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2820631/08da42fd-d957-67d5-4c5c-a853a62295fc.png" width=70%>

Web上のサービスとJSライブラリを利用するだけで、ここまで簡単に自覚させられるとは思ってもいませんでした。肝臓を労わろうと思います。<br>
今回も閲覧ありがとうございました。こんなライブラリ使うと面白いよ！等ありましたらご一報（コメント）ください。