Я работаю над приложением, в котором на одной странице пользователь должен подписывать два раза на двух разных холстах. Ниже приведен фрагмент кода.
var canvas = document.getElementById('signature');
var ctx = canvas.getContext("2d");
var drawing = false;
var prevX, prevY;
var currX, currY;
var signature = document.getElementsByName('signature')[0];
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("mouseup", stop);
canvas.addEventListener("mousedown", start);
var canvas = document.getElementById('signature2');
var ctx = canvas.getContext("2d");
var drawing = false;
var prevX, prevY;
var currX, currY;
var signature2 = document.getElementsByName('signature2')[0];
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("mouseup", stop);
canvas.addEventListener("mousedown", start);
function start(e) {
drawing = true;
}
function stop() {
drawing = false;
prevX = prevY = null;
signature.value = canvas.toDataURL();
}
function draw(e) {
if (!drawing) {
return;
}
// Test for touchmove event, this requires another property.
var clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
var clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
currX = clientX - canvas.offsetLeft;
currY = clientY - canvas.offsetTop;
if (!prevX && !prevY) {
prevX = currX;
prevY = currY;
}
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
prevX = currX;
prevY = currY;
}
canvas#signature {
border: 2px solid black;
}
canvas#signature2 {
border: 2px solid black;
}
form>* {
margin: 10px;
}
<form method="post">
<input type="hidden" name="command" value="submit">
<div>
<input name="name" placeholder="Your name" />
</div>
<div>
<canvas id="signature" width="300" height="100"></canvas>
</div>
<div>
<input type="hidden" name="signature" />
</div>
<div>
<canvas id="signature2" width="300" height="100"></canvas>
</div>
<div>
<input type="hidden" name="signature2" />
</div>
<input type="submit" value="submit">
<form>
Проблема
Использование приведенного выше кода canvas работает только во втором поле, а в первом - не работает.
Как я могу нарисовать в обоих полях разные подписи?
Проблема в вашем JavaScript заключается в том, что вы дважды объявляете переменные. Первый var canvas
относится к первому элементу холста и через 12 строк после того, как та же переменная снова объявлена, теперь уже со вторым элементом холста. И то же самое касается всех остальных (глобальных) переменных.
Чтобы избежать этой проблемы, вам нужны либо разные переменные (например, var canvas1 = ...
и var canvas2 = ...
), либо вы избегаете использования глобальных переменных, потому что они не масштабируются и сбивают с толку. Альтернативой в этой ситуации является размещение переменных, которые вам нужны, в качестве свойств самого элемента холста. Примером может служить переменная drawing
, которая является свойством каждого элемента холста.
Все функции обратного вызова (start
, stop
и draw
) имеют параметр с именем e
(объект события). На этом объекте вы можете найти target
, который всегда относится к элементу холста, а на элементе холста вы можете найти drawing
(e.target.drawing
), который был определен заранее. То же самое верно для prevX
и prevY
, которые являются частью объекта с именем position
.
В функции обратного вызова draw()
вы можете видеть, что я нахожу контекст холста (ctx
), опять же на основе e.target
.
/*
find all the relavant canvas elements
and call forEach to loop through the array
*/
document.querySelectorAll('form canvas').forEach(canvas => {
// properties for the canvas element
canvas.drawing = false;
canvas.position = {
prevX: undefined,
prevY: undefined
};
// event listeners on the canvas element
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("mouseup", stop);
canvas.addEventListener("mousedown", start);
});
function start(e) {
e.target.drawing = true;
}
function stop(e) {
let canvas = e.target;
canvas.drawing = false;
canvas.position.prevX = canvas.position.prevY = null;
let id = canvas.id;
document.forms.form01[id].value = canvas.toDataURL();
}
function draw(e) {
let canvas = e.target;
let ctx = canvas.getContext("2d");
if (!canvas.drawing) {
return;
}
// Test for touchmove event, this requires another property.
let clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
let clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
let currX = clientX - canvas.offsetLeft;
let currY = clientY - canvas.offsetTop;
if (!canvas.position.prevX && !canvas.position.prevY) {
canvas.position.prevX = currX;
canvas.position.prevY = currY;
}
ctx.beginPath();
ctx.moveTo(canvas.position.prevX, canvas.position.prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
canvas.position.prevX = currX;
canvas.position.prevY = currY;
}
canvas#signature {
border: 2px solid black;
}
canvas#signature2 {
border: 2px solid black;
}
form>* {
margin: 10px;
}
<form name="form01" method="post">
<input type="hidden" name="command" value="submit">
<div>
<input name="name" placeholder="Your name" />
</div>
<div>
<canvas id="signature" width="300" height="100"></canvas>
</div>
<div>
<input type="hidden" name="signature" />
</div>
<div>
<canvas id="signature2" width="300" height="100"></canvas>
</div>
<div>
<input type="hidden" name="signature2" />
</div>
<input type="submit" value="submit">
</form>
Нет, я просто исключил это в первую очередь. Теперь я добавил его снова. Я добавил имя в форму и добавил строку в функцию остановки, где URL-адрес данных добавляется как значение в скрытые поля.
это нормально, но почему я не получаю обе подписи после отправки формы?