Не адаптируется пазл - капча 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>

Ответы (0 шт):