Jeff Kreeftmeijer

Experimenting with Node.js

2010-07-26
If you see extra mouse cursors moving around: don’t worry, they’re part of the demo. You can always disable them if you want.
I’ve written a follow-up on this article, in which I improved a lot of the code. Be sure to read that one too!

If you’re using a browser that supports web sockets, you might see some extra mouse cursors moving around. These are actually other people also looking at this page right now, live, as we speak. If you don’t see anything, try to open up this page in another browser window next to this one and move your mouse in it.

This is an experiment I did to play around with Node.js and web sockets. I’ve put everything in a Gist in case you want to try it out yourself. I’ll explain how it works in this article.

Web socket server

Using @miksago‘s node-websocket-server made it extremely easy to send and receive messages from a web socket. Here’s the code that runs the server:

var ws = require(__dirname + '/lib/ws'),
    server = ws.createServer();

server.addListener("connection", function(conn){
  conn.addListener("message", function(message){
    message = JSON.parse(message);
    message['id'] = conn.id
    conn.broadcast(JSON.stringify(message));
  });
});

server.addListener("close", function(conn){
  conn.broadcast(JSON.stringify({'id': conn.id, 'action': 'close'}));
});

server.listen(8000);

After including the node-websocket-server library and creating the server, I add some listeners to know when clients disconnect or send a message and make sure messages get sent to the other clients. Whenever it receives a JSON message, it includes the connection’s id before broadcasting it to the clients to make it possible to find out which cursor we need to move.

I saved it as server.js, so starting the server is as simple as running node server.js. To make sure it keeps running, I daemonized it with God, using the same config file I used in the “Daemonizing Navvy with God” article.

Receiving messages

Now, in a regular javascript file — with some jQuery — I included into this page, I connect to the web socket like this:

var conn;
var connect = function() {
  if (window["WebSocket"]) {
    conn = new WebSocket("ws://jeffkreeftmeijer.com:8000");
    conn.onmessage = function(evt) {
      data = JSON.parse(evt.data);
      if(data['action'] == 'close'){
        $('#mouse_'+data['id']).remove();
      } else if(data['action'] == 'move'){
        move(data);
      };
    };
  }
};

window.onload = connect;

As you can see, this connects to the server we just started. When a message is received, it checks the action it’s supposed to perform. If the action is “move”, it’ll move a mouse cursor on the screen using the move() function I’ll show you later. If it’s “close”, it means that the client disconnected and his cursor has to be removed from the screen.

Sending messages

Now we’re able to receive messages, move and delete cursors. The last thing we need is the client to be able to send out messages:

$(document).mousemove(
  ratelimit(function(e){
    if (conn) {
      conn.send(JSON.stringify({
        'action': 'move',
        'x': e.pageX,
        'y': e.pageY,
        'w': $(window).width(),
        'h': $(window).height()
      }));
    }
  }, 40)
);

Whenever you move your mouse, the .mousemouse() function gets triggered that sends some JSON with the mouse position and screen size to the socket. The ratelimit method makes sure that there’s a forty millisecond interval between messages.

Moving the cursors

So, when the other clients receive a “move” message, it calls the move() function, like I showed you before. It looks like this:

function move(mouse){
  if($('#mouse_'+mouse['id']).length == 0) {
    $('body').append(
      '<div class="mouse" id="mouse_'+mouse['id']+'"/>'
    );
  }

  $('#mouse_'+mouse['id']).css({
    'left' : (($(window).width() - mouse['w']) / 2 + mouse['x']) + 'px',
    'top' : mouse['y'] + 'px'
  })

It creates a div for the new mouse if it doesn’t exist yet and moves it to the right position. Also, the x-position of the mouse gets calculated while keeping the difference in screen size in mind. This way it gets calculated from the center of the page, instead of from the left.

Blew your mind?

Tracking mouse movement and showing cursors to other clients is cool, but not useful in any way (although you could think of some cool use-cases for this). What this example does show is that you can do pretty impressive things using web sockets and Node.js. And it was a great excuse to play around with it.

This was the first thing I did using Node.js, so the code is probably far from perfect. If you know a way to improve it, please fork the Gist and show me how it should be done. I’ll update the article.

I’m excited about Node.js and I’ll probably write and play around with it some more in the future, so stay tuned.