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

cod*_*ver 8 javascript fabricjs

我有一个带有可添加对象的画布,以及撤消和重做按钮.正如你在我的例子中所看到的,我能够撤消/重做一次,但事情就会破裂; 通过这个我的意思是我可以添加一个对象并删除它,但是如果我移动添加的对象并点击撤消,它应该移动到我以前的位置,但它会从画布中消失.

我正在使用fabric.js 1.7.22.

我的代码:

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());
  }
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

Ale*_*les 8

您需要添加某种状态管理函数来处理画布的状态,并且每次发生更改时都能够恢复和更新状态.

这些变化既可以由加法或画布(的更新被触发object:added,object:modified在画布上处理照顾这个),或者通过undo,redo行动.

为了避免这些undo,redo操作与历史记录冲突并添加重复项,您需要在它们发生时标记它们,这就是canvas.loadFromJSON回调在画布更新后实际触发操作的方便之处.

我添加了它的一个功能示例,并添加了一些调试消息,以便代码更容易理解.在你习惯它之前,大部分都是有点密集的阅读)

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;
        });
    }
};
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)