{"id":14,"date":"2013-08-04T03:40:11","date_gmt":"2013-08-04T03:40:11","guid":{"rendered":"http:\/\/mypocket-technologies.com\/?p=457"},"modified":"2013-08-04T03:40:11","modified_gmt":"2013-08-04T03:40:11","slug":"collaborative-drawing-application-using-socket-io-node-js-and-canvas","status":"publish","type":"post","link":"https:\/\/bitcows.com\/?p=14","title":{"rendered":"Collaborative drawing application using socket.io, node.js and canvas"},"content":{"rendered":"<p>In my day job i do all kinds of different projects. Recently, I was tasked to do a collaborative drawing application using HTML5 canvas. Now, I&#8217;m sure there are any number of ways to do this, but I decided the fastest and easiest way was to use node.js and socket.io. After looking around I didn&#8217;t see a lot of articles on how do this, so I figured I would write my own.<br \/>\n<em>DISCLAIMER:  This is not a comprehensive tutorial on socket.io, or node.js. This is only for demonstration purposes of how to communicate between two browsers using canvas.  Just because I did my code this way doesn&#8217;t mean you have to. There are a lot of different ways to write javascript.<\/em><\/p>\n<p><strong>Assumptions:<\/strong><\/p>\n<ul>\n<li>Basic understanding of HTML5, CSS and <a href=\"http:\/\/jquery.com\/\" target=\"_new\" rel=\"noopener\">jQuery<\/a><\/li>\n<li>Know a tad about <a href=\"http:\/\/getbootstrap.com\/2.3.2\/\" target=\"_new\" rel=\"noopener\">bootstrap<\/a>.<\/li>\n<li>Working with the Canvas element would be helpful.<\/li>\n<li>Working knowledge of <a href=\"http:\/\/nodejs.org\/\" target=\"_new\" rel=\"noopener\">node.js<\/a> and <a href=\"http:\/\/socket.io\" target=\"_new\" rel=\"noopener\">socket.io<\/a><\/li>\n<li>Browsers that support the canvas element.<\/li>\n<li>Basic command line and terminal knowledge (i.e. cd, ls)<\/li>\n<\/ul>\n<p>Ok so lets get started. I&#8217;m not going to go into all the details on how to install node.js its really quite easy and the <a href=\"http:\/\/nodejs.org\/download\/\" target=\"_new\" rel=\"noopener\">documentation on the site<\/a> is very good. I will touch on how to set up the socket.io piece however.<\/p>\n<p>Once you have node.js install you will need to install the socket.io module<br \/>\nOpen a terminal and type <strong><code>npm install socket.io<\/code><\/strong> in it. This should get the socket.io modules onto your system.<br \/>\nMine installed here <strong>\/Users\/darren\/node_modules\/socket.io<\/strong> (note I&#8217;m on a mac)<br \/>\nThat&#8217;s pretty much it for the install. Next you will need to write the code to launch the server and get this drawing application running.<\/p>\n<p>Lets write a basic socket server file. Create a new file called <em><strong>server.js<\/strong><\/em> and put the following:<\/p>\n<pre class=\"prettyprint\">\nio = require('socket.io').listen(4000)\n    console.log(\"It worked\");\nio.sockets.on('connection', function (socket) {}); \n<\/pre>\n<p>Depending on your set up you can put this file in a number of places. I found just putting it in the same folder as my socket.io folder  <strong>\/Users\/darren\/node_modules\/<\/strong> worked just fine. <\/p>\n<p>Once you have done this save the file and go back to the termial change directory <strong><code>cd [Folder path with server.js file in it]<\/code><\/strong>. Once you are in the directory type <strong><code>node server.js<\/code><\/strong> you sould see something like this:<\/p>\n<div class=\"terminal\">\n<pre class=\"prettyprint\">darren$ node server.js\ninfo  - socket.io started\nIt worked<\/pre>\n<\/div>\n<p>Now open a new browser window and type <strong>http:\/\/localhost:4000\/<\/strong><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-471\" title=\"localhost\" src=\"http:\/\/mypocket-technologies.com\/wp-content\/uploads\/2013\/08\/localhost.png\" alt=\"\" width=\"262\" height=\"111\" \/><br \/>\n<strong>Moving on&#8230;<\/strong><br \/>\nNow your server elements are set up lets move on to the fun part, drawing! <\/p>\n<p>So lets create our <strong>index.html<\/strong> file.<br \/>\nThe main thing to get out of this code is just a basic set up of the file. You will see some include files at the top. All these files will be included at the bottom of this post.<br \/>\nThis is the most important part to take away from this.<br \/>\n<strong><code>&lt;script src=&quot;http:\/\/localhost:4000\/socket.io\/socket.io.js&quot;&gt;&lt;\/script&gt;<\/code><\/strong> this what hooks us into the socket.io server.<\/p>\n<pre class=\"prettyprint\">&lt;!doctype html&gt;<br\/>&lt;html lang=&quot;en&quot;&gt;<br\/>\t&lt;title&gt;Shared DrawPad&lt;\/title&gt;<br\/>\t&lt;link type=&quot;text\/css&quot; href=&quot;css\/bootstrap.min.css&quot; rel=&quot;stylesheet&quot;\/&gt;<br\/>\t&lt;link type=&quot;text\/css&quot; href=&quot;css\/drawpad.css&quot; rel=&quot;stylesheet&quot;\/&gt;<br\/>\t&lt;script src=&quot;js\/jquery-1.10.2.min.js&quot;&gt;&lt;\/script&gt;<br\/>\t&lt;script src=&quot;js\/bootstrap.min.js&quot;&gt;&lt;\/script&gt;<br\/>\t&lt;script src=&quot;js\/drawing.js&quot;&gt;&lt;\/script&gt;<br\/>\t&lt;script src=&quot;http:\/\/localhost:4000\/socket.io\/socket.io.js&quot;&gt;&lt;\/script&gt;<br\/>\t<br\/>\t&lt;body&gt;<br\/>\t\t&lt;div id=&quot;drawingPad&quot;&gt;<br\/>\t\t\t&lt;!-- Code will be place dynamically --&gt;<br\/>\t\t&lt;\/div&gt;<br\/>\t&lt;\/body&gt;<br\/>\t&lt;script type=&quot;text\/javascript&quot;&gt;<br\/>\t\t$(document).bind(&quot;touchmove&quot;, function(e) {<br\/>\t\t\te.preventDefault();<br\/>\t\t});<br\/>\t\t\/\/ overriding default options<br\/>\t\tvar options = {<br\/>\t\t\twidth:800,<br\/>\t\t\theight:500<br\/>\t\t},<br\/>\t\t\/\/init the drawpad<br\/>\t\tdp = new DrawingPad(options);<br\/>\t\tdp.init(&quot;#drawingPad&quot;);<br\/>\t&lt;\/script&gt;<br\/>&lt;\/html&gt;<\/pre>\n<p><strong>Drawing Javascript Code<\/strong><br \/>\nI&#8217;m not going to go into every line of code and explain what it does. You can look over the <a href=\"https:\/\/github.com\/djmason9\/websocket-canvas-draw\" target=\"_new\" rel=\"noopener\">full code<\/a> and see read the comments if you want. What I do want to do is point out some of the special things that make this drawing application capable of being collaborative.<\/p>\n<p>The first thing you need to do is establish a connection to the socket. Here I just create an object that the application can use to set and call socket events.<br \/>\n<strong><code><br \/>\nDP.thisObj.socket = io.connect(\"http:\/\/localhost:4000\");<br \/>\n<\/code><\/strong><\/p>\n<pre class=\"prettyprint\">\n...\n$(selector).append(_buildToolBar); \/\/add tool bar to DOM\n\n\/\/register socket listeners\nDP.thisObj.socket = io.connect(\"http:\/\/localhost:4000\");\n\t\nDP.thisObj.socket.on('setUserList', function(data) {\n   return setUserList(data); \/\/show pop up list\n});\n...\n<\/pre>\n<p>The next thing would be to establish <em>listeners<\/em> for socket events. So that when socket calls <em><strong>emit<\/strong><\/em> I can listen for that and do something. In this example I am setting a listener that listens for the <em>draw<\/em> emit event from the server. <\/p>\n<pre class=\"prettyprint\">\nDP.thisObj.socket.on('draw', function(data) {\n      return draw(data);\n});<\/pre>\n<p>The other thing you will be using a lot of is the <strong><em>emit<\/em><\/strong> event. The server can emit events and so can you. When you emit an event the server needs to listen for that event in order to react to it. In this example I will emit events then the server will listen for that event and emit back a response. So first I will talk about the client side emit events then I&#8217;ll look at how the server handles that. <\/p>\n<p>This code is the event binding of the canvas element. I&#8217;m using jQuery to bind a set of event types (&#8220;touchstart&#8221; , &#8220;mousedown&#8221;, &#8220;touchmove&#8221; , &#8220;mousemove&#8221;, &#8220;touchend&#8221; , &#8220;mouseup&#8221;). Once one of those events is triggered I want the canvas&#8217;s that are sharing to listen for those events too and draw. I do this by calling <code><strong>DP.thisObj.socket.emit('drawRequest', data) <\/strong><\/code><\/p>\n<pre class=\"prettyprint\">\nDP.thisObj.find(\".myCanvas\").bind(events, function(e){\n  e.preventDefault();\n  if(DP.isDrawing || DP.isLineDrawing) {\n    var coords = _getCoords(DP.isTouchDevice?e.originalEvent:e),\n    data = {\n\t x: coords.x,\n\t y: coords.y,\n\t type: e.type,\n\t isTouchDevice : DP.isTouchDevice,\n\t color: DP.thisObj[DP.thisObj.id].ctx.strokeStyle,\n\t stroke : DP.thisObj[DP.thisObj.id].ctx.lineWidth,\n\t isLineDrawing : DP.isLineDrawing,\n\t isErase : DP.isErase,\n\t id : DP.thisObj.id\n   };\n\n   draw(data, true);\n\n   if(DP.okToDraw || e.type === eventType.up) {\n\t DP.isSharing ? <b>DP.thisObj.socket.emit('drawRequest', data)<\/b> : \"\";\n   }\n  }\n});\n<\/pre>\n<p><b>Back to the server&#8230;<\/b><br \/>\nIn order for the <em>drawRequest<\/em> to be picked up and broadcast to everyone else I need to have a lister on the socket server to listen for the <em>drawRequest<\/em> call. So on the socket server (<b>server.js<\/b>) I added this code <\/p>\n<pre class=\"prettyprint\">\n\/\/drawing data\nsocket.on('drawRequest', function (data) {\n  socket.broadcast.emit('draw', {\n\tx: data.x,\n\ty: data.y,\n\ttype: data.type,\n\tisTouchDevice : data.isTouchDevice,\n\tcolor: data.color,\n\tstroke: data.stroke,\n\tisLineDrawing: data.isLineDrawing,\n\tisErase: data.isErase,\n\tid: data.id\n  });\n});\n<\/pre>\n<p>Notice on the server the syntax is a little different. I have an <b>on<\/b> event listening for the <em>drawRequest<\/em> message then it broadcasts an emit to everyone else except the person calling it. This is sort of important to know because if you were doing something that you needed to listen for too, you would need to leave out the broadcast piece. So in the case of <em>getUserList<\/em> where I&#8217;m getting a list of all connected users I need to get back that list. If I called <strong>socket.broadcast.emit(&#8220;setUserList&#8221;, connectedClients);<\/strong> everyone else would be sent that userList and not me.  So what i need to do is this.<\/p>\n<pre class=\"prettyprint\">\n\/\/returns back a list of clients to the requester\nsocket.on(\"getUserList\", function (data) {\n   socket.emit(\"setUserList\", connectedClients); \/\/send to sender\n});\n<\/pre>\n<p>I&#8217;m just leaving out the broadcast part and it echoes back to me too.<\/p>\n<p>That&#8217;s about it. The rest of the file is about the drawing piece of the code. If you want to learn how to draw on the canvas you can go through and look at the code and see how I did it. But this is really more about just communicating across the network.<\/p>\n<p><strong>Links:<\/strong><br \/>\n<a href=\"https:\/\/github.com\/djmason9\/websocket-canvas-draw\" target=\"_new\" rel=\"noopener\">Get the full code<\/a><\/p>\n<p><iframe loading=\"lazy\" width=\"100%\" height=\"315\" src=\"\/\/www.youtube.com\/embed\/SnUtpKww7Nc\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my day job i do all kinds of different projects. Recently, I was tasked to do a collaborative drawing application using HTML5 canvas. Now, I&#8217;m sure there are any number of ways to do this, but I decided the fastest and easiest way was to use node.js and socket.io. After looking around I didn&#8217;t&hellip;<\/p>\n<p class=\"more-link\"><a href=\"https:\/\/bitcows.com\/?p=14\" class=\"themebutton\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[50,62],"class_list":["post-14","post","type-post","status-publish","format-standard","hentry","category-coding","tag-javascript","tag-web"],"_links":{"self":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=14"}],"version-history":[{"count":0,"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts\/14\/revisions"}],"wp:attachment":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}