Railsアプリにいい感じのグラフを導入する

こんにちは。スバルです。

今回は、Railsアプリにいい感じのグラフを導入する方法を勉強します。

診断系のアプリで、結果画面にグラフが表示されてることって結構ありますよね。

図を表示

Image from Gyazo

あれ、僕もやってみたかったんです。この前作ったアプリに実装してみました。

開発環境

ruby 2.6.6 Rails 6.1.4

手順

railsにいい感じにグラフを入れるためには、chart.jsというコードを使用する必要があります。

Chart.js

手順に倣って導入していきましょう。

まずは<head>タグの中にCDNを用意します。

	# app/views/layout/application.html.erb

<script src="<https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.min.js>"></script>

グラフを表示したいviewにcanvas idを設置します

app/views/optimes/_result.html.erb
<div class ="chart_area">
    <canvas id="myChart"></canvas> 
  </div>

chart.js公式サイトにあるコードをコピーします。


<script>
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["赤", "青", "黄色", "緑", "紫", "橙"],
        datasets: [{
            label: '得票数',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});
</script>

上記のdata:部分を改良させることで、診断結果とグラフを対応させることが出来ます。

表示される診断結果項目にspanタグをつけ、それぞれにclassを設定します。

<ul>
            <li><p class="optime subtitle border-bottom" >睡眠時間</p><span class="optime__select"><%= optime.sleepy %></span>時間</li>
              <li class="mb-4 comment"><%= good_sleep(optime)%></li>

            <li><p class="optime subtitle border-bottom">勤務時間</p><span class="optime__select"><%=optime.work%></span>時間</li>
              <li class="mb-4 comment"><%= good_work(optime)%></li>
       
            <li><p class="optime subtitle border-bottom">食事時間</p><span class="optime__select"><%=optime.eat%></span>時間</li>
              <li class="mb-4 comment"><%= good_eat(optime)%></li>
       
            <li><p class="optime subtitle border-bottom">通勤時間</p><span class="optime__select"><%=optime.commute%></span>時間</li>
              <li class="mb-4 comment"><%= good_commute(optime)%></li>
       
            <li><p class="optime subtitle border-bottom">衛生管理時間</p><span class="optime__select"><%=optime.hygiene%></span>時間</li>
              <li class="mb-4 comment"><%= good_hygiene(optime)%></li>
        </ul>

そして、pタグに設定したoptimeクラスの配列一つ一つをDOM操作していきます。

 
<script>
																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																								 //ページ内の科目を取得
 var subject01 = document.querySelectorAll('.optime')[0].innerHTML,
        subject02 = document.querySelectorAll('.optime')[1].innerHTML,
        subject03 = document.querySelectorAll('.optime')[2].innerHTML,
        subject04 = document.querySelectorAll('.optime')[3].innerHTML,
        subject05 = document.querySelectorAll('.optime')[4].innerHTML,

        //ページ内の数値を取得
        subjectnum01 = document.querySelectorAll('.optime__select')[0].innerHTML,
        subjectnum02 = document.querySelectorAll('.optime__select')[1].innerHTML,
        subjectnum03 = document.querySelectorAll('.optime__select')[2].innerHTML,
        subjectnum04 = document.querySelectorAll('.optime__select')[3].innerHTML,
        subjectnum05 = document.querySelectorAll('.optime__select')[4].innerHTML;
    

dataを編集していきます。

        //取得した科目と数値をChart.jsに入れる
    var data = {
        labels: [subject01, subject02, subject03, subject04, subject05],
        datasets: [{
            label: '可処分時間項目',
            data: [subjectnum01, subjectnum02, subjectnum03, subjectnum04, subjectnum05],
            backgroundColor: ['rgb(248, 252, 8)','rgb(162, 226, 89)','rgb(253, 237, 15)','rgb(228, 230, 141)','rgb(89, 226, 203)'],
            borderColor: 'rgba(255,135,0,1)',
            pointBackgroundColor: 'rgba(255,135,0,1)',
            pointBorderColor: 'rgba(255,135,0,0)',
            pointBorderWidth: 0,
            pointRadius: 5,
            pointStyle: 'circle',
            pointHoverRadius: 5,
            pointHitRadius: 5
        }]
    };

varで設定したdataを、グラフ上のdataに紐づけます。

<script>
 //ページ内の科目を取得
  
