概要
- Userが5段階評価ができる5つの項目のレビューを行うと、それぞれの平均値がレーダーチャートとなってトップビューに表示される実装を行ったので、その手順を記す。5段階評価機能については、別記事でまとめています。
前提
- 今回の実装においては、chart.jsとchartkick両方を利用する。利用先は以下の通り。
- トップビュー(/index):chartkickでバーチャート表示
- 詳細ページ(/show):chart.jsでレーダーチャート表示
- JSとrailsの連携は、gem gonを利用する。(chartkickはrails内で完結)
- gonとは:controller内でセットした変数をJavascript内で使う事ができるgem。他にもあると思いますが、今回はこちら使用
- テーブルやカラムの関係性については、下記データベース設計を参照。
データベース設計
gonとchartkick、chart.jsのインストール
- Gemfileに以下を追記して、bundle installを行う
- 上述の通り、JavaScriptとの連携が必要なので、gonというgemを利用してデータ渡しを行う。
gem 'gon'
gem 'chartkick'
-
yarn add chartkick chart.js
を行ってインストール -
application.js
でchart.js
とchartkick
を追加
app/javascript/packs/application.js
require("chartkick")
require("chart.js")
-
application.html
に以下記載。CDNに公開されているjsファイルを読み込む。- gonもここで設定するので、
include_gon
を記載しておく
- 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に質問したが、回答なし...
- Chartkick.jsで、最大値・最小値が正しく設定されない
- もし同じような現象になって、解決できた方がいたら教えてください!
詳細ページ(/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>