WebSocket/Canvas Drawing
Canvas Drawing with WebSocket
Soul-Learner
2015. 10. 2. 11:09
웹소켓을 이용한 원격 캔바스에 그림 그리기 예제
개요
로그인한 특정 이용자의 리스트 중에서 선택된 한 이용자의 캔바스에 마우스 드래그로 그림을 그려 보일 수 있는 웹소켓 예제이다
테스트 환경
Windows 7, JDK 8, JSP, Tomcat 8, HTML 5, jQuery 2
loginForm.jsp
<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>로그인</title> </head> <body> <p> <form action="loginProc.jsp" method="post"> I D <input type="text" name="id" value="user01"> PWD <input type="password" name="pwd" value="1111"> <button type="submit">로그인</button> </form> </body> </html>
loginProc.jsp
<%@page import="java.util.*"%> <%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% request.setCharacterEncoding("utf-8"); String id = request.getParameter("id"); String pwd = request.getParameter("pwd"); if(id!=null && !id.equals("")) { session.setAttribute("id", id); } %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> 로그인 결과 </title> </head> <body> <p> <a href="canvas_network.jsp">네트웍 그리기</a> </body> </html>
canvas_network.jsp
<%@page import="java.util.*"%> <%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% Object objList = application.getAttribute("usrList"); List<String> usrList = null; if(objList!=null) usrList = (List<String>) objList; %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>네트워크 캔바스 예제</title> <script type="text/javascript" src="jquery-2.1.4.min.js"></script> <style type="text/css"> body { margin:0px 0px; text-align: center; } canvas { display:inline-block; border: 1px solid black; } </style> <script type="text/javascript"> var clientId = '<%=(String) session.getAttribute("id")%>'; var Chat = {}; Chat.socket = null; // connect() 함수 정의 Chat.connect = (function(host) { // 서버에 접속시도 if ('WebSocket' in window) { Chat.socket = new WebSocket(host); } else if ('MozWebSocket' in window) { Chat.socket = new MozWebSocket(host); } else { Console.log('Error: WebSocket is not supported by this browser.'); return; } // 서버에 접속이 되면 호출되는 콜백함수 Chat.socket.onopen = function () { console.log('Info: WebSocket connection opened.'); }; // 연결이 끊어진 경우에 호출되는 콜백함수 Chat.socket.onclose = function () { console.log('Info: WebSocket closed.'); }; // 서버로부터 메시지를 받은 경우에 호출되는 콜백함수 Chat.socket.onmessage = function (message) { var jsonObj = eval('('+message.data+')'); if('clear' in jsonObj) { clearCanvas(); } else if('content' in jsonObj) { var jsonLine = jsonObj.content; drawLine(jsonLine); } }; }); // connect() 함수 정의 끝 // 위에서 정의한 connect() 함수를 호출하여 접속을 시도함 Chat.initialize = function() { if (window.location.protocol == 'http:') { //Chat.connect('ws://' + window.location.host + '/websocket/chat'); Chat.connect('ws://192.168.8.32:8888/MyWeb/websocket/chat'); } else { Chat.connect('wss://' + window.location.host + '/websocket/chat'); } }; // 서버로 메시지를 전송하고 입력창에서 메시지를 제거함 Chat.sendMessage = (function(jsonObj) { if (jsonObj != null) { Chat.socket.send(JSON.stringify(jsonObj)); } }); </script> <script type="text/javascript"> var cnt = 0; var ctx = null; var x1=y1=x2=y2=0; var isDrag = false; var ptArr = new Array(); var timer = null; var jsonStr = ''; $(function(){ var $canvas = $('canvas').eq(0); ctx = $canvas[0].getContext("2d"); $canvas.on('mousedown', function(evt){ x1 = evt.pageX - this.offsetLeft; y1 = evt.pageY - this.offsetTop; isDrag = true; }); $canvas.on('mouseup', function(evt){ isDrag = false; }); $canvas.on('mousemove', function(evt){ if(isDrag) { x2 = evt.pageX-this.offsetLeft; y2 = evt.pageY-this.offsetTop; var receiver = $('select[name=receiver]').val(); var msg = {sender:clientId, receiver:receiver}; msg.content = {x1:x1, y1:y1, x2:x2, y2:y2}; Chat.sendMessage(msg); x1 = x2; y1 = y2; } }); $('#btnClear').eq(0).on('click',function(){ var receiver = $('select[name=receiver]').val(); Chat.sendMessage({sender:clientId, receiver:receiver, clear:true}); }); Chat.initialize(); }); function drawLine(jsonLine) { ctx.strokeStyle = "#ff5533"; ctx.lineJoin = "round"; ctx.lineWidth = 5; ctx.beginPath(); ctx.moveTo(jsonLine.x1, jsonLine.y1); ctx.lineTo(jsonLine.x2, jsonLine.y2); ctx.closePath(); ctx.stroke(); } function clearCanvas() { ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); } </script> </head> <body> 대화상대 선택<select id="receiver" name="receiver"> <% if(usrList!=null) { for(int i=0;i<usrList.size();i++) { %> <option><%=usrList.get(i)%></option> <% } } %> </select><br> <canvas width="600" height="480"></canvas> <button type="button" id='btnClear' style="vertical-align: top;">캔바스 지우기</button> </body> </html>
ServletAwareConfig.java
package org.kdea.web.socket; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.websocket.HandshakeResponse; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpointConfig; public class ServletAwareConfig extends ServerEndpointConfig.Configurator { @Override public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { HttpSession session = (HttpSession) request.getHttpSession(); //ServletContext ctx = session.getServletContext(); config.getUserProperties().put(HttpSession.class.getName(), session); //config.getUserProperties().put(ServletContext.class.getName(), ctx); } }
ChatAnnotation.java
package org.kdea.web.socket; import java.io.IOException; import java.util.*; import javax.servlet.http.HttpSession; import javax.websocket.EndpointConfig; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.json.simple.*; import org.json.simple.parser.*; @ServerEndpoint(value = "/websocket/chat", configurator=ServletAwareConfig.class) //클라이언트가 접속할 때 사용될 URI public class ChatAnnotation { private static Map<String, Session> sessionMap = new HashMap<>(); private HttpSession httpSession; public ChatAnnotation() { } @OnOpen public void start(Session session, EndpointConfig config) { this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName()); String userId = (String)httpSession.getAttribute("id"); System.out.println("접속한 클라이언트 ID:"+userId); sessionMap.put(userId, session); Object objList = httpSession.getServletContext().getAttribute("usrList"); if(objList==null) { List<String> usrList = new ArrayList<>(); httpSession.getServletContext().setAttribute("usrList", usrList); objList = usrList; } List<String> usrList = (List<String>) objList; usrList.add(userId); } @OnClose public void end() { String usrId = (String)httpSession.getAttribute("id"); sessionMap.remove(usrId); Object objList = httpSession.getServletContext().getAttribute("usrList"); List<String> usrList = (List<String>) objList; usrList.remove(usrId); } // 현재 세션과 연결된 클라이언트로부터 메시지가 도착할 때마다 새로운 쓰레드가 실행되어 incoming()을 호출함 @OnMessage public void incoming(String message) { if(message==null || message.trim().equals("")) return; JSONParser jsonParser = new JSONParser(); try { JSONObject jsonObj = (JSONObject)jsonParser.parse(message); String sender = (String)jsonObj.get("sender"); String receiver = (String)jsonObj.get("receiver"); try { sessionMap.get(receiver).getBasicRemote().sendText(message); sessionMap.get(sender).getBasicRemote().sendText(message); return; } catch (IOException e) { e.printStackTrace(); } } catch (ParseException e) { e.printStackTrace(); } } @OnError public void onError(Throwable t) throws Throwable { System.err.println("Chat Error: " + t.toString()); } }