fabric.StaticCanvas.prototype.getObjectByName = function(name){
if(!name || typeof name === 'undefined'){
return [];
}
return this._objects.filter(function(o) {
return o.name === name;
});
}
var canvas = new fabric.Canvas('fabriccanvas');
canvas.counter = 0;
var newleft = 0;
canvas.selection = false;
var undoStack = [];
var redoStack = [];
addrect = function addrect(top, left, width, height, fill) {
var rect = new fabric.Rect({
top: document.getElementById("fabriccanvas").height,
name: 'rectangle ' + canvas.counter,
left: 0 + newleft,
width: 100,
height: 100,
fill: '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6),
//fix attributes applied for all rects
opacity: 0.75,
lockRotation: true,
originX: 'left',
originY: 'bottom',
cornerSize: 15,
hasRotatingPoint: false,
perPixelTargetFind: true,
minScaleLimit: 1
})
canvas.add(rect);
undoStack.push({
type:'added',
object : rect
})
canvas.counter++;
newleft += 100;
redoStack=[];
}
var state = [];
var mods = 0;
var props = {};
canvas.on(
'mouse:down', function (e) {
var block = e.target;
if(block){
props.oldStage = {
left:block.left,
top:block.top,
width:block.width,
height:block.height,
scaleX:block.scaleX,
scaleY:block.scaleY,
}
}
}).on(
'mouse:up', function (e) {
var block = e.target;
if(block){
props.newStage = {
left:block.left,
top:block.top,
width:block.width,
height:block.height,
scaleX:block.scaleX,
scaleY:block.scaleY,
}
undoStack.push({
objectName : block.name,
type:'modified',
oldStage:props.oldStage,
newStage:props.newStage
});
props={};
}
});
undo = function undo() {
if(undoStack.length){
var undoData = undoStack.pop();
if(undoData && undoData.type){
switch(undoData.type){
case 'added':
var objectByName = canvas.getObjectByName(undoData.object.name);
if(objectByName.length){
canvas.remove(objectByName[0]);
}
break;
case 'modified':
var objectByName = canvas.getObjectByName(undoData.objectName);
if(objectByName.length){
for(var key in undoData.oldStage){
objectByName[0].set(key, undoData.oldStage[key]);
}
}
break;
}
canvas.renderAll();
}
redoStack.push(undoData);
}
}
redo = function redo() {
if(redoStack.length){
var redoData = redoStack.pop();
if(redoData && redoData.type){
switch(redoData.type){
case 'added':
if(redoData.object){
canvas.add(redoData.object);
}
break;
case 'modified':
var objectByName = canvas.getObjectByName(redoData.objectName);
if(objectByName.length){
for(var key in redoData.newStage){
objectByName[0].set(key, redoData.newStage[key]);
}
}
break;
}
canvas.renderAll();
}
undoStack.push(redoData);
}
}
clearcan = function clearcan() {
canvas.clear().renderAll();
canvas.counter=0;
undoStack=[];
redoStack=[];
newleft = 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.js"></script>
<input type="button" value="addrect" onclick="addrect()">
<input type="button" value="undo" onclick="undo()">
<input type="button" value="redo" onclick="redo()">
<input type="button" value="clear" onclick="clearcan()">
<br/>
<canvas id="fabriccanvas" width="600" height="200" style="border:1px solid #ccc"></canvas>