Fabric.js History Operations (undo, redo) and Useful Tips

Alim Özdemir
3 min readAug 15, 2019

Hello again, today’s subject is a javascript library called Fabric.js. I have worked with this library a couple of times in the past. However, you have to improvise while using the library features for advanced usages. I needed common features for my projects. Such as, history implementation (redo, undo), clipping the canvas, export image with high resolution and so on. I think this blog post will help other people for required such kind of features.

History

First of all, most required features are undo and redo actions. In fabric.js almost every action is catched with object:modified, object:added and object:removed. Basically, we are keeping the state of the canvas on a stack and redraw the state each time.

historySaveAction collects the user’s actions into the historyUndo stack. However, the events are post-events, because of this we can’t get the current state of the canvas. To solve this problem, we are keeping the current state of the canvas on historyNextStatevariable. And pushing it into the stack when a new event fired.

undo function applies the rollback operation on the state popped from the stack. However, during the canvas re-rendering events from the old state will also trigger. These events should not be fired, therefore historyProcessing variable will block the new states from getting pushed into the stack.

npm package

I have created a npm package in order to make it easier to apply the processes we discussed above. Additionally, it includes redo action. You can install the package using with

npm install fabric-history

Import it to a node project with

import 'fabric-history';

Then basically you have to initialize it

const canvas = new fabric.Canvas('canvas');
canvas.historyInit();

Finally, you can easily redo and undo with

canvas.undo();
canvas.redo();

Download the canvas with higher resolution

Second problem I have faced, my canvas had lower resolution than I needed, and I wanted to download the high resolution version of it. There is a built-in solution for this. Basically, you can multiply the canvas while downloading by

canvas.toDataUrl({ multiplier: 3 });

Then you can download the 3x canvas.

Clip canvas

In most cases, I wanted to clip objects with different kind of shapes. HTML5 canvas has a property called globalCompositeOperation.

https://www.rgraph.net/canvas/reference/globalcompositeoperation.html

This is important while clipping a fabric object. Same rules apply here. For example, I have added a rectangle on the canvas. Then, I have set the clipPath property to a group of objects.

The circle defines the outside border of the rectangle and second rectangle will cut inside of the circle. You can easily set the globalCompositeOperation as destination-out value. And the result;

You can see an example below:

Conclusion

In this blog post, we learned how to use globalCompositeOperation with fabric.js’s objects. Additionally, I have published my first npm package under name fabric-history.

UPDATE

I have updated the fabric-history package. historyInitfunction is not necessary anymore. You just import the package and use undo , redo functions.

fabric-history source code

Resources

--

--