Node.jsを短期学習してみる #7 「チャット (ver.2)」

2015年3月1日

Nodejs 学習 特集

前回、チャットツールを作ってみましたが、デザイン要素が全くなかったので、少しUIにこだわったバージョンにアップデートしてみました。 Node.jsを短期学習してみる #3「チャット」

変更点

  1. チャットに入った場合と出た場合のユーザーの「入室」「退室」をアイコンにしてみた
  2. メッセージを、テキスト改行の形式から、LINEチャットみたいな見栄えに変更
  3. 自分と、他の人を見分けられるように色を変えてみた。
  4. 自分と、他の人の見分けを位置で左右にワケてみた。
  5. スマホで見た場合にviewportをセットして、操作しやすくする。

見た目で比べる

旧バージョン

新バージョン

見て分かっていただけると思うが、UIデザインを入れた場合と入れなかった場合は、印象も使い勝手も、格段に違ってくる。 最近は、「UI/UX」というジャンルで、デザイン性もシステムの重要な要素という分野になってきている。

ソースコード

/** * Lineのようなチャットシステム */ // 1.モジュールオブジェクトの初期化 var fs = require("fs"); var server = require("http").createServer(function(req, res) { res.writeHead(200, {"Content-Type":"text/html"}); var output = fs.readFileSync("./index.html", "utf-8"); res.end(output); }).listen(1080); var io = require("socket.io").listen(server); // ユーザ管理ハッシュ var userHash = {}; // 2.イベントの定義 io.sockets.on("connection", function (socket) { // 接続開始カスタムイベント(接続元ユーザを保存し、他ユーザへ通知) socket.on("connected", function (name) { userHash[socket.id] = name; for(var i in userHash){ io.sockets.emit("publish", {mode:"user-add",socket_id:i,name:userHash[i]}); } }); // メッセージ送信カスタムイベント socket.on("publish", function (data) { io.sockets.emit("publish", {mode:"message",socket_id:socket.id,name:data.name,value:data.value}); }); // 接続終了組み込みイベント(接続元ユーザを削除し、他ユーザへ通知) socket.on("disconnect", function () { if (userHash[socket.id]) { delete userHash[socket.id]; io.sockets.emit("publish", {mode:"user-del",socket_id:socket.id}); } }); }); console.log("Run ..."); <html> <head> <meta charset="UTF-8"> <title>Chat</title> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <style type="text/css"> html,body{ height:100%; margin:0; padding:0; } /*<<head*/ div.page-head{ position:fixed; width:100%; top:0; left:0; padding:0; margin:0; z-index:100; } div.page-head div.users{ text-align:center; background-color:#EEE; margin:0px; height:40px; padding:0px; line-height:40px; } div.page-head div.comment{ text-align:center; height:28px; padding:10px 0 10px 0; background-color:white; border-bottom:1px dotted #DDD; } div.page-head div.comment input[type="text"]{ width:200px; height:28px; border:1px solid #CCC; border-radius:0; -webkit-appearance: none; vertical-align:middle; margin:0; padding:4px; font-size:14px; } div.page-head div.comment button{ width:60px; height:28px; line-height:20px; border-radius:0; -webkit-appearance: none; border:1px solid #CCC; background-color:#CCC; color:white; font-weight:bold; margin:0; padding:4px; font-size:14px; vertical-align:middle; } /*head>>*/ /*<<user-icon*/ div.user , div.msg-user-other div.msg-user{ background-color:blue; width:32px; height:32px; line-height:32px; margin:2px 2px 0 0; padding:0; text-align:center; font-size:10px; color:white; border:0; border-radius:16px; display:inline-block; overflow:hidden; } div.user_my , div.msg-user-my div.msg-user{ background-color:orange; display:inline-block; vertical-align:top; } /*user-icon>>*/ /*<<message*/ #msg{ width:100%; max-width:480px; z-index:10; margin:100px auto 0 auto; } #msg div.msg-user-other{ vertical-align:top; margin:4px; position:relative; display:block; } #msg div.msg-user{ text-align:left; } #msg div.msg-user-my{ text-align:right; } #msg div.msg-value{ position:relative; max-width:220px; display:inline-block; margin:0 10px 10px 10px; padding:4px 20px; border-radius:8px; vertical-align:top; } #msg div.msg-user-other div.msg-value{ border:2px solid blue; background-image:linear-gradient(to bottom,white,#66F); } #msg div.msg-user-other div.msg-value:after{ content: ''; position: absolute; border-right: 10px solid blue; border-top: 5px solid transparent; border-bottom: 5px solid transparent; top: 10px; left: -12px; } #msg div.msg-user-my div.msg-value{ border:2px solid orange; background-image:linear-gradient(to bottom,white,orange); } #msg div.msg-user-my div.msg-value:after{ content: ''; position: absolute; border-left: 10px solid orange; border-top: 5px solid transparent; border-bottom: 5px solid transparent; top: 10px; right: -12px; } /*message>>*/ </style> </head> <body> <div class='page-head'> <div id="users" class='users'></div> <div class='comment'> <input type="text" id="msg_input" style="width:200px;" /><button onclick="publishMessage();">sent</button> </div> </div> <div id="msg"></div> <script type="text/javascript" src="/socket.io/socket.io.js"></script> <script type="text/javascript"> // 1.イベントとコールバックの定義 var socketio = io.connect('http://%server-address%:1080'); socketio.on("connected", function(name) {}); socketio.on("publish", function (data){ if(data.mode=="user-add"){ user_add(data.socket_id,data.name,data.people); } else if(data.mode=="user-del"){ user_del(data.socket_id); } else{ addMessage(data.socket_id,data.name,data.value); } }); socketio.on("disconnect", function () {}); // 2.イベントに絡ませる関数の定義 function start(name) { socketio.emit("connected", name); } function publishMessage() { var textInput = document.getElementById('msg_input'); var msg = textInput.value; socketio.emit("publish", {name:myName,value: msg}); textInput.value = ''; } function addMessage (socket_id,name,msg) { if(msg===""||msg==undefined){return} var domMeg = document.createElement('div'); var user_icon = "user"; //message-value var val = ""; if(socket_id == socketio.id){ domMeg.className = "msg-user-my"; user_icon += " user_my"; val += "<div class='msg-value'>"+ msg +"</div>"; val += "<div class='user user_my'>"+ name +"</div>"; } else{ domMeg.className = "msg-user-other"; val += "<div class='user'>"+ name +"</div>"; val += "<div class='msg-value'>"+ msg +"</div>"; } domMeg.innerHTML = val; msgArea.appendChild(domMeg); } function user_add (socket_id,name,people) { if(document.getElementById("user_id_"+socket_id)!=null){ return; } var users = document.getElementById("users"); if(users==null){return} //エレメント作成 var div = document.createElement("div"); if(socket_id == socketio.id){ div.className = "user user_my"; } else{ div.className = "user"; } div.id = "user_id_"+socket_id; div.innerHTML = name users.appendChild(div); } function user_del (socket_id) { var user = document.getElementById("user_id_"+socket_id); if(user!=null){ user.parentNode.removeChild(user); } } // 3.開始処理 var msgArea = document.getElementById("msg"); var myName = Math.floor(Math.random()*100)+1; start(myName); </script> </body> </html>

注意点

「%server-address%」の箇所はサーバーのIPアドレスかドメインで書き換えてください。

起動

# 通常起動 $ node chat.js # 永久起動 $ forever start chat.js # アクセスURL # http://%server-address%:1080/

実際に使ってみる

既にforeverで立ち上げっぱなしにしているので、興味のある人は試してもらいたい。 http://chat.ideacompo.com:1080/ ※すみません、現在停止してます。 ちなみに、このツールの為に、サブドメインと、リバースプロキシの設定を施して、自宅サーバーの裏に置いてあるraspberry-piで動かしている。 本当なら、同時に何人ぐらいでアクセスできるか試したいのだが、それは別の機会で行うことにしよう。

まだイケていないトコロ

入室した人を乱数でナンバリングして、それをそのまま名前にしているので、ログインという機能で、名前を入力できる機能をつけなければいけない。 できれば、twitterなどのOAuth認証で、アイコンを取得してくると、ユーザーが画像になって非常にUI的に良くなるイメージがある。 だんだんサービスみたいになってきたな・・・ 次回、そこを改修してFIXしたいと思う。