javascript - 为绘画程序创建 'History Panel'

标签 javascript html canvas undo revision-history

我正在使用 HTML5/Canvas 制作一个非常简单的“像素绘画”程序。 我想为用户提供返回“历史记录”的选项,例如 Photoshop/Adobe 程序中的“历史记录”面板。

基本上,它是一个撤消按钮,但您可以返回到操作的开始处,并且还会有一个日志显示每个操作的详细信息。

这可能吗?我该如何开始存储这些数据?

Chrome 浏览器中有多少可用内存才能在一页上实现此操作? –(抱歉,如果问这个问题很愚蠢,对于 Javascript 和在浏览器中工作仍然很陌生。)

我已阅读this undo button Question ,这很相似,但我想让有关存储的数据的信息可见。

非常感谢您提供的任何帮助!

最佳答案

您需要构建一个简单的撤消重做堆栈。然后您需要决定是否存储矢量数据或图像数据。后者效率更高,但也会占用更多内存。您可能会遇到想要存储两种类型的数据(图像顶部的路径)的情况。

该方法的步骤很简单:

  • 存储新文档的初始状态。保持堆栈指针指向下一个空闲槽(例如使用数组)。
  • 当按下鼠标(或启动其他一些会导致更改的操作)时,向前移动堆栈指针。
  • 释放鼠标按钮时,制作快照、创建缩略图等。是否要将绘图存储为点或位图取决于您。如果位图数据,您可以通过使用例如 zip 压缩它来绕过存储空间。 。向前移动堆栈指针。如果此时堆栈中存在快照,请将其删除。
  • 当您需要撤消时,只需撤回先前存储的步骤并将堆栈指针向后移动即可。通过保留快照,您可以通过向前移动堆栈指针来重做并重绘快照(如果有)。
  • 最后,要可视化撤消重做堆栈,您只需按比例将每个快照渲染到单独的 Canvas 上,然后将其提取为放入列表中的图像即可。

注意:创建撤消状态时,清除新堆栈指针位置之后的所有快照非常重要。这是因为如果已经使用了undo,那么如果没有发生任何变化就可以使用redo。但是,如果使用撤消并添加新绘图,这将使下一个状态无效,因此必须将它们删除。

至于浏览器内存,这取决于用户的系统。有些有几千兆字节,有些则有很多。没有办法知道。您必须选择适合您的场景以及目标受众的用户体验策略。

示例

这并没有实现处理缩略图同步的逻辑,但具有大多数其他部分。我将剩下的作为练习。

var ctx = c.getContext("2d"),
    stack = [],                  // undo-redo stack
    sp = 0,                      // stack pointer
    isDown = false;              // for drawing (demo)

capture();                       // create an initial undo capture (blank)

ctx.lineCap = "round";           // setup line for demo
ctx.lineWidth = 4;

// simple draw mechanism
c.onmousedown = function(e) {
  sp++;                          // on mouse down, move stack pointer to next slot
  isDown = true;                 // NOTE: clear any snapshots after this point (not shown)
  var pos = getXY(e);            // start drawing some line - how you draw is up to you
  ctx.beginPath();
  ctx.moveTo(pos.x, pos.y);
}

window.onmousemove = function(e) {
  if (!isDown) return;           // only for drawing
  var pos = getXY(e);
  ctx.lineTo(pos.x, pos.y);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(pos.x, pos.y);
}

window.onmouseup = function() {
  if (!isDown) return;
  isDown = false;
  capture();                     // capture an undo state
  makeThumb();                   // create and insert a thumbnail of state
};

function capture() {
  stack[sp] = c.toDataURL();     // one way, you could use getImageData, 
                                 // or store points instead.. it's up to you
}

// Creates a thumbnail of current canvas and insert into visible undo stack
function makeThumb() {
  var canvas = document.createElement("canvas");
  canvas.width = canvas.height = 64;
  var ctxTmp = canvas.getContext("2d");
  ctxTmp.drawImage(c, 0, 0, canvas.width, canvas.height);
  undos.appendChild(canvas);
}

// UNDO button clicked
undo.onclick = function() {
  var img = new Image;           // restore previous state/snapshot
  img.onload = function() {
    ctx.clearRect(0, 0, c.width, c.height);
    ctx.drawImage(this, 0, 0);
  }
  
  // move stack pointer back and get previous snapshot
  if (sp > 0) img.src = stack[--sp];
};

// REDO button clicked
redo.onclick = function() {
  
  // anything we can redo?
  if (sp < stack.length) {
    var img = new Image;
    img.onload = function() {
      ctx.clearRect(0, 0, c.width, c.height);
      ctx.drawImage(this, 0, 0);
    }
  
    // move stack pointer forward and get next snapshot
    img.src = stack[++sp];
  }
};

function getXY(e) {
  var r = c.getBoundingClientRect();
  return {x: e.clientX - r.left, y: e.clientY - r.top}
}
#c {background:#ccc}
<button id=undo>Undo</button>
<button id=redo>Redo</button><br>
<canvas id=c width=500 height=500></canvas>
<div id=undos></div>

关于javascript - 为绘画程序创建 'History Panel',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37141406/

相关文章:

javascript - 如何使用node.js和gm检查损坏的jpg图像?

javascript - 选择除父级的第一个具有 ID 的子级之外的所有子级,然后应用操作

javascript - MEAN 堆栈 docker 容器在 OS X 和 DigitalOcean 上具有相同配置的最简单设置是什么?

javascript - 修改光标 'lags'

javascript - 如何制作这个 Gauge 微分 Angular ?

jquery - 需要 html5 和 jQuery submit()

javascript - 如何使用点击事件检测 Canvas 上的对象

javascript - 在字符串连接中添加换行符

html - openlayers 3 : how to draw sth using canvas. getContext ('2d' ) 在 map 顶部

ios - Canvas getImageData 不适用于 Mobile Safari