撤消重做功能在这段代码中工作正常,但是如何使用fabricjs enlivenObjects方法执行相同操作。我希望使用enlivenObjects而不是loadFromJSON方法实现相同的结果.canvas对象容器中的对象应该能够撤消和重做。
<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>
var canvas = new fabric.Canvas('fabriccanvas');
canvas.counter = 0;
var newleft = 0;
canvas.selection = false;
addrect = function addrect(top, left, width, height, fill) {
canvas.add(new fabric.Rect({
top: document.getElementById("fabriccanvas").height,
name: 'rectangle ' + window.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
}));
updateModifications(true);
canvas.counter++;
newleft += 100;
}
var state = [];
var mods = 0;
canvas.on(
'object:modified', function () {
updateModifications(true);
},
'object:added', function () {
updateModifications(true);
});
function updateModifications(savehistory) {
if (savehistory === true) {
myjson = JSON.stringify(canvas);
state.push(myjson);
}
}
undo = function undo() {
if (mods < state.length) {
canvas.clear().renderAll();
canvas.loadFromJSON(state[state.length - 1 - mods - 1]);
canvas.renderAll();
//console.log("geladen " + (state.length-1-mods-1));
//console.log("state " + state.length);
mods += 1;
//console.log("mods " + mods);
}
}
redo = function redo() {
if (mods > 0) {
canvas.clear().renderAll();
canvas.loadFromJSON(state[state.length - 1 - mods + 1]);
canvas.renderAll();
//console.log("geladen " + (state.length-1-mods+1));
mods -= 1;
//console.log("state " + state.length);
//console.log("mods " + mods);
}
}
clearcan = function clearcan() {
canvas.clear().renderAll();
newleft = 0;
}
答案 0 :(得分:1)
我认为使用loadFromJSON
或enlivenObjects
来实现此目的不是很好。
如果在运行undo / redo时要加载大量的svg,则将花费一些时间进行渲染,对于很小的更改(如对象的位置)重新加载所有内容也没有多大意义。
我的想法是使用两个堆栈,在其中您将使用结构事件保存对象的修改。
您可以在这里看看:
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>