Javascript 如何使用数组添加撤消列表?

Javascript 如何使用数组添加撤消列表?,javascript,arrays,html5-canvas,undo,Javascript,Arrays,Html5 Canvas,Undo,我正在尝试用JavaScript制作一个绘画程序,我想包括一个撤销功能(而不是橡皮擦)。如何将所有事件添加到一个数组中,然后逐个删除它们 我有一个工具的下拉列表(到目前为止只有四个工具在工作)。我添加了一个id为的撤销按钮。我已经尝试了几个小时(事实上是几天)来找出如何做到这一点。我已经找到了一些例子,我想我必须同时使用push和空数组才能更进一步 这是刀具选择和按钮的代码 <label> Object type: <select id="selectTool"&g

我正在尝试用JavaScript制作一个绘画程序,我想包括一个撤销功能(而不是橡皮擦)。如何将所有事件添加到一个数组中,然后逐个删除它们

我有一个工具的下拉列表(到目前为止只有四个工具在工作)。我添加了一个id为的撤销按钮。我已经尝试了几个小时(事实上是几天)来找出如何做到这一点。我已经找到了一些例子,我想我必须同时使用push和空数组才能更进一步

这是刀具选择和按钮的代码

<label>
  Object type:
    <select id="selectTool">
        <option value="line">Linje</option>
        <option value="pencil">Blyant</option>
        <option value="rect">Rektangel</option>
        <option value="circle">Sirkel</option>
        <option value="oval">Oval</option>
        <option value="polygon">Polygon</option>
    </select>

  Shape drawn:
    <select id="shapeDrawn">
        <option value=""></option>
    </select>   

  <input type="button" id="cmbDelete" value="Undo last action">

</label>

理想情况下,画布上绘制的所有内容都会添加到下拉菜单中,​点击一个按钮就可以删除(撤消)。这是代码的“工作”版本

您当前的实现没有使用
形状
数组,并且在创建形状后无法重新绘制它们

因此,最容易将每个动作存储为位图。 因此,位图需要一个数组,我们称之为:

var history = [];
一旦绘制了某些内容,我们将创建当前画布的快照并将其存储在该数组中:

history.push(contextTmp.getImageData(0,0,canvasTmp.width,canvasTmp.height))
要撤消操作时,请弹出历史记录并在画布上绘制最后一个位图:

function cmbDeleteClick(){
    history.pop()
    contextTmp.putImageData(history[history.length-1],0,0)
}

油漆
#内容{位置:相对;}
#cvs{border:1px solid#c00;}
#cvsTmp{位置:绝对;顶部:1px;左侧:1px;}

对象类型:
林杰
布莱恩特
雷克坦格尔
瑟克尔
椭圆形
多边形
绘制的形状:
历史:

if(window.addEventListener){ window.addEventListener('load',函数(){ var帆布; var语境; var canvasTmp; var-contextTmp; var工具; var-toolDefault='line'; var=null; 变量形状=[]; var历史=[]; 变量历史选择; //画布和临时画布 函数init(){ canvasTmp=document.getElementById('cvs'); 如果(!canvasTmp){ 返回; }如果(!canvasTmp.getContext){ 返回; } historySelect=document.getElementById('historySelect') historySelect.addEventListener('change',()=>{ restoreHistoryAction(historySelect.value) }) contextTmp=canvasTmp.getContext('2d'); 如果(!contextTmp){ 返回; } //添加临时画布。 var content=canvasTmp.parentNode; canvas=document.createElement('canvas'); 如果(!画布){ 返回; } canvas.id='cvsTmp'; canvas.width=canvasTmp.width; canvas.height=canvasTmp.height; content.appendChild(画布); context=canvas.getContext('2d'); //获取工具选择输入。 var toolSelect=document.getElementById('selectTool'); 如果(!工具选择){ 返回; } toolSelect.addEventListener('change',ev_tool_change,false); //激活默认工具。 如果(工具[toolDefault]){ 工具=新工具[toolDefault](); toolSelect.value=工具默认值; } //附加mousedown、mousemove和mouseup事件侦听器。 canvas.addEventListener('mousedown',evMouse,false); canvas.addEventListener('mousemove',evMouse,false); canvas.addEventListener('mouseup',evMouse,false); drawCanvas() } 功能ev鼠标(ev){ 如果(ev.layerX | ev.layerX==0){ ev._x=ev.layerX; ev._y=ev.layerY; } var evHandler=tool[ev.type]; if(evHandler){ evHandler(ev); } } //对工具选择器所做的任何更改的事件处理程序。 功能工具更改(ev){ if(工具[this.value]){ 工具=新工具[this.value](); } } //在间隔超时时更新画布 函数drawCanvas(){ contextTmp.drawImage(画布,0,0); history.push(contextTmp.getImageData(0,0,canvasTmp.width,canvasTmp.height)) updateHistorySelection() clearRect(0,0,canvas.width,canvas.height); } 功能电动工具更换(ev){ if(工具[this.value]){ 工具=新工具[this.value](); } } //获取画布中鼠标坐标的EXACT位置 功能鼠标动作(ev){ 如果(ev.layerX | ev.layerX==0){ ev._x=ev.layerX; ev._y=ev.layerY; } //调用该工具的事件处理程序。 var func=工具[ev.type]; if(func){ func(ev); } } 函数selectShapeChange(){ 画布(); } var工具={}; //画笔。 tools.pencil=函数(){ var工具=这个; this.start=false; this.mousedown=函数(ev){ context.beginPath(); 上下文移动到(ev.\ux,ev.\uy); tool.started=true; }; this.mousemove=函数(ev){ 如果(工具启动){ 上下文行(ev.\ux,ev.\uy); stroke(); } }; this.mouseup=函数(ev){ 如果(工具启动){ 工具。鼠标移动(ev); tool.start=false; 画布(); } }; }; //矩形工具。 tools.rect=函数(){ var工具=这个; this.start=false; this.mousedown=函数(ev){ tool.started=true; 工具x0=ev.\u x; 工具y0=ev.\u y; }; this.mousemove=函数(ev){ 如果(!tool.started){ 返回; } var x=数学最小值(ev._x,tool.x0), y=数学最小值(ev._y,工具y0), w=Math.abs(ev.\ux-tool.x0), h=数学绝对值(ev._y-工具y0); clearRect(0,0,canvas.width,canvas.height); 如果(!w | |!h){ 返回; } fillRect(x,y,w,h); context.fillStyle='hsl('+360*Math.random()+',50%,50%); }; this.mouseup=函数(ev){ 如果(工具启动){ 工具。鼠标移动(ev); tool.start=false; 画布(); } }; }; //线条工具。 tools.line=函数(){ var工具=这个; this.start=false; this.mousedown=函数(ev){ tool.started=true; 工具x0=ev.\u x; 工具y0=ev.\u y; }; this.mousemove=函数(ev){ 如果(!tool.started){ 返回; }
function cmbDeleteClick(){
    history.pop()
    contextTmp.putImageData(history[history.length-1],0,0)
}
function undoLastChange() {
  const canvas = document.getElementById('canvas_ID');
  const ctx = canvas.getContext('2d');
  const img = new Image();
  img.onload = () => {
    ctx.drawImage(img, 0, 0);
  };
  img.src = undoArray.pop();
}