var ctx = document.getElementById('myChart').getContext('2d');
var myChart   = new Chart(ctx, {
        type: 'doughnut',
        typetype        options: {
            title: {
                display: true,
                text: '固定時間内訳',
                padding: 4,
                fontSize: 20
            },
            legend: {
                text: '固定時間内訳',
                display: false,
                labels: {
                    fontColor: 'rgb(5, 99, 132)',
                    fontSize: 16
                }
            },
            scale: {
                pointLabels: {
                    fontSize: 15,
                    fontColor: 'rgb(0, 65, 112)',
                    padding: 20
                },
                ticks: {
                    beginAtZero: true,
                }
            },
            layout: {
                padding: {
                    left: 0,
                    right: 0,
                    top: 0,
                    bottom: 0
                }
            },
            maintainAspectRatio: false,
        }
    });
</script>

実際に出来上がったview

<div class ="chart_area mp-3">
    <canvas id="myChart" ></canvas> 
  </div>
    <div class="text-center wrapper mb-3 mt-4">
      <h2  class="text-center title" >固定時間削減方法</h2>
        <ul>
            <li><p class="optime subtitle border-bottom" >睡眠時間</p><span class="optime__select"><%= optime.sleepy %></span>時間</li>
              <li class="mb-4 comment"><%= good_sleep(optime)%></li>

            <li><p class="optime subtitle border-bottom ">勤務時間</p><span class="optime__select"><%=optime.work%></span>時間</li>
              <li class="mb-4 comment"><%= good_work(optime)%></li>
       
            <li><p class="optime subtitle border-bottom">食事時間</p><span class="optime__select"><%=optime.eat%></span>時間</li>
              <li class="mb-4 comment"><%= good_eat(optime)%></li>
       
            <li><p class="optime subtitle border-bottom">通勤時間</p><span class="optime__select"><%=optime.commute%></span>時間</li>
              <li class="mb-4 comment"><%= good_commute(optime)%></li>
       
            <li><p class="optime subtitle border-bottom">衛生管理時間</p><span class="optime__select"><%=optime.hygiene%></span>時間</li>
              <li class="mb-4 comment"><%= good_hygiene(optime)%></li>
        </ul>
    </div>
</div>

 //ページ内の科目を取得
    var subject01 = document.querySelectorAll('.optime')[0].innerHTML,
        subject02 = document.querySelectorAll('.optime')[1].innerHTML,
        subject03 = document.querySelectorAll('.optime')[2].innerHTML,
        subject04 = document.querySelectorAll('.optime')[3].innerHTML,
        subject05 = document.querySelectorAll('.optime')[4].innerHTML,

        //ページ内の数値を取得
        subjectnum01 = document.querySelectorAll('.optime__select')[0].innerHTML,
        subjectnum02 = document.querySelectorAll('.optime__select')[1].innerHTML,
        subjectnum03 = document.querySelectorAll('.optime__select')[2].innerHTML,
        subjectnum04 = document.querySelectorAll('.optime__select')[3].innerHTML,
        subjectnum05 = document.querySelectorAll('.optime__select')[4].innerHTML;
            //取得した科目と数値をChart.jsに入れる
    var data = {
        labels: [subject01, subject02, subject03, subject04, subject05],
        datasets: [{
            label: '可処分時間項目',
            data: [subjectnum01, subjectnum02, subjectnum03, subjectnum04, subjectnum05],
            backgroundColor: ['rgb(248, 252, 8)','rgb(162, 226, 89)','rgb(253, 237, 15)','rgb(228, 230, 141)','rgb(89, 226, 203)'],
            borderColor: 'rgba(255,135,0,1)',
            pointBackgroundColor: 'rgba(255,135,0,1)',
            pointBorderColor: 'rgba(255,135,0,0)',
            pointBorderWidth: 0,
            pointRadius: 5,
            pointStyle: 'circle',
            pointHoverRadius: 5,
            pointHitRadius: 5
        }]
    };
var ctx = document.getElementById('myChart').getContext('2d');
var myChart   = new Chart(ctx, {
        type: 'doughnut',
        data: data,
        options: {
            title: {
                display: true,
                text: '固定時間内訳',
                padding: 4,
                fontSize: 20
            },
            legend: {
                text: '固定時間内訳',
                display: false,
                labels: {
                    fontColor: 'rgb(5, 99, 132)',
                    fontSize: 16
                }
            },
            scale: {
                pointLabels: {
                    fontSize: 15,
                    fontColor: 'rgb(0, 65, 112)',
                    padding: 20
                },
                ticks: {
                    beginAtZero: true,
                }
            },
            layout: {
                padding: {
                    left: 0,
                    right: 0,
                    top: 0,
                    bottom: 0
                }
            },
            maintainAspectRatio: false,
        }
    });

それでは、試してみましょう。

Image from Gyazo

グインって感じでグラフが実装できましたね。

ちなみに、 type: 'doughnut',の部分を変えるだけで様々なグラフに変化させることができます。

type: 'radar'

Image from Gyazo

type: 'pie'

Image from Gyazo

type: 'bar'

Image from Gyazo