Implementing Robust Undo/Redo in Fabric.js Canvas Editors

This article explains how to add undo and redo functionality to a Fabric.js canvas editor by maintaining a history stack, provides full source code, discusses performance considerations, and compares alternative approaches such as the Command Pattern and object‑level diff snapshots.

Code Mala Tang
Code Mala Tang
Code Mala Tang
Implementing Robust Undo/Redo in Fabric.js Canvas Editors

Any editor needs undo and redo features, and this guide shows how to implement them in a Fabric.js image editor that supports various canvas transformations.

The example adds random‑colored rectangles and demonstrates undo/redo, which applies to all Fabric.js canvas applications.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Fabric.js canvas undo and redo functionality</title>
</head>
<body>
  <h1>Fabric.js 6.0.2 Canvas undo and redo</h1>
  <input type="button" id="addrect" value="addrect" />
  <input type="button" disabled="disabled" id="btnUndo" value="undo" />
  <input type="button" disabled="disabled" id="btnRedo" value="redo" />
  <input type="button" id="clear" value="clear" />
  <canvas id="c" width="600" height="200" style="border:1px solid #ccc"></canvas>
  <script src="assets/js/thirdparty/fabric.min.js"></script>
  <script type='module'>
import UndoRedo from './UndoRedo.js';

var canvas = new fabric.Canvas('c');
canvas.counter = 0;
const ur = new UndoRedo(canvas);
var newleft = 0;
canvas.selection = false;

const Rectangle = {
    addrect: function() {
        ur.updateState();
        canvas.add(new fabric.Rect({
            top: canvas.height,
            name: 'rectangle ' + window.counter,
            left: 0 + newleft,
            width: 100,
            height: 100,
            fill: '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6),
            opacity: 0.75,
            lockRotation: true,
            originX: 'left',
            originY: 'bottom',
            cornerSize: 15,
            hasRotatingPoint: false,
            perPixelTargetFind: true,
            minScaleLimit: 1
        }));
        canvas.counter++;
        newleft += 100;
    },
    clearcan: function() {
        newleft = 0;
        canvas.clear();
        canvas.renderAll();
    }
};

document.getElementById('addrect').addEventListener('click', function() {
    Rectangle.addrect();
});
document.getElementById('clear').addEventListener('click', function() {
    Rectangle.clearcan();
    ur.clearAll();
});
</script>
</body>
</html>

The editor records each operation by pushing the current canvas state (as JSON) onto an undo stack; undo pops the last state, pushes the current state onto a redo stack, and restores the popped state, while redo performs the inverse.

This stack‑based approach works for simple and complex edits, ensuring accurate and consistent undo/redo, but can consume significant memory and affect performance with many operations.

Alternative strategies include:

Command Pattern

Pros: minimal memory use, precise granularity, composable commands, O(1) state switches.

Cons: requires a command class for each action, deep knowledge of Fabric object structures, difficult to restore some complex operations.

Best for: advanced editors and systems needing fine‑grained control.

Object‑level Diff Snapshots

Pros: less space than full JSON, fast restoration, no custom command classes needed.

Cons: must track unique object IDs, intercept Fabric events, performance may degrade with many changes.

Best for: canvases with many objects but few changes, such as designers or annotation tools.

Summary

Undo and redo are essential for image editors; a well‑designed implementation like Photoveda's provides a solid reference for developers building similar functionality.

JavaScriptCanvasFabric.jsUNDORedo
Code Mala Tang
Written by

Code Mala Tang

Read source code together, write articles together, and enjoy spicy hot pot together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.