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したいと思う。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。