LoginSignup
6
4

More than 3 years have passed since last update.

【Rails】個人開発のアプリにGitHub風のチャートを実装

Posted at

個人開発のWebアプリまちかどルート」v6.2に、名づけて《アクティビティ・チャート》なるものを実装したときのメモです。

参考記事

こちらの記事を参考にさせていただきました。
ありがとうございます!

Railsアプリで Cal-Heatmap を表示してみる
https://qiita.com/volpe28v/items/3a5a2c05f1c0ee3fa5ad

以下、じぶんなりのアレンジも含めてメモとして残します。

view

\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」と「Cal-heatmap」を読み込ませています。

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

公式のドキュメントを参考にしながらcal.init({ })内の各種オプションを指定しています。また、前述の参考記事と違うのは、とくにdataの部分です。下記のAPIに渡すパラメーターのstartstopTime.nowメソッドを使うことで、APIから取得するJSONデータの期間(ここでは6か月分)を指定しています。

API

\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を使ってAPIを構築しています。

参考記事と違うのはPostCommentというふたつのテーブルにある投稿日時のカラム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を追記したり、いろいろ試したのですが解決できていません。

まだまだ未熟です...。
これからも精進していきたいと思います。

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