0
1

More than 1 year has passed since last update.

【Rails6】レビューの平均値をレーダーチャートで表示する方法(gon、chartkick、chart.js)

Last updated at Posted at 2022-12-18

概要

前提

  • 今回の実装においては、chart.jsとchartkick両方を利用する。利用先は以下の通り。
    • トップビュー(/index):chartkickでバーチャート表示
    • 詳細ページ(/show):chart.jsでレーダーチャート表示
  • JSとrailsの連携は、gem gonを利用する。(chartkickはrails内で完結)
    • gonとは:controller内でセットした変数をJavascript内で使う事ができるgem。他にもあると思いますが、今回はこちら使用
  • テーブルやカラムの関係性については、下記データベース設計を参照。

データベース設計

image.png

gonとchartkick、chart.jsのインストール

  • Gemfileに以下を追記して、bundle installを行う
    • 上述の通り、JavaScriptとの連携が必要なので、gonというgemを利用してデータ渡しを行う。
gem 'gon'
gem 'chartkick'
  • yarn add chartkick chart.jsを行ってインストール
  • application.jschart.jschartkickを追加
app/javascript/packs/application.js
require("chartkick")
require("chart.js")
  • application.htmlに以下記載。CDNに公開されているjsファイルを読み込む。
    • gonもここで設定するので、include_gonを記載しておく
app/views/layouts/application.html.erb
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.min.js"></script>

<%= include_gon %>

chartkickについて

  • 簡単にグラフを作成することができるグラフ描画ライブラリ。他の言語でも使えるが、主にRubyで使われることが多いらしい。
  • 今回の場合...
    • index時では個別idが振られておらず、@reviewにおけるrailsとjavaの連携が難しいため(gon利用してもできず)、railsで完結するchartkickを利用。これにより、indexページの時点で各種項目の表示が可能になる。

トップビュー(/index)にchartkickでバーチャートを表示する

  • itemコントローラーには以下が記載済み
app/controllers/items_controller.rb
class ItemsController < ApplicationController
  def index
    @items = Item.all.page(params[:page]).per(10).order(item_name: 'ASC')
    @itemsindex = Item.all.order(item_name: 'ASC')
    @reviews = Review.all
    @all_rating = '総合評価'
    @rating1 = '評価1'
    @rating2 = '評価2'
    @rating3 = '評価3'
    @rating4 = '評価4'
    @itemname =  Item.pluck(:item_name)
    gon.itemname = @itemname
  end
  • _item.html.erbに以下を追記する
    • 部分テンプレート作っていなければindex.html。今回はindexで<%= render partial: 'item', collection: @items %>をしているので、_item.html.erbに記載しています
app/views/items/_item.html.erb
<%= column_chart  [
     ["評価1", item.reviews.average(:rating1).to_f.round(1)],
     ["評価2", item.reviews.average(:rating2).to_f.round(1)],
     ["評価3", item.reviews.average(:rating3).to_f.round(1)],
     ["評価4", item.reviews.average(:rating4).to_f.round(1)],
      ] , label: "#{item.item_name}の評価" , width: "300px", height: "300px" , min: 0, max: 5, 
     colors: ["#FF0000", "#FFA500", "#AFDFE4", "#F0FFF0"] 
     %>
  • グラフの種類は以下がある
    • column_chart(縦棒グラフ)
    • bar_chart(横棒グラフ)
    • line_chart(折れ線グラフ)

chartkickで解決できなかった問題

  • いくつか不具合?が発生。どこかのgemが影響しているのか?対応方法不明。
    • bar_chartと記載しても、column_chartになってしまう
    • Min/Maxを設定しているのに反映されない
    • ラベルを消しても、赤い四角だけが残る。
  • 以下で2022/06/11に質問したが、回答なし...

詳細ページ(/show)にchart.jsでレーダーチャートを表示する

  • itemコントローラーで以下を記載する
    • 上述の通り、JavaScriptとの連携が必要なので、gonというgemを利用してデータ渡しを行う。
app/controllers/items_controller.rb
  def show
    @item = Item.find(params[:id])
    @review = Review.new
    @reviews = @item.reviews.includes(:user)
    gon.item = @item
    gon.rate1 = @item.reviews.average(:rating1).to_f.round(1)
    gon.rate2 = @item.reviews.average(:rating2).to_f.round(1)
    gon.rate3 = @item.reviews.average(:rating3).to_f.round(1)
    gon.rate4 = @item.reviews.average(:rating4).to_f.round(1)

    @all_rating = '総合評価'
    @rating1 = '評価1'
    @rating2 = '評価2'
    @rating3 = '評価3'
    @rating4 = '評価4'
  end
  • _show_chart.html.erbに以下を追記する

    • 部分テンプレート作っていなければshow.html。今回はindexで<%= render partial: "items/show_chart" %>をしているので、_show_chart.html.erbに記載しています
  • chart.jsはグラフ描画エリアの指定に、canvas要素を使用する

    • <canvas id="myChart"></canvas> 
  • canvas要素(ID : myChart ) を取得し、変数 ctx に入力する

    • var ctx = document.getElementById("myChart");
  • 今回はレーダーチャートなのでradarを選択

    • type: 'radar'。他にも公式サイトにたくさん種類あります
  • dataには、controllerで定義した以下を代入

    • data: [gon.rate1, gon.rate2, gon.rate3, gon.rate4]
    • ※総合評価はレーダーチャート項目には含めていません
  • labelには、controllerで定義した以下を代入。

    • label: gon.item.item_name
  • optionで、最小値・最大値を設定。

_show_chart.html.erb
<div class="chartbox">
<canvas id="myChart"></canvas> 
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
  type: 'radar',
  data: {
    labels: ["評価1", "評価2", "評価3", "評価4"],
    datasets: 
    [
        {
        label:  gon.item.item_name ,
        backgroundColor: 'rgba(255,140,0,0.2)',
        borderColor: 'rgba(255,69,0,0.2)',
        data: [gon.rate1, gon.rate2, gon.rate3, gon.rate4]
        },
    ]
  },
  options: {
      scale: {
          ticks: {
              suggestedMin: 0,
              suggestedMax: 5
          }
      }      
  }
});
   
</script> 
</div>
0
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
0
1