HTML5 Canvas Element and it’s clipTo property using FabricJS and NodeJS

Using the clipTo function in the HTML5 canvas with FabricJS and NodeJS
This article discusses how to use HTML5, FabricJS, and NodeJS to make a dynamic web app for interacting with the HTML5 Canvas. Also, how to clip an image to a bounding box to create a crop function in FabricJS.

Sometime ago I was new to the HTML5 canvas – it sounded cool with unlimited possibilities but I had no use case for it at the time and no time to dabble with it.  But then a project came along and I didn’t just dip my toe into the canvas world, I jumped head first in!  Well sort of – I utilized the FabricJS library to try and ease my way in.  Then, shortly after that, I had to dive into setting up NodeJS and created a webserver in NodeJS.  The NodeJS webserver is used to generate high-resolution print quality images from the design created on the HTML5 canvas.

A quick side note: In this application, the website owners print the high resolution images for the client.  While HTML5 and the canvas could create the print quality images in the browser with out using the NodeJS server, I ran into issues in transferring the images to the web server for the business to print.  The biggest issue came from mobile devices and file size and memory limitations set there.

So my first dive into HTML5 Canvas and FabricJS, I needed to utilize the clipTo property.  And I got it to work, but after a ton of fumbling and struggling.  In hindsight that I learned this week, I didn’t understand what was happening.  So hopefully I can help clear that up for some others.

What is the HTML5 Canvas?

We need to understand this first.  At it’s base level, the <canvas> is nothing more than another HTML element really…  If you add this tag you won’t get anything cool or fancy happening on your page.  But it’s more of a powerful placeholder for what is yet to come.

The way you “paint” on your canvas (which you actually can with free hand options) is typically through Javascript code.  This can be done ‘statically’, or dynamically through user interactions.  And this is where you should get excited.  Users can modify the canvas through HTML controls you offer them.  This is what brings the canvas alive and opens the door to some amazing interactivity on your website!

What is unique about the <canvas> tag is that the elements you put on the canvas do NOT become a part of the DOM structure.  So anything that lives on the canvas kind of lives in no mans land so to speak…  So what this means is that from a developers standpoint, trying to inspect the contents of the canvas and doing debugging is rather difficult.  (Again, I’ve never worked in native Canvas, so I may be wrong here and welcome comments if I’m off base on this.)

Also, since I come from an SEO mindset, I’ll point out that the canvas will have zero SEO benefit for you, and if your entire page is built on the canvas, that means that you will kill your SEO value.  BUT, adding canvas elements through out your page and site won’t be a problem – I’m just saying you still need traditional text and image content for Search Engines to be able to understand what your page is about.  Think of this much like Flash – search engines struggled to understand Flash elements, partially because they were dynamic components and thus the contents of the page would change.  In essence, canvas is the direct replacement to Flash both in functionality and purpose, so they see it the same way.

I should note that there is a way to view the Canvas in your debugger (this method is for Chrome; I believe something similar can be done in Firebug), but I don’t find it to be too overly helpful.  Using the profiling features you can see how the canvas renders and some other details.  Here is a great tutorial on profiling the canvas from HTML5 Rocks.

Reference: W3Schools

FabricJS Brings A Lot to Canvas Development

I mentioned above that you can use Javascript to write to the canvas and build interactive controls.  As with most programming tasks, there are various methods to approach this.  In my case, I’ve using the FabricJS library to simplify the programming tasks – FabricJS is designed to make it a bit easier to work with the <canvas> element.

Seeing as I haven’t dabbled too deeply into the raw canvas methods I’m not sure, just how much FabricJS really simplifies things.  But I will say this – what would take 5 lines of raw canvas code can be accomplished in 1 line of FabricJS code.  I did look at some other libraries as well for manipulating the canvas, but they didn’t seem as robust or as friendly for working with images and text.

As stated in the section above, seeing what is on the canvas and debugging it can be tough.  But this is one of the benefits of working with FabricJS.  What FabricJS does behind the scenes is builds the contents that go onto the canvas into JSON objects.  The JSON objects then get rendered into Canvas elements.  SO, this means that the JSON objects are now javascript variables, which means you can use the Javascript console in your developers tools to see what is on the canvas.  Additionally, you can easily manipulate your canvas object by modifying the JSON object and calling the render method.  In other-words, you have full insight and control over your canvas element!

