我正在尝试在JavaScript中创建一个goBack()函数,它基本上是一个撤销按钮。例如:用户拖放1个图像并绘制2条线。goBack()函数应该一次删除一条线,然后删除图像。我的函数删除线和图像,但不是按顺序。它首先删除图像,即使它是第一个拖动的东西。为了更好地理解,下面是代码。
//Javascript per la creazione di cirucuiti elettrici
const NUMERO_CICLO = 990;
const NUMERO_CICLO_INTERNO = 60;
const resistor = document.getElementById('component_circuit_resistor');
const condensator = document.getElementById('component_circuit_condensator');
const tranistor = document.getElementById('component_circuit_tranistor');
const alimentator = document.getElementById('component_circuit_alimentator');
const circuit = document.getElementById('components_circuit');
const back_button = document.getElementById('back-button');
const clear_button = document.getElementById('clear-button');
const draggable = document.querySelectorAll('.draggable');
const container = document.querySelectorAll('.container');
const canvas = document.getElementById('canvas');
const foward_button = document.getElementById('foward-button');
/** EDIT START */
const draggableImages = document.querySelectorAll('img[draggable]');
for (let i = 0; i < draggableImages.length; i++)
draggableImages[i].ondragstart = (ev) => {
ev.dataTransfer.setData('text/plain', i.toString());
};
canvas.ondragover = (ev) => ev.preventDefault(); // IMPORTANT
const drawnImageData = [];
const deletedImageData = [];
canvas.ondrop = (ev) => {
const index = parseInt(ev.dataTransfer.getData('text/plain'));
const img = draggableImages[index];
drawnImageData.push({ img, x: ev.offsetX, y: ev.offsetY });
};
clear_button.disabled = true;
clear_button.style.cursor = 'not-allowed';
foward_button.disabled = true;
foward_button.style.cursor = 'not-allowed';
back_button.disabled = true;
back_button.style.cursor = 'not-allowed';
/** EDIT END */
canvas.width = 1500;
canvas.height = 855;
canvas.style.backgroundColor = 'lightgrey';
circuit.appendChild(canvas);
canvas.style.borderRadius = '10px';
canvas.style.marginLeft = 'auto';
canvas.style.marginRight = 'auto';
canvas.style.display = 'block';
const ctx = canvas.getContext('2d');
const circles = [];
const lines = [];
const lines_c = [];
var deletedLines = [];
for (let y = 20; y <= NUMERO_CICLO; y += 20) {
for (let i = 0; i < NUMERO_CICLO_INTERNO; i++) {
circles.push({
x: 13 + i * 25,
y,
radius: 5,
color: 'grey',
});
}
}
let startCircle = null;
let endCircle = null;
var priorita = null;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
circles.forEach((circle) => {
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
ctx.fillStyle = circle.color;
ctx.fill();
});
lines.forEach((line) => {
ctx.beginPath();
ctx.lineWidth = 4;
ctx.moveTo(line.start.x, line.start.y);
ctx.lineTo(line.end.x, line.end.y);
ctx.stroke();
});
if (startCircle && endCircle) {
ctx.beginPath();
ctx.lineWidth = 4;
ctx.moveTo(startCircle.x, startCircle.y);
ctx.lineTo(endCircle.x, endCircle.y);
ctx.stroke();
}
/** EDIT START */
for (const data of drawnImageData)
ctx.drawImage(data.img, data.x, data.y, data.img.width, data.img.height);
/** EDIT END */
requestAnimationFrame(draw);
if(drawnImageData.length > 0 || lines.length > 0){
clear_button.disabled = false;
clear_button.style.cursor = 'pointer';
back_button.disabled = false;
back_button.style.cursor = 'pointer';
}
}
draw();
function goBack() {
if (drawnImageData.length > 0) {
deletedImageData.push(drawnImageData.pop());
}
else if (lines.length > 0) {
deletedLines.push(lines.pop());
}
// Check if there are any items left to undo
if (drawnImageData.length === 0 && lines.length === 0) {
back_button.disabled = true;
back_button.style.cursor = 'not-allowed';
clear_button.disabled = true;
clear_button.style.cursor = 'not-allowed';
}
// Enable the forward button
foward_button.disabled = false;
foward_button.style.cursor = 'pointer';
}
function goFoward() {
if (deletedImageData.length > 0) {
drawnImageData.push(deletedImageData.pop());
} else if (deletedLines.length > 0) {
lines.push(deletedLines.pop());
}
// Check if there are any items left to redo
if (deletedImageData.length === 0 && deletedLines.length === 0) {
foward_button.disabled = true;
foward_button.style.cursor = 'not-allowed';
}
// Enable the back button
back_button.disabled = false;
back_button.style.cursor = 'pointer';
}
function clearCanvas() {
if (confirm('Are you sure you want to delete the circuit?')) {
lines.length = 0;
deletedLines.length = 0;
lastDeleted = null;
// clear drawn images data
drawnImageData.length = 0;
clear_button.disabled = true;
clear_button.style.cursor = 'not-allowed';
foward_button.disabled = true;
foward_button.style.cursor = 'not-allowed';
back_button.disabled = true;
back_button.style.cursor = 'not-allowed';
}
}
function getNearestCircle(x, y) {
let nearestCircle = null;
let nearestDistance = Infinity;
circles.forEach((circle) => {
const distance = Math.sqrt((circle.x - x) ** 2 + (circle.y - y) ** 2);
if (distance < nearestDistance && distance < 30) {
nearestCircle = circle;
nearestDistance = distance;
}
});
return nearestCircle;
}
let isDrawing = false;
canvas.addEventListener('mousedown', (event) => {
const x = event.offsetX;
const y = event.offsetY;
const circle = getNearestCircle(x, y);
if (circle) {
startCircle = circle;
endCircle = { x, y };
isDrawing = true;
}
});
canvas.addEventListener('mousemove', (event) => {
if (isDrawing) {
endCircle.x = event.offsetX;
endCircle.y = event.offsetY;
} else {
const x = event.offsetX;
const y = event.offsetY;
const circle = getNearestCircle(x, y);
if (circle) {
circles.forEach((circle) => {
circle.color = 'grey';
});
circle.color = 'red';
} else {
circles.forEach((circle) => {
circle.color = 'grey';
});
}
}
});
canvas.addEventListener('mouseup', () => {
if (isDrawing) {
const x = endCircle.x;
const y = endCircle.y;
const circle = getNearestCircle(x, y);
if (circle) {
lines.push({
start: startCircle,
end: circle,
});
}
isDrawing = false;
startCircle = null;
endCircle = null;
}
});
//back_button.addEventListener("click", goBack);
//foward_button.addEventListener("click", goBack);
clear_button.addEventListener('click', clearCanvas);
var back_clicked = false;
back_button.addEventListener('click', function () {
back_clicked = true;
goBack();
back_clicked = false;
});
var foward_clicked = false;
foward_button.addEventListener('click', function () {
foward_clicked = true;
goFoward();
foward_clicked = false;
});
<h1 id="h1_titolo">From Circuit to Breadboard</h1>
<div class="container">
<div class="components">
<div id="components_circuit">
<h3 id="h3_componenti_circuit">Componenti:</h3>
<ul id="components_circuit_border">
<li>
<img
id="component_circuit_resistor"
src="https://i.kym-cdn.com/entries/icons/original/000/006/428/637738.jpg"
height="50"
draggable
/>
</li>
<br /><br />
<li>
<img
id="component_circuit_condensator"
src="https://ftw.usatoday.com/wp-content/uploads/sites/90/2017/05/spongebob.jpg"
height="50"
draggable
/>
</li>
<br /><br />
<li>
<img
id="component_circuit_transistor"
src="https://pyxis.nymag.com/v1/imgs/0f9/f96/029acbf4c6d8c67e138e1eb06a277204bf-05-patrick.rsquare.w700.jpg"
height="50"
draggable
/>
</li>
<br /><br />
</ul>
<div class="elementi_disegno">
<h1 id="h1_disegna">Disegna il tuo circuito!</h1>
<button id="back-button">
Indietro
<span class="material-symbols-outlined">undo</span>
</button>
<button id="foward-button">
Avanti
<span class="material-symbols-outlined">redo</span>
</button>
<button id="clear-button">
Clear All
<span class="material-symbols-outlined">delete</span>
</button>
<canvas id="canvas" class="dropzone"></canvas>
</div>
</div>
1条答案
按热度按时间m3eecexj1#
这是因为你没有保存执行的顺序。在
goBack()
函数中,如果数组不为空,你总是首先尝试从drawnImageData
数组中删除,即使最近的执行是绘制线条。我会通过创建另一个数组来保持执行顺序,如下所示:以下是更新后的片段: