【個人アプリ作業メモ】1つのグラフで棒グラフと折れ線グラフを表示する方法

## 今回やったこと
すでにx軸が日付、Y軸がカロリーの棒グラフは作ってあり、そこにY軸に体重の折れ線グラフを追加していきます。
![スクリーンショット 2020-08-22 午後8.04.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/f7158914-52e4-6fb0-173f-b0e7b524bd60.png)

## グラフ実装前の下準備

### 体重入力フォームを追加

```ruby:
.weight
  体重
  = f.number_field :weight, step: '0.1', placeholder: '例）70'
  kg
```

![スクリーンショット 2020-08-21 午後3.48.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/cb0d8f05-22be-11c9-d4a4-47d26c0e55c4.png)

### 体重を保存するためのカラムを追加
https://qiita.com/azusanakano/items/a2847e4e582b9a627e3a#%E3%82%AB%E3%83%A9%E3%83%A0%E8%BF%BD%E5%8A%A0
この記事参考にすればすぐできます。

![スクリーンショット 2020-08-21 午後3.54.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/3efacea1-7b2e-041d-998d-badef908469d.png)

### ストロングパラメーターにも体重カラムを追加

```ruby:posts_controller.rb
private
  def post_params
    params.require(:post).permit(:food, :calorie, :protein, :fat, :carbo, :text, :image, :weight).merge(user_id: current_user.id)
  end
```
### 体重を表示
```ruby:_post.html.haml
.weight
- if post.weight.present?
  = post.weight
  kg
```

### 実際のページ（表示されるとこうなる）
![スクリーンショット 2020-08-22 午後8.02.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/a51eac1e-620e-9beb-818e-509823d3ea5b.png)

##  いよいよグラフに体重を追加していく!!
さて、ここからグラフにどうやってこの追加した体重を載せていくか？

現状のグラフはどうなっているかというと、こんな感じ。
![スクリーンショット 2020-08-22 午後8.04.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/f7158914-52e4-6fb0-173f-b0e7b524bd60.png)

現状ではヨコに体重、タテにカロリーだけ。
ここにタテに体重の折れ線グラフも追加して、カロリーと体重の相関を見れるようにしたい。

↓
わりとすぐに参考記事が見つかって意外と1時間でできました。

## 完成コードはこちら

```ruby:app/controllers/charts_controller.rb
class ChartsController < ApplicationController

  def index
    # カロリー
    # 日付ごとで分けてカロリー合計を算出
    sum_calorie = current_user.posts.group("date(created_at)").sum(:calorie)
    # 日付ごとのカロリー合計がハッシュの形なので値を取得して配列に入れて変数に代入
    array_calorie = sum_calorie.values

    # gonを使ってデータをjs側に渡す
    gon.data = []
    # mapメソッドで日付ごとのカロリー合計を1つずつ取り出す
    # mapメソッドの使い方 → 配列変数.map {|変数名| 具体的な処理 }
    gon.data = array_calorie.map{ |calorie| calorie}

    # 日付ごとにまとめてそのうちcreated_atカラムだけ取得。配列の形で格納されている
    dates_calorie = current_user.posts.group("date(created_at)").select(:created_at)

    gon.date = []
    @dates = dates_calorie.map{ |dates| dates.created_at}
    # each文で日付の表記を1つずつ取り出して変える
    @dates.each do |a|
      gon.date << a.strftime("%Y年%m月%d日")
    end


    # 体重 ☆今回この部分を追加しました☆
    gon.weight = current_user.posts.group("date(created_at)").select(:weight).map{ |weight| weight[:weight]}
  end
end
```

```ruby:app/view/charts/index.html.erb
<%# canvasタグ内にグラフを描く  %>
<div class="chart-container" style="position: relative; height:50vh; width:50vw">
    <canvas id="myChart"width="400" height="400"></canvas>
</div>

<%# htmlのscriptタグ内にjsを書いていく %>
<script>
# グラフ部分のDOMを取得しgetContextメソッドでグラフを描く
var ctx = document.getElementById("myChart").getContext('2d');

var myChart = new Chart(ctx, {
    
    type: 'bar',
    data: {
        # labelsでX軸を指定
        labels: gon.date,
        datasets: [{
            type: 'bar', # カロリーは棒グラフ
            label: "1日のカロリー合計",
            # dataでY軸を指定
            data: gon.data,
            backgroundColor: 'rgba(75, 192, 192, 0.2)',
            borderColor: 'rgba(75, 192, 192, 1)',
            borderWidth: 1,
            fill: false
        },
    #今回はこの部分を追加しました----------------------------
        {
            type: 'line', #体重は折れ線グラフ
            label: "体重",
            # dataでY軸を指定
            data: gon.weight,
            backgroundColor: 'rgba(255, 99, 132, 0.2)',
            borderColor: 'rgb(255, 99, 132)',
            borderWidth: 1.2,
            #これを書かないと棒線の下の部分が塗られてしまう
            fill: false,
        }]
    #------------------------------------------------------
    },
    options: {
        title:  {
            display: true,
            text: "カロリーグラフ"
        },
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                },
                id: 'y左軸'
            }]
        }
    }
});

</script>

<div class="home">
    <%= link_to 'ホームに戻る', root_path %>
</div>
```
## 出来上がったグラフがこちら
![スクリーンショット 2020-08-22 午後9.10.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/5e8eda89-b5fc-3cb4-0c37-cd2a833a9820.png)

## 参考にした記事と完成までのプロセス
http://www.dcom-web.co.jp/lab/javascript/draw_multi_axis_graph_using_chartjs
最初に参考にしたのがこのページ。

1. いきなりgonで渡さず、最初は上記記事を参考に[60, 70]と適当に数字を置いて表示されるか試した。
2. それがうまくいって、無事グラフが表示されることを確認したら、どうしたら体重をコントローラーからビューに受け渡せるか考えた。
3. 1日で1つの体重をどうやって取得するか難しそうだなと思っていたが、Railsのgroupメソッドを使うと、そのグループごとにidが最も小さいものにまとめてくれることがわかった。日付ごとにgroupメソッドでまとめれば、その日投稿されたpostsの中で最もidが小さいweightを取得できる。https://pikawaka.com/rails/group#group%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AE%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AA%E4%BD%BF%E3%81%84%E6%96%B9
4. あとはgonに代入してgonからgonへ受け渡す。
5. 最後に`fill: false,`を追加して線の形にして終了。