Не адаптируется пазл - капча js под касания на мобильном устройстве
Решил написать простенький скрипт пазлов для капчи, столкнулся с проблемой, не могу адаптировать движения мыши для тача на телефоне. На компьютерной версии всё работает плавно, на телефоне - вообще почти не работает (детали пазла не перетаскиваются). В чём ошибка? Заранее спасибо!
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Капча</title>
<script>
var is_touch = navigator.maxTouchPoints && navigator.maxTouchPoints > 0;
const PUZZLE_DIFFICULTY = 3;
const PUZZLE_HOVER_TINT = '#000099';
var ctx, canvas, img, pieces, mainWidth, mainHeight, pieceWidth, pieceHeight, currentPiece, currentDroppedPiece, mouse, touch;
var count = 0, maxCount = 0, gamesCount = 0;
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
function init() {
img = new Image();
let img_gen = ['https://biarby.ru/test/test/captcha-new/img/1.jpg', 'https://biarby.ru/test/test/captcha-new/img/2.jpg', 'https://biarby.ru/test/test/captcha-new/img/3.jpg', 'https://biarby.ru/test/test/captcha-new/img/4.jpg', 'https://biarby.ru/test/test/captcha-new/img/5.jpg'];
let i = getRandomInt(0, 5);
img.src = img_gen[i];
img.addEventListener('load',onImage,false);
}
function onImage (e) {
pieceWidth = Math.floor (img.width / PUZZLE_DIFFICULTY)
pieceHeight = Math.floor (img.height / PUZZLE_DIFFICULTY)
mainWidth = pieceWidth * PUZZLE_DIFFICULTY;
mainHeight = pieceHeight * PUZZLE_DIFFICULTY;
setCanvas ();
initPuzzle ();
}
function setCanvas(){
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
canvas.width = mainWidth;
canvas.height = mainHeight;
canvas.style.border = "1px solid green";
}
function initPuzzle(){
pieces = [];
mouse = {x:0,y:0};
touch = {x:0,y:0};
currentPiece = null;
currentDroppedPiece = null;
ctx.drawImage(img, 0, 0, mainWidth, mainHeight, 0, 0, mainWidth, mainHeight);
if (!gamesCount) createTitle("Нажми, чтобы пройти капчу");
buildPieces();
}
function createTitle (msg) {
ctx.fillStyle = "#000000";
ctx.globalAlpha = .5;
ctx.fillRect (100,mainHeight - 40,mainWidth - 200,40);
ctx.fillStyle = "#FFFFFF";
ctx.globalAlpha = 1;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "20px Arial";
ctx.fillText(msg,mainWidth / 2,mainHeight - 20);
}
function buildPieces(){
var i, piece, xPos = 0, yPos = 0;
for (i = 0;i < PUZZLE_DIFFICULTY * PUZZLE_DIFFICULTY;i++) {
piece = {}; piece.sx = xPos; piece.sy = yPos; pieces.push(piece);
xPos += pieceWidth;
if (xPos >= mainWidth) {
xPos = 0; yPos += pieceHeight;
}
}
document.onmousedown = shufflePuzzle;
document.ontouchstart = shufflePuzzle;
}
function shufflePuzzle() {
pieces = shuffleArray(pieces);
ctx.clearRect(0,0,mainWidth,mainHeight);
var i, piece, xPos = 0, yPos = 0;
for (i = 0;i < pieces.length;i++) {
piece = pieces[i]; piece.xPos = xPos; piece.yPos = yPos;
ctx.drawImage (img, piece.sx, piece.sy, pieceWidth, pieceHeight, xPos, yPos, pieceWidth, pieceHeight);
ctx.strokeRect (xPos, yPos, pieceWidth,pieceHeight);
xPos += pieceWidth;
if (xPos >= mainWidth){
xPos = 0; yPos += pieceHeight;
}
}
document.onmousedown = onPuzzleClick;
document.ontouchstart = onPuzzleClick;
}
function onPuzzleClick(e){
if (is_touch) {
if (e.layerX || e.layerX == 0){
touch.x = e.layerX - canvas.offsetLeft;
touch.y = e.layerY - canvas.offsetTop;
}
else if(e.offsetX || e.offsetX == 0) {
touch.x = e.offsetX - canvas.offsetLeft;
touch.y = e.offsetY - canvas.offsetTop;
}
currentPiece = checkPieceClicked();
if (currentPiece != null) {
ctx.clearRect (currentPiece.xPos,currentPiece.yPos,pieceWidth,pieceHeight);
ctx.save();
ctx.globalAlpha = .9;
ctx.drawImage (img, currentPiece.sx, currentPiece.sy, pieceWidth, pieceHeight,
touch.x - (pieceWidth / 2), touch.y - (pieceHeight / 2), pieceWidth, pieceHeight);
ctx.restore();
document.ontouchmove = updatePuzzle;
document.ontouchend = pieceDropped;
}
} else {
if (e.layerX || e.layerX == 0){
mouse.x = e.layerX - canvas.offsetLeft;
mouse.y = e.layerY - canvas.offsetTop;
}
else if(e.offsetX || e.offsetX == 0) {
mouse.x = e.offsetX - canvas.offsetLeft;
mouse.y = e.offsetY - canvas.offsetTop;
}
currentPiece = checkPieceClicked();
if (currentPiece != null) {
ctx.clearRect (currentPiece.xPos,currentPiece.yPos,pieceWidth,pieceHeight);
ctx.save();
ctx.globalAlpha = .9;
ctx.drawImage (img, currentPiece.sx, currentPiece.sy, pieceWidth, pieceHeight,
mouse.x - (pieceWidth / 2), mouse.y - (pieceHeight / 2), pieceWidth, pieceHeight);
ctx.restore();
document.onmousemove = updatePuzzle;
document.onmouseup = pieceDropped;
}
}
}
function checkPieceClicked() {
if (is_touch) {
var i, piece;
for (i = 0;i < pieces.length;i++) {
piece = pieces[i];
if (touch.x < piece.xPos || touch.x > (piece.xPos + pieceWidth) ||
touch.y < piece.yPos || touch.y > (piece.yPos + pieceHeight)) {
}
else return piece;
}
return null;
} else {
var i, piece;
for (i = 0;i < pieces.length;i++) {
piece = pieces[i];
if (mouse.x < piece.xPos || mouse.x > (piece.xPos + pieceWidth) ||
mouse.y < piece.yPos || mouse.y > (piece.yPos + pieceHeight)) {
}
else return piece;
}
return null;
}
}
function updatePuzzle (e) {
if (is_touch) {
currentDroppedPiece = null;
if (e.layerX || e.layerX == 0) {
touch.x = e.layerX - canvas.offsetLeft;
touch.y = e.layerY - canvas.offsetTop;
}
else if(e.offsetX || e.offsetX == 0) {
touch.x = e.offsetX - canvas.offsetLeft;
touch.y = e.offsetY - canvas.offsetTop;
}
ctx.clearRect (0,0,mainWidth,mainHeight);
var i, piece;
for (i = 0;i < pieces.length;i++) {
piece = pieces[i];
if (piece == currentPiece) continue;
ctx.drawImage (img, piece.sx, piece.sy, pieceWidth, pieceHeight, piece.xPos, piece.yPos, pieceWidth, pieceHeight);
ctx.strokeRect (piece.xPos, piece.yPos, pieceWidth,pieceHeight);
if (currentDroppedPiece == null){
if (touch.x < piece.xPos || touch.x > (piece.xPos + pieceWidth) ||
touch.y < piece.yPos || touch.y > (piece.yPos + pieceHeight)) {
}
else {
currentDroppedPiece = piece;
ctx.save();
ctx.globalAlpha = .33;
ctx.fillStyle = PUZZLE_HOVER_TINT;
ctx.fillRect(currentDroppedPiece.xPos,currentDroppedPiece.yPos,pieceWidth, pieceHeight);
ctx.restore();
}
}
}
ctx.save();
ctx.globalAlpha = .66;
ctx.drawImage(img, currentPiece.sx, currentPiece.sy, pieceWidth, pieceHeight,
touch.x - (pieceWidth / 2), touch.y - (pieceHeight / 2), pieceWidth, pieceHeight);
ctx.restore();
ctx.strokeRect( touch.x - (pieceWidth / 2), touch.y - (pieceHeight / 2), pieceWidth,pieceHeight);
} else {
currentDroppedPiece = null;
if (e.layerX || e.layerX == 0) {
mouse.x = e.layerX - canvas.offsetLeft;
mouse.y = e.layerY - canvas.offsetTop;
}
else if(e.offsetX || e.offsetX == 0) {
mouse.x = e.offsetX - canvas.offsetLeft;
mouse.y = e.offsetY - canvas.offsetTop;
}
ctx.clearRect (0,0,mainWidth,mainHeight);
var i, piece;
for (i = 0;i < pieces.length;i++) {
piece = pieces[i];
if (piece == currentPiece) continue;
ctx.drawImage (img, piece.sx, piece.sy, pieceWidth, pieceHeight, piece.xPos, piece.yPos, pieceWidth, pieceHeight);
ctx.strokeRect (piece.xPos, piece.yPos, pieceWidth,pieceHeight);
if (currentDroppedPiece == null){
if (mouse.x < piece.xPos || mouse.x > (piece.xPos + pieceWidth) ||
mouse.y < piece.yPos || mouse.y > (piece.yPos + pieceHeight)) {
}
else {
currentDroppedPiece = piece;
ctx.save();
ctx.globalAlpha = .33;
ctx.fillStyle = PUZZLE_HOVER_TINT;
ctx.fillRect(currentDroppedPiece.xPos,currentDroppedPiece.yPos,pieceWidth, pieceHeight);
ctx.restore();
}
}
}
ctx.save();
ctx.globalAlpha = .66;
ctx.drawImage(img, currentPiece.sx, currentPiece.sy, pieceWidth, pieceHeight,
mouse.x - (pieceWidth / 2), mouse.y - (pieceHeight / 2), pieceWidth, pieceHeight);
ctx.restore();
ctx.strokeRect( mouse.x - (pieceWidth / 2), mouse.y - (pieceHeight / 2), pieceWidth,pieceHeight);
}
}
function pieceDropped (e) {
document.onmousemove = null;
document.onmouseup = null;
document.ontouchmove = null;
document.ontouchend = null;
if (currentDroppedPiece != null) {
var tmp = {xPos:currentPiece.xPos,yPos:currentPiece.yPos};
currentPiece.xPos = currentDroppedPiece.xPos;
currentPiece.yPos = currentDroppedPiece.yPos;
currentDroppedPiece.xPos = tmp.xPos;
currentDroppedPiece.yPos = tmp.yPos;
count++;
}
resetPuzzleAndCheckWin();
}
function resetPuzzleAndCheckWin() {
ctx.clearRect (0,0,mainWidth,mainHeight);
var gameWin = true;
var i, piece;
for (i = 0;i < pieces.length;i++) {
piece = pieces[i];
ctx.drawImage(img, piece.sx, piece.sy, pieceWidth, pieceHeight, piece.xPos, piece.yPos, pieceWidth, pieceHeight);
ctx.strokeRect(piece.xPos, piece.yPos, pieceWidth,pieceHeight);
if (piece.xPos != piece.sx || piece.yPos != piece.sy) {
gameWin = false;
}
}
if (gameWin) {
setTimeout(gameOver,330);
}
}
function gameOver(){
document.onmousedown = null;
document.onmousemove = null;
document.onmouseup = null;
document.ontouchstart = null;
document.ontouchmove = null;
document.ontouchend = null;
gamesCount++;
initPuzzle();
if (maxCount == 0) maxCount = count;
createTitle ('Вы прошли капчу!');
if (count < maxCount) maxCount = count;
count = 0;
}
function shuffleArray (o) {
for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
</script>
<body onload="init();">
<canvas id="canvas" width="279" height="180" style="border: 1px solid green;"></canvas>
<script>var i = 1;</script>
<noscript>Нет js</noscript>
</body>
</html>