简体   繁体   English

如何退回到HTML5 Canvas历史记录

[英]How to step back in HTML5 Canvas history

I have an image cropper using Imgly HTML5 Canvas plugin. 我有一个使用Imgly HTML5 Canvas插件的图像裁剪器。 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: 该插件在图像加载时使用以下命令创建canvas元素:

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. 因此,我不确定如何构建一个调用堆栈来引用每个更改,并回溯到对画布中图像的修改历史。

The HTML5 canvas nicely converts to JSON which can then be used to reload the canvas. HTML5画布很好地转换为JSON,然后可用于重新加载画布。 You can store this in a global object. 您可以将其存储在全局对象中。

var myObj = window.myObj || {};

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

Get the canvas data: 获取画布数据:

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

Reload data: 重新加载数据:

var reloadData = JSON.parse(myObj.history[someIndex]);
var ctx = myObj.canvas.getContext('2d');
ctx.putImageData(reloadData, 0, 0);

Once you can store/load data the tricky part is managing the myObj.history array. 一旦可以存储/加载数据,最棘手的部分就是管理myObj.history数组。

You should look at the command pattern . 您应该查看命令模式 Basically, you need to write a function for every action that the user can do. 基本上,您需要为用户可以执行的每个操作编写一个函数。 When they click a button or load an image, don't call the function right away. 当他们单击按钮或加载图像时,请勿立即调用该函数。 Instead, create a command object with all the information needed to execute the command plus the information needed to undo it. 而是创建一个命令对象,其中包含执行命令所需的所有信息以及撤消命令所需的信息。

Commands are applied to a data model (the image and the crop marks). 命令应用于数据模型(图像和裁切标记)。 A command "load image" needs to record the new and the previous image URL so you can load the correct image when you move through the history. 命令“加载图像”需要记录新的和先前的图像URL,以便在浏览历史记录时可以加载正确的图像。

For crop commands, you need to store the old and new crop rectangles - if you keep a copy of the original image around. 对于裁切命令,您需要存储新旧裁切矩形-如果您保留原始图像的副本。 When the command is executed, you apply the new crop rectangle on the original and draw that on the canvas. 执行命令后,将新的裁切矩形应用于原始裁切矩形并将其绘制在画布上。

For undo, you use the original image and the previous crop rectangle. 对于撤消,使用原始图像和先前的裁剪矩形。

So the trick is to define a data model which contains all the information how the UI looks like (which is often hard to get from the UI directly - you can't get crop information after rendering the cropped image to the canvas). 因此,诀窍是定义一个数据模型,其中包含UI外观的所有信息(通常很难直接从UI获取-在将裁剪后的图像渲染到画布后无法获取裁剪信息)。 The commands then manipulate this state (so the next command can save it for undo) and update the UI. 然后,这些命令将操纵该状态(以便下一个命令可以将其保存为撤消操作)并更新UI。

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

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