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.
答案 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。