Building a collaborative whiteboard with Fabric.js
Written by Jeroen van Veen on 19th February 2016
Canvas is a nice medium, but it lacks scene abstraction. When you paint strokes on the canvas, there is no reference or whatsoever of the action that’s being carried out. You have to manually keep track of parameters like brush size, paint location/interpolation, color and a dozen other parameters and share these serialized actions with other users, so their canvas is getting updated accordingly to your canvas state. Other artistic tools like text and shapes have their own set of parameters as well. Summarised; writing such a scene-tracking library would have been a massive effort and was not an option for a hackathon-style project.
Working with Fabric.js
Next I had to hook up other users to the same canvas drawing session. Using raw websockets would have been fine, but it would require a lot of boilerplate code that Socket.io already takes care of in a clean way. After I got Socket.io hooked up in Node.js and the browser, I tried to send Fabric.js canvas actions across the wire. This is another thing that got me excited about Fabric.js. It’s very easy to serialize Fabric.js shapes and their current state to JSON, send the data over the wire, and rebuild the object on the other browser canvas. After wiring up several events, I tried to figure out an easy way to restore the current state of a canvas drawing after a user reloaded the browser. There has to be an authoritative source that contains the current state of the canvas, preferably the server.
Fabric.js in Node.js
Node.js has no browser DOM. I figured that I had to store all actions in a database and rebuild the canvas manually. Hell no! Fabric.js to the rescue! It turns out that Fabric.js runs just as easily in Node.js as it does in the browser using node-canvas. So, by adding a serverside Fabric.js canvas in-between the message-passing code, I was able to keep track of the canvas state on the server while multiple users were editing it. Awesome! The whole state is being loaded by the browser from a separate view that’s triggered by an URL like http://localhost:3000/state.js, which makes it easy to add gzip compression to the JSON data before it’s sent over the wire. As a bonus, serverside Fabric.js canvas made it also a no-brainer to make an svg and png export view of the editable canvas.
Finishing the MVP
The project was a lot of fun to work on and shows that with the right libraries and with a small amount of custom code, one can build an MVP collaborative drawing board application in a small amount of time. The only thing I would do different next time is using MongoDB over LokiJS, because this use case only needed serverside storage, and I’m more familiar with MongoDB than with LokiJS.