How to step back in HTML5 Canvas history

时间:2015-07-08 15:38:58

标签: javascript jquery html5 canvas

I have an image cropper using Imgly HTML5 Canvas plugin. I need to be able to setup a history stack for the cropper to be able to undo a crop operation. Currently, I can clear the canvas on button click, but I need to be able to retain the original image, and just move back through a history of changes of the image in the canvas, in the event that a cropping step is done incorrectly.

I have the following which simply clears the 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();
    });

The plugin creates the canvas element on image load with:

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);
};

And this is used on resize:

    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;
};

So I'm not sure how to build a call stack to reference each change and move back through a history of modifications to an image in the canvas.

2 个答案:

答案 0 :(得分:3)

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 :(得分:0)

您应该查看command pattern。基本上,您需要为用户可以执行的每个操作编写一个函数。当他们点击按钮或加载图片时,请不要立即调用该功能。而是创建一个命令对象,其中包含执行命令所需的所有信息以及撤消命令所需的信息。

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

对于裁剪命令,您需要存储旧的和新的裁剪矩形 - 如果您保留原始图像的副本。执行该命令时,在原始图像上应用新的裁剪矩形并在画布上绘制它。

对于撤消,您可以使用原始图像和上一个裁剪矩形。

所以诀窍是定义一个数据模型,其中包含UI的所有信息(通常难以直接从UI获取) - 在将裁剪后的图像渲染到后,您无法获取裁剪信息帆布)。然后命令操作此状态(因此下一个命令可以保存它以进行撤消)并更新UI。