LoginSignup
7
6

More than 3 years have passed since last update.

node.js + socket.io + chart.js でアンケート結果の簡易グラフ描画を作成

Last updated at Posted at 2019-01-06

はじめに

heroku + electron でニコニコメソッドを作ってみました。でスタンプ入力をすると相手の画面にスタンプが表示されるアプリを作ってみたので、そのスタンプ入力回数を集計して棒グラフで表示できる機能を chart.js にてつくってみました。
chart1.png

モックアップ

モックアップ : https://nico-chat.herokuapp.com/mock-up/chart/CD
入力画面と描画画面を分けたい人はブラウザを2つ立ち上げて(一つのPCでもいいし、入力はスマホ、描画はPCでもOk)
入力 : https://nico-chat.herokuapp.com/mock-up/chart/C
描画 : https://nico-chat.herokuapp.com/mock-up/chart/D
A~Dのボタンを押すとスタンプ描画画面にスタンプが表示され、グラフがカウントアップしていきます。
Resetボタンを押すとカウントクリアになります。

ソースコード

https://github.com/UC-SADA/socket-chart
にアップしました。

使い方

githubからダウンロード後

$ node index.js

実行(足りていない、モジュールがあったら npm install でインストールしてください。)

あとは、localhost:2525/controller にアクセスしてスタンプを押して

localhost:2525/chart にグラフが描画されればOK

localhost:2525/display にはスタンプが表示されているはず。

実装内容

メインファイル

index.js

"use strict";
const path = require('path');
const express = require('express');
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const extend = require('util')._extend

http.listen(process.env.PORT || 2525, function(){
  console.log("PORT : " + process.env.PORT || 2525);
});

//選択肢
var a = 0
var b = 0
var c = 0
var d = 0

//入力側画面
app.use("/controller",express.static(path.join(__dirname, 'public')))

//コメント/スタンプ出力側画面
app.get("/display", function(req, res){
  res.sendFile(__dirname + '/index_nico-Display.html');
});
//グラフ出力側画面
app.get("/chart", function(req, res){
  res.sendFile(__dirname + '/index_chart.html');
});
//ソケット通信のアクション内容
app.get('/like', function (req, res) {
  const msg = extend({}, req.query);
  console.log(JSON.stringify(msg));
  switch ( JSON.stringify(msg) )
{
    case '{"image":"A"}' : a++;
     break;
    case '{"image":"B"}' : b++;
     break;
    case '{"image":"C"}' : c++;
     break;
    case '{"image":"D"}' : d++;
     break;
    case '{"image":"Reset"}' : a=b=c=d=0;
     break;
    default:
     console.log("etc")
     break;
}
  var stamp_cnt = [[a],[b],[c],[d]]
  io.emit('like', msg)
  io.emit('chart', stamp_cnt)
  console.log(stamp_cnt)
  res.end()
})

入力画面

index.html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Nico-Choice</title>
  <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
  <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <script src='https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js'></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
  <script type="text/javascript" src="JS/niconico.js"></script>
  <script type="text/javascript" src="JS/chartDraw.js"></script>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      FastClick.attach(document.body);
      }, false);

    function handleSubmit (form) {
      const action = $(form).attr('action')
      const params = $(form).serialize()
      const url = `${action}?${params}`
      $.get(url)
        .fail(function () {
          alert('failed to send message.')
        });
    }

    function like (type) {
      const url = `/like?image=${type}`
      $.get(url)
        .fail(function () {
          alert('failed to like.')
        })
    }
  </script>
</head>

<body>
  <div class="container">
    <form class="form-horizontal" style="margin: 16px" role="form" action="/like" method="get" onsubmit="handleSubmit(this); return false;">
      <div class="form-group">
        <label class="control-label col-sm-2">選択肢</label>
        <div class="input-group">
          <button class="btn btn-default" type="button" onclick="like('A')">
            <i></i> A
          </button>
           
          <button class="btn btn-default" type="button" onclick="like('B')">
            <i></i> B
          </button>
           
          <button class="btn btn-default" type="button" onclick="like('C')">
            <i></i> C
          </button>
           
          <button class="btn btn-default" type="button" onclick="like('D')">
            <i></i> D
          </button>
   
          <button class="btn btn-default" type="button" onclick="like('Reset')">
            <i></i> Reset
          </button>
        </div>
      </div>
    </form>
  </div>
</body>
</html>

グラフ描画画面

index_chart.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Nico-Chart</title>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js'></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
  <script type="text/javascript" src="../controller/JS/chartDraw.js"></script>

</head>
<body>
  <canvas id="myChart_1"></canvas>
  <script>
    var bar_list = [[0],[0],[0],[0]];
    var socket = io();
    socket.on('chart', function(cnt){
      bar_List = cnt;
      chartDraw("myChart_1") ;
      console.log("chartDraw");
    });
  </script>
</body>
</html>

グラフ描画のJS

chartDraw.js
function chartDraw(mychart){
      myChart_1 = new Chart(document.getElementById(mychart), {
        type: "bar",
        data: {
          labels: ["アンケート結果"],
          datasets: [
            { label: "A", data: bar_List[0], backgroundColor: "rgba(244, 143, 177, 0.6)" },
            { label: "B", data: bar_List[1], backgroundColor: "rgba(255, 235, 59, 0.6)" },
            { label: "C", data: bar_List[2], backgroundColor: "rgba(100, 181, 246, 0.6)" },
            { label: "D", data: bar_List[3], backgroundColor: "rgba(50, 81, 246, 0.6)" }
          ]
        },
options: {
animation : false,
  scales: {
    yAxes: [{
      ticks: {
        suggestedMax: 100,
        suggestedMin: 0,
        stepSize: 10,
             }
           }]
          }
}})}

最後に

現状のソースでは、一人が何回も投票できる仕組みになっているので、投票回数を制限できる仕組みも作ってみたいと思います。

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