gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 01:03:12 26 4
gpt4 key购买 nike

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

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

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

<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 shapes = [];
shapes.push(newShape);


function cmbDeleteClick(){
if(shapes.length > 0){
var selectedShapeIndex = selectShape.selectedIndex;
shapes.splice(selectedShapeIndex,1);
selectShape.options.remove(selectedShapeIndex);
selectShape.selectedIndex = selectShape.options.length - 1;
}
cmbDelete = document.getElementById("cmbDelete");
cmbDelete.addEventListener("click",cmbDeleteClick, false);
fillSelectShapeTypes();
drawCanvas();
}

理想情况下, Canvas 上绘制的所有内容都会添加到下拉菜单中,并且可以通过单击按钮将其删除(撤消)。这是代码 JS Bin 的“工作”版本

最佳答案

您当前的实现不使用 shapes 数组,并且无法在创建它们后重新绘制它们。

因此,将每个操作存储为位图是最简单的。因此,您需要一个位图数组,我们称之为:

var history = [];

一旦绘制了一些东西,我们就会创建当前 Canvas 的快照并将其存储在该数组中:

history.push(contextTmp.getImageData(0,0,canvasTmp.width,canvasTmp.height))

当您想要撤消操作时,弹出历史记录并在 Canvas 上绘制最后一个位图:

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Paint</title>
<style type="text/css">
#content { position: relative; }
#cvs { border: 1px solid #c00; }
#cvsTmp { position: absolute; top: 1px; left: 1px; }
</style>
</head>
<body>
<p>

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

History:
<select id="historySelect">
</select>

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

</label>

</p>

<div id="content">
<canvas id="cvs" width="1024" height="512"></canvas>
</div>

<script type="text/javascript">


