简体   繁体   English

撤消和重做画布不按预期工作

[英]Undo and Redo Canvas Not Working as Expected

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. 我正在使用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 the undo , redo actions. 可以通过添加或更新画布( object:addedobject:modified画布上的object:modified处理程序来处理)或通过undoredo操作来触发更改。

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 the canvas.loadFromJSON callback comes in handy to actually trigger an action after the canvas has been updated. 为了避免这些undoredo操作与历史记录冲突并添加重复项,您需要在它们发生时标记它们,这就是canvas.loadFromJSON回调在画布更新后实际触发操作的方便之处。

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) 在你习惯它之前,大部分都是有点密集的阅读)

 const canvas = new fabric.Canvas('canvas', { backgroundColor: 'grey', centeredScaling: true }); canvas.setWidth(400); canvas.setHeight(600); canvas.preserveObjectStacking = true; var Addtext = () => { const 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; }; var canvasHistory = { state: [], currentStateIndex: -1, undoStatus: false, redoStatus: false, undoFinishedStatus: true, redoFinishedStatus: true, }; const updateHistory = () => { if (canvasHistory.undoStatus === true || canvasHistory.redoStatus === true) { console.log('Do not do anything, this got triggered automatically while the undo and redo actions were performed'); } else { const jsonData = canvas.toJSON(); const canvasAsJson = JSON.stringify(jsonData); // NOTE: This is to replace the canvasHistory when it gets rewritten 20180912:Alevale if (canvasHistory.currentStateIndex < canvasHistory.state.length - 1) { const indexToBeInserted = canvasHistory.currentStateIndex + 1; canvasHistory.state[indexToBeInserted] = canvasAsJson; const elementsToKeep = indexToBeInserted + 1; console.log(`History rewritten, preserved ${elementsToKeep} items`); canvasHistory.state = canvasHistory.state.splice(0, elementsToKeep); // NOTE: This happens when there is a new item pushed to the canvasHistory (normal case) 20180912:Alevale } else { console.log('push to canvasHistory'); canvasHistory.state.push(canvasAsJson); } canvasHistory.currentStateIndex = canvasHistory.state.length - 1; } }; canvas.on('object:added', () => { updateHistory(); }); canvas.on('object:modified', () => { updateHistory(); }); var undo = () => { if (canvasHistory.currentStateIndex - 1 === -1) { console.log('do not do anything anymore, you are going far to the past, before creation, there was nothing'); return; } if (canvasHistory.undoFinishedStatus) { canvasHistory.undoFinishedStatus = false; canvasHistory.undoStatus = true; canvas.loadFromJSON(canvasHistory.state[canvasHistory.currentStateIndex - 1], () => { canvas.renderAll(); canvasHistory.undoStatus = false; canvasHistory.currentStateIndex--; canvasHistory.undoFinishedStatus = true; }); } }; var redo = () => { if (canvasHistory.currentStateIndex + 1 === canvasHistory.state.length) { console.log('do not do anything anymore, you do not know what is after the present, do not mess with the future'); return; } if (canvasHistory.redoFinishedStatus) { canvasHistory.redoFinishedStatus = false; canvasHistory.redoStatus = true; canvas.loadFromJSON(canvasHistory.state[canvasHistory.currentStateIndex + 1], () => { canvas.renderAll(); canvasHistory.redoStatus = false; canvasHistory.currentStateIndex++; canvasHistory.redoFinishedStatus = true; }); } }; 
 <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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM