I have a canvas with an addable objects, as well as Undo and Redo buttons. As you can see in my example, I'm able to undo/redo 1 time but things break; by this I mean I can add an object and remove it but if for example I move the added object and hit undo, it should move to where I had it previously but instead it disappears from the canvas.
I'm using fabric.js 1.7.22.
My Code:
var canvas = this.__canvas = new fabric.Canvas('canvas', {
backgroundColor: 'grey',
centeredScaling: true
});
canvas.setWidth(400);
canvas.setHeight(600);
canvas. preserveObjectStacking = true;
// Add Text
function Addtext() {
var text = new fabric.IText("Tape and Type...", {
fontSize: 30,
top: 10,
left: 10,
textAlign: "center",
});
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
text.enterEditing();
text.selectAll();
canvas.renderAll();
canvas.isDrawingMode = false;
}
// Undo Redo
canvas.on('object:added',function(){
if(!isRedoing){
h = [];
}
isRedoing = false;
});
var isRedoing = false;
var h = [];
function undo(){
if(canvas._objects.length>0){
h.push(canvas._objects.pop());
canvas.renderAll();
}
}
function redo(){
if(h.length>0){
isRedoing = true;
canvas.add(h.pop());
}
}
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<a href="#" class="btn btn-dark" onclick="Addtext()">Add Text</a>
<button onclick="undo()" type="button" class="btn btn-sm btn-dark">
<i class="material-icons">undo</i>
</button>
<button onclick="redo()" type="button" class="btn btn-sm btn-dark">
<i class="material-icons">redo</i>
</button>
<canvas id="canvas"></canvas>
You need to add some kind of state management functions that handle the state of the canvas, and that is able to restore and to update the state each time a change occurs.
The changes could be triggered by either the adding or updating of the canvas (the
object:added
,object:modified
handlers on the canvas take care of this) or by theundo
,redo
actions.To avoid those
undo
,redo
actions colliding with the history and adding duplicates you need to flag them when they are happening, and that is where thecanvas.loadFromJSON
callback comes in handy to actually trigger an action after the canvas has been updated.I added a functional example of it, and also added a couple of debugging messages so that the code is a little more understandable. Mostly is a little dense to read until you get used to it)