Web Experiment: Shared canvas with Websockets

For today experiment I tryed to recreate the cool sketchpad by mr doob using websockets and HTML5Canvas.

The idea is that while you paint on the canvas your strokes are send to the server and broadcast to all the users on the web in realtime using websockets, you also can see the cursor of the other people. Click on the image to test it but remember that if there are not other users online you will be just drawing alone.

Shared Canvas

If you want to know more about the coding read the full post.

Server side

I’ve been trying for a long time to make an app using websockets, but it turned out to be harder than it should be, mainly because the standard has been changing constantly for the last year so it was hard to find libraries to use on the server side to abstract me from the protocol, I even tryed to coded by myself but there was some binary info being exchanged that I couldnt handle.

I wanted to code a simple broadcast server. I’ve done it before in python but for this time I wanted to use node.js, I really think that nodejs is a great idea. I understand why some people hesitate, but the truth is that it allows to prototype apps really fast thanks to a good API and the benefits of using the same code on the server and the client.

I’ve tryed to code a broadcast server in nodejs before, but all the libraries I tryed were giving me problems during installation, even using the node package manager. Everybody recommends to use socket.IO but I find that library too big and complex to use (it forces you to serve files to fallback in case the browser doesnt support websockets, which wasnt my case).

Finally I found one called faye-websockets that worked perfectly, nice sintax and support most of the version of the standard. It even creates an http server so you can use the same server to handle static files.

The server is really simple, every message gets resend to all the clients connected, it even allows to buffer the latest 100 messages so you can replicate the last part of the session when someone gets connected.

I was surprised by the performance, it will be nice to make a benchmark with several users but right now it seems it can handle a lot of concurrent users without problems.

And the coolest thing is that the server is totally blind to the app, so I can reuse it for any app I want in the future. I’m improving it so it allows a tiny protocol to store and retrieve info from the server.

Client side

Here nothing new, the user actions are transformed in messages and then processed by the painting app and sent to the server, so I dont have to code the behaviour of the users actions separately.

I experimented with different types of brushes but the HTML5 Canvas is limited, I wanted to tint an image and use it as a brush but the Canvas doesnt allow to tint an image, so I discarded that option).

The cool thing is that now I can add new types of user actions and the platform doesnt change, so to prove that I did cursor rendering on the screen of the other online users.

Persistent data

There is only one problem about the app, new users cant see the previous image (besides the buffered strokes which are just a few), so I’ve been thinking of an option that let the users send to the server the canvas image so the new users can download it, I can do that easily using the http server included with the library.

The server sets a DB where it can store data (just a name=>value storage). Clients can send data with a given name or retrieve it. This info is not persistent once the server is restarted (it can be easily dumped to a text file but I dont need it by now).

The only problem was that due to cross-server policies I wasnt able to access the HTTP server through ajax calls if the server were I hosted the app was not the own websocket-http server (which wasnt).

Luckly thanks to this wonderful site I was able to set the CORS policy info on the HTTP response header very easily just adding this field:

response.writeHead(status_code, {'Content-Type': 'text/plain', "Access-Control-Allow-Origin":"*"});

Another nice feature is that I can access my server through the browser typing an special url to check how many clients are online, useful to debug purposes. I even could create a tiny admin protocol to handle stuff.


Leave a Reply

5 + = nine