個人開発のWebアプリ**「まちかどルート」v6.2に、名づけて《アクティビティ・チャート》**なるものを実装したときのメモです。
#まちかどルート v6.2 リリースhttps://t.co/JaIlGWYGmA
— 西村 治久(ハル) (@west2538) June 17, 2019
冒険者のステータスに 「アクティビティ・チャート」 を追加!投稿やクリアといった活動(アクティビティ)が多いほどチャートにたくさん草が生えます pic.twitter.com/EZOYgTFs4H
参考記事
こちらの記事を参考にさせていただきました。
ありがとうございます!
Railsアプリで Cal-Heatmap を表示してみる
https://qiita.com/volpe28v/items/3a5a2c05f1c0ee3fa5ad
以下、じぶんなりのアレンジも含めてメモとして残します。
view
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cal-heatmap/3.6.2/cal-heatmap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cal-heatmap/3.6.2/cal-heatmap.css" />
レイアウトテンプレートのapplication.html.erb
にこの3行を書き加えることで、今回必要なライブラリ「D3.js」と「Cal-heatmap」を読み込ませています。
<div id="heatmap"></div>
<script>
var startDate = new Date();
startDate.setMonth(startDate.getMonth() - 5);
var parser = function(data) {
return eval("(" + data + ")");
};
var cal = new CalHeatMap();
cal.init({
itemSelector: "#heatmap",
data: "/api/v1/comments?user_id=<%= @user.id %>&start=<%= Time.now.ago(6.months) %>&stop=<%= Time.now %>",
afterLoadData: parser,
cellSize: 5,
domain: "month",
subDomain: "day",
range: 6,
tooltip: false,
start: startDate,
domainLabelFormat: "%b",
legend: [1,2,3,4],
weekStartOnMonday: false,
legendVerticalPosition: "center",
legendOrientation: "vertical"
});
</script>
公式のドキュメントを参考にしながらcal.init({ })
内の各種オプションを指定しています。また、前述の参考記事と違うのは、とくにdata
の部分です。下記のAPIに渡すパラメーターのstart
とstop
にTime.now
メソッドを使うことで、APIから取得するJSONデータの期間(ここでは6か月分)を指定しています。
API
module Resources
module V1
class Comments < Grape::API
resources :comments do
# /api/v1/comments
desc 'アクティビティ・チャートJSON出力'
params do
requires :user_id, type: Integer, desc: 'ユーザーID'
end
get do
user = User.find(params[:user_id])
from = params[:start]
to = params[:stop]
comments1 = Post.where(post_uid: user.uid, created_at: from..to)
comments2 = Comment.where(user_uid: user.uid, created_at: from..to)
comments1 = comments1.to_a
comments2 = comments2.to_a
comments = comments1 + comments2
comments.map{|c| c.created_at.to_i}.inject(Hash.new(0)){|h, tm| h[tm] += 1; h}.to_json
end
end
end
end
end
わたしのアプリでも、ちょうど参考記事と同じくGrapeを使ってAPIを構築しています。
参考記事と違うのはPost
とComment
というふたつのテーブルにある投稿日時のカラムcreated_at
を抽出&結合し、アクティビティ・チャートに反映させている点です。
課題
参考記事にも書かれていますが**「rails から json で返したデータをパースするメソッドを定義して afterLoadData に設定する(eval しないと json として読み込めなかったので)」**とのこと。
確かにこれをしないとチャートが表示されません。
しかしながら、このせいか、ログを見るといちどに2回、APIを叩いています。
Started GET "/api/v1/comments?user_id=1&start=2018-12-18%2009:57:23%20+0900&stop=2019-06-18%2009:57:23%20+0900" for 192.168.14.1 at 2019-06-18 09:57:23 +0900
[1m[36mUser Load (0.1ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?[0m [["id", 1], ["LIMIT", 1]]
↳ app/api/resources/v1/comments.rb:12
[1m[36mPost Load (0.2ms)[0m [1m[34mSELECT "posts".* FROM "posts" WHERE "posts"."post_uid" = ? AND "posts"."created_at" BETWEEN ? AND ?[0m [["post_uid", "townsguild@another-guild.com"], ["created_at", "2018-12-18 09:57:23"], ["created_at", "2019-06-18 09:57:23"]]
↳ app/api/resources/v1/comments.rb:18
[1m[36mComment Load (0.1ms)[0m [1m[34mSELECT "comments".* FROM "comments" WHERE "comments"."user_uid" = ? AND "comments"."created_at" BETWEEN ? AND ?[0m [["user_uid", "townsguild@another-guild.com"], ["created_at", "2018-12-18 09:57:23"], ["created_at", "2019-06-18 09:57:23"]]
↳ app/api/resources/v1/comments.rb:19
Started GET "/api/v1/comments?user_id=1&start=2018-12-18%2009:57:23%20+0900&stop=2019-06-18%2009:57:23%20+0900" for 192.168.14.1 at 2019-06-18 09:57:23 +0900
[1m[36mUser Load (0.2ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?[0m [["id", 1], ["LIMIT", 1]]
↳ app/api/resources/v1/comments.rb:12
[1m[36mPost Load (0.7ms)[0m [1m[34mSELECT "posts".* FROM "posts" WHERE "posts"."post_uid" = ? AND "posts"."created_at" BETWEEN ? AND ?[0m [["post_uid", "townsguild@another-guild.com"], ["created_at", "2018-12-18 09:57:23"], ["created_at", "2019-06-18 09:57:23"]]
↳ app/api/resources/v1/comments.rb:18
[1m[36mComment Load (0.6ms)[0m [1m[34mSELECT "comments".* FROM "comments" WHERE "comments"."user_uid" = ? AND "comments"."created_at" BETWEEN ? AND ?[0m [["user_uid", "townsguild@another-guild.com"], ["created_at", "2018-12-18 09:57:23"], ["created_at", "2019-06-18 09:57:23"]]
↳ app/api/resources/v1/comments.rb:19
なんとかして1回で済むようにviewの<script>
にdata-turbolinks-eval=false
を追記したり、いろいろ試したのですが解決できていません。
まだまだ未熟です...。
これからも精進していきたいと思います。