1. west2538

    Posted

    west2538
Changes in title
+【Rails】個人開発のアプリにGitHub風のチャートを実装
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,118 @@
+個人開発のWebアプリ**「[まちかどルート](https://machiroute.herokuapp.com/)」v6.2**に、名づけて**《アクティビティ・チャート》**なるものを実装したときのメモです。
+
+<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E3%81%BE%E3%81%A1%E3%81%8B%E3%81%A9%E3%83%AB%E3%83%BC%E3%83%88?src=hash&amp;ref_src=twsrc%5Etfw">#まちかどルート</a> v6.2 リリース<a href="https://t.co/JaIlGWYGmA">https://t.co/JaIlGWYGmA</a><br><br>冒険者のステータスに 「アクティビティ・チャート」 を追加!投稿やクリアといった活動(アクティビティ)が多いほどチャートにたくさん草が生えます <a href="https://t.co/EZOYgTFs4H">pic.twitter.com/EZOYgTFs4H</a></p>&mdash; 西村 治久(ハル) (@west2538) <a href="https://twitter.com/west2538/status/1140637497979838464?ref_src=twsrc%5Etfw">June 17, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
+
+# 参考記事
+
+こちらの記事を参考にさせていただきました。
+ありがとうございます!
+
+**Railsアプリで Cal-Heatmap を表示してみる**
+https://qiita.com/volpe28v/items/3a5a2c05f1c0ee3fa5ad
+
+以下、じぶんなりのアレンジも含めてメモとして残します。
+
+# view
+
+```erb:\app\views\layouts\application.html.erb
+<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](https://d3js.org/)」と「[Cal-heatmap](https://cal-heatmap.com/)」を読み込ませています。
+
+```erb:\app\views\users\show.html.erb
+<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>
+```
+[公式のドキュメント](https://cal-heatmap.com/)を参考にしながら`cal.init({ })`内の各種オプションを指定しています。また、前述の参考記事と違うのは、とくに`data`の部分です。下記のAPIに渡すパラメーターの`start`と`stop`に`Time.now`メソッドを使うことで、APIから取得するJSONデータの期間(ここでは6か月分)を指定しています。
+
+# API
+
+```ruby:\app\api\resources\v1\comments.rb
+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](https://github.com/ruby-grape/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
+ User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
+ ↳ app/api/resources/v1/comments.rb:12
+ Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."post_uid" = ? AND "posts"."created_at" BETWEEN ? AND ? [["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
+ Comment Load (0.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_uid" = ? AND "comments"."created_at" BETWEEN ? AND ? [["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
+ User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
+ ↳ app/api/resources/v1/comments.rb:12
+ Post Load (0.7ms) SELECT "posts".* FROM "posts" WHERE "posts"."post_uid" = ? AND "posts"."created_at" BETWEEN ? AND ? [["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
+ Comment Load (0.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_uid" = ? AND "comments"."created_at" BETWEEN ? AND ? [["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`を追記したり、いろいろ試したのですが解決できていません。
+
+まだまだ未熟です...。
+これからも精進していきたいと思います。
+