如何在HTML5 Canvas中撤销操作历史记录

3
我使用了Imgly HTML5 Canvas插件来裁剪图片。我需要能够为裁剪器设置历史记录堆栈以便撤销裁剪操作。目前,我可以通过按钮点击清除画布,但我需要能够保留原始图像,并在画布中回退更改图像的历史记录,以防意外执行裁剪步骤。
以下是用于清除画布的代码:
$("#renderButton").click(function() {
        var elem = $(".imgly-canvas");
        var canvas = elem.get(0);
        var context = canvas.getContext("2d");
        $('#file').val('');

        context.clearRect(0, 0, canvas.width, canvas.height);
        context.beginPath();
    });

插件在图片加载时创建画布元素,使用以下代码:
Utils.getImageDataForImage = function(image) {
  var canvas, context;
  canvas = document.createElement("canvas");
  canvas.width = image.width;
  canvas.height = image.height;
  context = canvas.getContext("2d");
  context.drawImage(image, 0, 0);
  return context.getImageData(0, 0, image.width, image.height);
};

这是在调整大小时使用的:

    Utils.cloneImageData = function(imageData) {
  var i, newImageData, _i, _ref;
  newImageData = this.sharedContext.createImageData(imageData.width, imageData.height);
  for (i = _i = 0, _ref = imageData.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
    newImageData.data[i] = imageData.data[i];
  }
  return newImageData;
};

/*
  @param {Object} dimensions
  @param {Integer} dimensions.width
  @param {Integer} dimensions.height
  @returns {HTMLCanvasElement}
*/


Utils.newCanvasWithDimensions = function(dimensions) {
  var canvas;
  canvas = document.createElement("canvas");
  canvas.width = dimensions.width;
  canvas.height = dimensions.height;
  return canvas;
};

/*
  @param {imageData} imageData
  @returns {HTMLCanvasElement}
*/


Utils.newCanvasFromImageData = function(imageData) {
  var canvas, context;
  canvas = document.createElement("canvas");
  canvas.width = imageData.width;
  canvas.height = imageData.height;
  context = canvas.getContext("2d");
  context.putImageData(imageData, 0, 0);
  return canvas;
};

我不确定如何构建调用堆栈来引用每个更改并通过画布中的修改历史向后移动。

2个回答

8
HTML5画布能够很好地转换为JSON格式,并可用于重新加载画布。你可以将其存储在全局对象中。
var myObj = window.myObj || {};

myObj = {
    history: [],
    canvas: null
};

获取画布数据:
myObj.canvas = document.getElementById('canvas-id');
var ctx = myObj.canvas.getContext('2d');
var data = JSON.stringify(ctx.getImageData(0, 0, myObj.canvas.width, myObj.canvas.height));

myObj.history.push(data);

重新加载数据:
var reloadData = JSON.parse(myObj.history[someIndex]);
var ctx = myObj.canvas.getContext('2d');
ctx.putImageData(reloadData, 0, 0);

一旦你能够存储/加载数据,棘手的部分就是管理myObj.history数组。


1
你应该看一下 命令模式。基本上,你需要为用户可以执行的每个操作编写一个函数。当他们点击按钮或加载图像时,不要立即调用函数。相反,创建一个包含执行命令所需的所有信息以及撤销命令所需的信息的命令对象。

命令应用于数据模型(图像和裁剪标记)。"加载图像"命令需要记录新旧图像URL,以便在浏览历史记录时加载正确的图像。

对于裁剪命令,如果你保留了原始图像的副本,则需要存储旧的和新的裁剪矩形。当执行命令时,在原始图像上应用新的裁剪矩形并将其绘制到画布上。

对于撤销操作,使用原始图像和先前的裁剪矩形。

因此,关键是定义一个数据模型,其中包含UI外观的所有信息(通常很难从UI直接获取 - 在将裁剪后的图像呈现到画布后,无法获取裁剪信息)。然后,命令操作此状态(以便下一个命令可以保存它以供撤销),并更新UI。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接