I do have to give huge props to Kangax and Kienz for their efforts in developing the FabricJS library though.  The documentation isn’t always as clear or abundant as I may like at times, however it is still growing in community and usership and StackOverflow has been a great resource for information.  The basics are pretty well documented, but as you try to get more advanced and flex what FabricJS can do you need to pull up your sleeves and dig in deep.

Debugging Canvas with FabricJS

Using your Javascript console, or via console.log in your scripts, you can output the JSON objects that FabricJS is using for the canvas.

I forget the reason, but I have had to use a slightly modified method to do this in my webapp – I believe it’s simply because I have two canvases on the same page and one script that auto-detects which canvas you are working on.  So I’m using this script instead to accomplish the same thing:

So now you’ll output the JSON object that is powering your Canvas.  Also, from your browsers debugger you can copy this object to the clipboard if you’d rather view it in a text editor.

So HTML5 Canvas is JSON, right? No.

This is where my headaches were… I worked with FabricJS enough and inspected the JSON objects and just assumed that HTML5 Canvas was built on JSON and JSON alone.  But I’m finding that I’m quite wrong here.  How it really works is that the JSON object is sent to FabricJS to interpret how to display the HTML5 Canvas.  So to reiterate this, because this can become important, JSON is nothing more than instructions – it’s NOT HTML5 Canvas.  Keep reading if you don’t get why that’s important.

Wasn’t this article going to talk about the clipTo property?

Where I learned that canvas and JSON are not the same the hard way, is I was trying to set the clipTo property for an image.  So my task at hand was to have an image in a bounding box – so you can resize and reposition the image but it will never spill outside of the box that it lives in.  In other-words, I’m trying to build a cropping or picture framing method.  To do this, you need to clip the image to the bounding box using the clipTo property on the image – so cut off the edges of the image that fall outside of the bounding box.  Sounds simple, right?  Well not so much… (and on a side note, HTML5 has a default method for this that FabricJS does not recognize – it’s called the globalCompositeOperation.  There are 12 methods of how you can composite two laters together.)  I did find a solution for the bounding box with the clipTo property, and you can find that here.

After much work, I was able to accomplish this task, and you can find a working example of how I used FabricJS to clip and image to a bounding box on JS Fiddle.

The concept is this though – you have an image element, and you have a bounding box element (a rectangle object).  A function then calculates the offsets for the clip to object, which is in essence an inverse dimension that accounts for relative position within the canvas and rotation angles.  Something like that at least.  ;)  It works and it’s been a while since I’ve really dug into the code till I write this, so hopefully this all makes sense still.

This solution does utilize lodash as a method to bind processes together.

There are some limitations to this however:

  • This will work with text, however when you rotate the text the bounding box seems to drift one way or another…
  • The example shown is a rectangle bounding box.  I’ve done work with a polygon, however that introduces a whole new set of issues and I was not able to accomplish a full solution at this time.

Part of me thinks that it’s something to do with the version of FabricJS I’m using – I think Kangax has sone some bug fixes in the library that may help with these limitations, but I haven’t had a chance to fully explore correcting these issues.  (I welcome any insight others may have)

Don’t forget about FabricJS on NodeJS!

When I went to implement this on NodeJS as well for my final rendering, I had to ensure that I was adding in the clipTo property prior to rendering the canvas.  Since you are not displaying the canvas in NodeJS and only doing a single render of it for output, you just need to update the JSON, render the canvas with FabricJS for Node, and save your image.  Just that simple.

To expand a bit, what you are doing is sending the JSON object to NodeJS which is running FabricJS.  So the same process that happens in the browser where FabricJS translates the JSON object into a canvas object happens in the NodeJS server.  But since this is a server, you can’t visually see the canvas.  But I’m saving this out to an image file.  This can be done via several methods, but I’ve found the best method to be to use ImageMagick in NodeJS.

But the moral of the story here is that the NodeJS server needs a similar stack of libraries as the browser – similar version of FabricJS, lodash, etc.  Figuring out the right configuration for the NodeJS server was a project in itself for me and someday I may publish what I have going there.  But for now, the high-level information is here on how to pass the info back and forth.

If you are in need of the NodeJS setup, here is a set of instructions on how to install NodeJS with FabricJS on a Linux server.

I hope this article helps to get you started in the right direction or to clear up some confusion you may have about how to work with the HTML5 canvas element, FabricJS, and how you can utilize NodeJS in your canvas development.  Feel free to comment or ask questions – I enjoy having conversations about this setup.