Building a collaborative whiteboard with Fabric.js

Written by Jeroen van Veen on 19th February 2016

A colleague of mine asked whether I wanted to write a javascriptish whiteboard that allows multiple persons to draw on a shared canvas as a mini project for another colleague. Ow, and it shouldn’t take more than a day or so to build. Challenge accepted! So, where to get started besides the boilerplate npm/gulpfile?

Canvas

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

So I gave Fabric.js a try. According to the website, Fabric.js is ‘a powerful and simple javascript HTML5 canvas library’. Well, I can only endorse this! The library makes it a breeze to draw shapes, text, strokes and other media on the canvas. The awesome part is that it keeps track of these objects afterwards (the scene part), so they can be moved, rotated, transformed and deleted as vector objects using built-in UI-controls.

Multiple users

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.

getwellsoon-1

Your thoughts

  • Written by Harsh on 18th November 2015

    Hi,

    Can I get the source code of “whiteboard with Fabric.js” .
    I am trying to build one myself but I am looking for a good starting point.
    With your article and your source code I will very easy for me to understand and modify your code.

    Thanks
    Harsh

  • Written by Jeroen on 18th November 2015

    Hi Harsh,

    Sure the repo link is in the article. It is: https://github.com/wearespindle/dotd
    Feel free to ask if you have any questions!

    kind regards,

    Jeroen

  • Written by Derek Hildreth on 6th September 2016

    Jeroen,

    First off, thanks for putting this together and publishing it. It’s been a great resource to help me jump start my own project. Do you have any suggestions on how to support touch screen devices? If you pull up your dotd app in Chrome, bring up the development tools, and switch over to mobile mode, you’ll notice drawing isn’t supported. I’m hoping this is something simple that a node.js/canvas/fabric newbie like me would overlook. Thanks in advance for any help. Thought I’d ask here before asking stackoverflow.

    Thanks,
    Derek

  • Written by Jeroen van Veen on 12th September 2016

    Hi Derek,

    You’re welcome! I didn’t do any testing with touch devices, but you’ll probably need to fix it on the Fabric.js side. There is currently not much code in the dotd repo that handles drawing; that’s handled by Fabric.js completely iirc. I’m not sure if I included touch support in the build that comes with the repo. You probably want to check this. Also, there are some click handlers for the UI that may need to be extended to support touch events. For Fabricjs touch, I found the following resources:
    http://fabricjs.com/touch-events
    http://stackoverflow.com/questions/32472958/how-to-get-fabricjs-to-work-with-touch-events
    https://github.com/kangax/fabric.js/wiki/Working-with-events

    Good luck!

  • Written by Eric Brown on 2nd December 2016

    Since there isn’t a working demo online I’m trying to get it to run locally but having a dependency issue. I’ve installed jsdom, but still get the error. Any thoughts? Awesome concept.

    Error: Cannot find module ‘jsdom’
    at Function.Module._resolveFilename (module.js:469:15)
    at Function.Module._load (module.js:417:25)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object. (/Applications/MAMP/htdocs/whiteboard/public_html/dotd/node_modules/fabric/dist/fabric.js:17:21)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)

  • Written by Jeroen van Veen on 3rd January 2017

    Hi Eric,

    Dotd didn’t receive any updates for a long time. It’s dependencies node-canvas/fabric/jsdom don’t work with more recent Node versions. In order to get it working, you could use nvm(https://github.com/creationix/nvm/blob/master/README.markdown) and set your Node version back to 0.12. Remove the node_modules, and do a fresh npm install. This should work(although with some warnings ). Hope this helps.

  • Written by Stefan on 25th January 2017

    Interesting. As side project and for fun we created http://wireflow.co/wire/ts7mcS27BFb9nuTuL , real-time collaborative tool with Meter, React and Fabric.js.

    It’s buggy and unfinished, but you can check the functionality.

  • Written by Collaborative Digital Signage Project – Technologic Systems Blog on 1st February 2017

    […] whiteboard. Luckily, there were several available. After evaluating a few of them, we went with Building a collaborative whiteboard with Fabric.js by Jeroen van Veen. A node.js development environment was setup on a laptop, and customization on Jeroen’s code […]

  • Written by Alan D'monte on 17th August 2017

    Hi,
    It was a great article. I have been using fabric in a project for past couple of months, but I couldn’t find any support for multi touch drawing using fabric. Could you give any help/suggestions to implement it?
    Thanks in advance

  • Written by Manish Kumar on 14th August 2019

    Hi,

    I am able to clone repo: git clone git@github.com:wearespindle/dotd.git

    But not able to access folder. There is some permission issue here.

    Can you please help me to access folder and run project.

    Thanks.

  • Written by Henk on 14th August 2019

    Hi Manish,

    Thanks for trying this out.
    I just tested this and it should work without issue after cloning.
    Is it the “dotd”-folder that you are unable to enter? If so, are you using the right user with the right permissions? So not cloning as user root.

    Cheers, Henk

Devhouse Spindle