ブラック研究室へようこそ!

ブラック研究室。それは大学院生が放り込まれるかもしれない闇のアジト。在籍時代のエピソード・Web/アプリ開発の備忘録など。

【IT備忘録】リアルタイムお絵かきシステムを作ってみた③ 〜Githubで公開しました〜

 

www.blacklab-blog.net

 

前回、Node.js・Socket.IOをインストールし、Nginxとの連携設定をしました。

これで、導入はOKです。

 

以下のような構図ができあがりましたね。

f:id:blackLab:20180620112530p:plain

 

ソースコード公開

以下、リアルタイムお絵かきシステムのソースコードをGithubで公開します!

github.com

 

  • index.php

   スマホ向けのTOPページです。ここで1〜4の回答番号を選びます。

   ※回答番号とは、以下の投影画面で1〜4のどの四角いBOXに絵を書くか、のことです。

f:id:blackLab:20180531214347j:plain

 

  • client.php

   スマホ向けの絵を書くページ。回答番号を選ぶとこのページに飛びます。

  • monitor.php

   PC向けの投影画面です。

  • server.js

   Node.jsのサーバプログラムです。

   これは、前回記載した『任意の作業用ディレクトリ』に移して起動してください。

   ※Socket.IOのライブラリをインストールしたディレクトリに入れて起動する必要があります。

 

テクニック紹介

Socket.IOは便利ですよ。このお絵描きシステムで使っているテクニックを少し紹介します。

 

基本ルール

基本的に、以下の構図が成り立つと思われます。

これを意識しましょう。

クライアントAサーバクライアントB

 

また、当たり前の話ですが、Socket.IOでのやりとりはNode.jsを使っているので全てJavascriptで完結します。

前回同様、以下のSocet.IOのライブラリをクライアント側のページに読み込ませておきます。

<script src="/socket.io/socket.io.js" type="text/javascript"></script>

 

クライアントAサーバへの情報送信

例として、変数dataを、サーバ側がリッスンしている『ClientAtoServer』という関数へ送信します。emitで送信です。

dataの中身は数値でも、配列でもある程度何でも渡せます。dataを引数として持たなくてもいいです。ゆるいですね。 

//クライアントA側
var socket = io();
socket.emit('ClientAtoServer', data);

 

サーバクライアントBへ情報中継

サーバ側で、『ClientAtoServer』という関数をリッスンさせることで、クライアントAからの情報(data)を受け取ります。onでリッスンです。

そして、クライアントB側でリッスンしている『ServerToClientB』という関数へ情報(data)を橋渡ししてやります。

// サーバ側
socket.on('ClientAtoServer', function (data) {
      // dataをクライアントBへ中継する
      socket.emit('ServerToClientB', data);
});

 

クライアントBで情報受け取り

先程と同様に、クライアントB側で『ServerToClientB』という関数をリッスンします。

これで、橋渡しされてきた情報(data)がクライアントBで受け取ることができますね。

// クライアントB側
socket.on('ServerToClientB', function (data) {
        // ・・・
        // dataをガチャガチャする
        // ・・・
});

 

ルームの概念

「このルームに入っている人のみに情報を送りたい」ということが可能です。

■入室

まず、回答番号1番に書くよ、ということで、client.phpからサーバーへその番号を送って入室します。  ※team_num=1とします。

// client.php
socket.emit('sendTeamNumToServer', team_num);

 

 ■ルームへ配置

サーバー側は、 その番号を受け取り、このクライアントを「team1」というルームにjoinさせます。

// server.js
  socket.on('sendTeamNumToServer', function (num) {
        if(num==0){
        	//モニター
        	socket.join("monitor");
        }else if(num>0){
        	//クライアント(今回ここ)
        	socket.join("team"+num);
        }
    });

 

■ルームを絞った情報送信

そして、サーバから以下のようなコードを書いてやると、「team1」宛にのみ情報を送ることができます。

※broadcast.to("ルーム名")により、送り先ルームを指定しています。

socket.broadcast.to("team1").emit('forTeam1Function', data);

 

■情報受け取り 

 「team1」に入室しているクライアント側で、上記に沿って『forTeam1Function』をリッスンさせていれば、dataを受け取ることができます。

socket.on('forTeam1Function', function (data) {
        // ・・・
        // dataをガチャガチャする
        // ・・・
});

 慣れてくると、結構簡単です!

 

絵が書かれるときの構造

これらを応用して、スマホから絵が書かれたら投影画面に反映する、ということをやっているのですが、

線を描画するときのイベントが少し複雑になってしまっているので解説します。

 

反映の精度を高めるため、以下の1〜3のステップでイベントを分けています。

これによって、線の太さや色、座標をバグることなく、投影画面に反映させることができています。

※詳細は、Github上のコードを参照くださいませ。

 

■1.線の描き始め(指がスマホに触れた時)

スマホ →①→ サーバ →②→ 投影画面

①:関数名「sendDrawDownToServer」

②:関数名「sendEachDrawDownToClient」

 

■2.線を引っ張っている最中(指がスマホ上で動いている時)

スマホ →①→ サーバ →②→ 投影画面

①:関数名「sendDrawToServer」

②:関数名「sendEachDrawToClient」

 

■3.線の描き終わり(指がスマホを離れた時)

スマホ →①→ サーバ →②→ 投影画面

①:関数名「sendDrawUpToServer」

②:関数名「sendEachDrawUpToClient」

 

 

参考までに!!

ではまた!!