if(window.addEventListener) {
window.addEventListener('load', function () {
var canvas;
var context;
var canvasTmp;
var contextTmp;

var tool;
var toolDefault = 'line';

var cmbDelete = null;
var shapes = [];
var history = [];
var historySelect;

// Canvas and temp. canvas

function init () {
canvasTmp = document.getElementById('cvs');
if (!canvasTmp) {
return;
} if (!canvasTmp.getContext) {
return;
}

historySelect = document.getElementById('historySelect')
historySelect.addEventListener('change', ()=>{
restoreHistoryAction(historySelect.value)
})

contextTmp = canvasTmp.getContext('2d');
if (!contextTmp) {
return;
}

// Add the temporary canvas.
var content = canvasTmp.parentNode;
canvas = document.createElement('canvas');
if (!canvas) {
return;
}

canvas.id = 'cvsTmp';
canvas.width = canvasTmp.width;
canvas.height = canvasTmp.height;
content.appendChild(canvas);

context = canvas.getContext('2d');


// Get the tool select input.
var toolSelect = document.getElementById('selectTool');
if (!toolSelect) {
return;
}
toolSelect.addEventListener('change', ev_tool_change, false);

// Activate the default tool.
if (tools[toolDefault]) {
tool = new tools[toolDefault]();
toolSelect.value = toolDefault;
}

// Attach the mousedown, mousemove and mouseup event listeners.
canvas.addEventListener('mousedown', evMouse, false);
canvas.addEventListener('mousemove', evMouse, false);
canvas.addEventListener('mouseup', evMouse, false);

drawCanvas()
}

function evMouse (ev) {
if (ev.layerX || ev.layerX == 0) {
ev._x = ev.layerX;
ev._y = ev.layerY;
}
var evHandler = tool[ev.type];
if (evHandler) {
evHandler(ev);
}
}

// The event handler for any changes made to the tool selector.
function toolChange (ev) {
if (tools[this.value]) {
tool = new tools[this.value]();
}
}


// Updates Canvas on interval timeout
function drawCanvas() {
contextTmp.drawImage(canvas, 0, 0);
history.push(contextTmp.getImageData(0,0,canvasTmp.width,canvasTmp.height))
updateHistorySelection()
context.clearRect(0, 0, canvas.width, canvas.height);
}

function ev_tool_change (ev) {
if (tools[this.value]) {
tool = new tools[this.value]();
}
}

// Get excact position for mouse coordinates in canvas
function mouseAction (ev) {
if (ev.layerX || ev.layerX == 0) {
ev._x = ev.layerX;
ev._y = ev.layerY;
}

// Call the event handler of the tool.
var func = tool[ev.type];
if (func) {
func(ev);
}
}


function selectShapeChange(){
drawCanvas();
}





var tools = {};

// The drawing pencil.
tools.pencil = function () {
var tool = this;
this.started = false;

this.mousedown = function (ev) {
context.beginPath();
context.moveTo(ev._x, ev._y);
tool.started = true;
};

this.mousemove = function (ev) {
if (tool.started) {
context.lineTo(ev._x, ev._y);
context.stroke();
}
};

this.mouseup = function (ev) {
if (tool.started) {
tool.mousemove(ev);
tool.started = false;
drawCanvas();
}
};
};

// The rectangle tool.
tools.rect = function () {
var tool = this;
this.started = false;

this.mousedown = function (ev) {
tool.started = true;
tool.x0 = ev._x;
tool.y0 = ev._y;
};

this.mousemove = function (ev) {
if (!tool.started) {
return;
}

var x = Math.min(ev._x, tool.x0),
y = Math.min(ev._y, tool.y0),
w = Math.abs(ev._x - tool.x0),
h = Math.abs(ev._y - tool.y0);

context.clearRect(0, 0, canvas.width, canvas.height);

if (!w || !h) {
return;
}
context.fillRect(x, y, w, h);
context.fillStyle = 'hsl(' + 360 * Math.random() + ', 50%, 50%)';
};

this.mouseup = function (ev) {
if (tool.started) {
tool.mousemove(ev);
tool.started = false;
drawCanvas();
}
};
};

// The line tool.
tools.line = function () {
var tool = this;
this.started = false;

this.mousedown = function (ev) {
tool.started = true;
tool.x0 = ev._x;
tool.y0 = ev._y;
};

this.mousemove = function (ev) {
if (!tool.started) {
return;
}

context.clearRect(0, 0, canvas.width, canvas.height);

context.beginPath();
context.moveTo(tool.x0, tool.y0);
context.lineTo(ev._x, ev._y);
context.stroke();
context.closePath();
};

this.mouseup = function (ev) {
if (tool.started) {
tool.mousemove(ev);
tool.started = false;
drawCanvas();
}
};
};

// Circle tool
tools.circle = function () {
var tool = this;
this.started = false;

this.mousedown = function (ev) {
tool.started = true;
tool.x0 = ev._x;
tool.y0 = ev._y;
};

this.mousemove = function (ev) {
if (!tool.started) {
return;
}

context.clearRect(0, 0, canvas.width, canvas.height);

var radius = Math.max(
Math.abs(ev._x - tool.x0),
Math.abs(ev._y - tool.y0)
) / 2;

var x = Math.min(ev._x, tool.x0) + radius;
var y = Math.min(ev._y, tool.y0) + radius;

context.beginPath();
context.arc(x, y, radius, 0, Math.PI*2, false);
// context.arc(x, y, 5, 0, Math.PI*2, false);
context.stroke();
context.closePath();

};

this.mouseup = function (ev) {
if (tool.started) {
tool.mousemove(ev);
tool.started = false;
drawCanvas();
}
};
};

// Ellipse/oval tool

// Polygon tool

// Undo button

function cmbDeleteClick(){
if(history.length<=1)
return

history.pop()
contextTmp.putImageData(history[history.length-1],0,0)
updateHistorySelection()
}

function updateHistorySelection(){
historySelect.innerHTML = ''

history.forEach((entry,index)=>{
let option = document.createElement('option')
option.value = index
option.textContent = index===0 ? 'Beginning' : 'Action '+index
historySelect.appendChild(option)
})

historySelect.selectedIndex = history.length-1
}

function restoreHistoryAction(index){
contextTmp.putImageData(history[index],0,0)
}

cmbDelete = document.getElementById("cmbDelete");
cmbDelete.addEventListener("click",cmbDeleteClick, false);

init();

}, false); }


</script>
</body>
</html>

但这并不是很有效。它将为每个操作存储 Canvas 的完整位图,因此非常消耗内存。最好让绘图工具实际创建一个形状实例,可以调用该实例在 Canvas 上按需重绘。

关于javascript - 如何使用数组添加撤消列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55871586/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com