user331914
user331914

Reputation:

How to add undo-functionality to HTML5 Canvas?

I have a Sketching app done in all HTML5 and Javascript, and I was wondering how I would create an Undo Button, so you could undo the last thing you drew. Any idea?

Upvotes: 11

Views: 16353

Answers (3)

Miguel Ehrstrand
Miguel Ehrstrand

Reputation: 71

Here is a solution that works for me. I have tried it in the latest versions of Firefox and Chrome and it works really well in those two browsers.

var isFirefox = typeof InstallTrigger !== 'undefined';
var ctx = document.getElementById('myCanvas').getContext("2d");
var CanvasLogBook = function() {
    this.index = 0;
    this.logs = [];
    this.logDrawing();
};
CanvasLogBook.prototype.sliceAndPush = function(imageObject) {
    var array;
    if (this.index == this.logs.length-1) {
        this.logs.push(imageObject);
        array = this.logs;
    } else {
        var tempArray = this.logs.slice(0, this.index+1);
        tempArray.push(imageObject);
        array = tempArray;
    }
    if (array.length > 1) {
        this.index++;
    }
    return array;
};
CanvasLogBook.prototype.logDrawing = function() { 
    if (isFirefox) {
        var image = new Image();
        image.src = document.getElementById('myCanvas').toDataURL();
        this.logs = this.sliceAndPush(image);
    } else {
        var imageData = document.getElementById('myCanvas').toDataURL();
        this.logs = this.sliceAndPush(imageData);
    }
};
CanvasLogBook.prototype.undo = function() {
    ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height());
    if (this.index > 0) {
        this.index--;
        this.showLogAtIndex(this.index);
    }
};
CanvasLogBook.prototype.redo = function() {
    if (this.index < this.logs.length-1) {
        ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height());
        this.index++;
        this.showLogAtIndex(this.index);
    }
};
CanvasLogBook.prototype.showLogAtIndex = function(index) {
    ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height());
    if (isFirefox) {
        var image = this.logs[index];
        ctx.drawImage(image, 0, 0);
    } else {
        var image = new Image();
        image.src = this.logs[index];
        ctx.drawImage(image, 0, 0);
    }
};
var canvasLogBook = new CanvasLogBook();

So every time you draw any thing you will there after run function canvasLogBook.logDrawing() to store a snapshot of the canvas and then you can call canvasLogBook.undo() to undo and canvasLogBook.redo() to redo.

Upvotes: 1

Jonas
Jonas

Reputation: 128867

You have to store all modifications in a datastructure. Then you can delete the latest modification if the user wants to undo it. Then you repaint all drawing operations from your datastructure again.

Upvotes: 14

Jean Vincent
Jean Vincent

Reputation: 12435

The other option, if you need to manipulate objects is to convert your canvas to SVG using a library that preserves the Canvas API preventing a rewrite.

At least one such library exists at this time (November 2011): SVGKit

Once you have SVG, it is much easier to remove objects and much more without the need to redraw the entire canvas.

Upvotes: 1

Related Questions