LoginSignup
2
1

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-08-22

今回やったこと

すでにx軸が日付、Y軸がカロリーの棒グラフは作ってあり、そこにY軸に体重の折れ線グラフを追加していきます。
スクリーンショット 2020-08-22 午後8.04.20.png

グラフ実装前の下準備

体重入力フォームを追加

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

スクリーンショット 2020-08-21 午後3.48.55.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

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

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

体重を表示

_post.html.haml
.weight
- if post.weight.present?
  = post.weight
  kg

実際のページ(表示されるとこうなる)

スクリーンショット 2020-08-22 午後8.02.51.png

いよいよグラフに体重を追加していく!!

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

現状のグラフはどうなっているかというと、こんな感じ。
スクリーンショット 2020-08-22 午後8.04.20.png

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


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

完成コードはこちら

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
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>

<%# htmlscriptタグ内に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

参考にした記事と完成までのプロセス

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,を追加して線の形にして終了。
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1