Search code examples
javascripthtmlcsscanvastouch

HTML Canvas help for touchscreen


Hi there Im working on a mobile specific website that involves the users drawing shapes and patterns on their mobile. Im having trouble implementing this for mobile The canvas drawing workings perfectly with desktop but not at all with touchscreen devices. Ive triedn using touch events but they dont seem to be working at all. Below is my code. Any help would be much appreciated

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>


<style>
canvas { border: 5px solid blue }

</style>

</head>
<body>
<canvas id="c" width="500" height="300"></canvas>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>


<script>
function midPointBtw(p1, p2) {
  return {
    x: p1.x + (p2.x - p1.x) / 2,
    y: p1.y + (p2.y - p1.y) / 2
  };
 }

function getPattern() {
  return ctx.createPattern(img, 'repeat');
 }


var el = document.getElementById('c');
var ctx = el.getContext('2d');

ctx.lineWidth = 50;
ctx.lineJoin = ctx.lineCap = 'round';

var img = new Image;
img.onload = function() {
  ctx.strokeStyle = getPattern();
};
img.src = "dick2.png";

var isDrawing, points = [ ];

el.ontouchstart = function(e) {
  isDrawing = true;
  points.push({ x: e.clientX, y: e.clientY });

};

el.ontouchmove = function(e) {
  if (!isDrawing) return;

  points.push({ x: e.clientX, y: e.clientY });
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

  var p1 = points[0];
  var p2 = points[1];

  ctx.beginPath();
  ctx.moveTo(p1.x, p1.y);

  for (var i = 1, len = points.length; i < len; i++) {
    var midPoint = midPointBtw(p1, p2);
    ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);
    p1 = points[i];
    p2 = points[i+1];
  }
  ctx.lineTo(p1.x, p1.y);
  ctx.stroke();
};

el.onmouseup = function() {
  isDrawing = false;
  points.length = 0;
};




function showInput() {
document.getElementById('display').innerHTML = 
document.getElementById("user_input").value;
    }







</script>


<form id ="search">
<input type = "text" name="message" id="user_input">
<input type = "button" value= "Submit" onclick="showInput();">
</form>



<p><span id='display'></span></p>

</body>
</html>

Solution

  • Touch events work differently compared to mouse events. Instead of just clientX and clientY being on the event itself, due to touchscreens being able to support multiple touch points at various sensitivities, they are accessible in a different location, under touches. If you only care about the first touch in the list, you can make your code compatible with both desktop and mobile fairly easily with minimal changes:

    function midPointBtw(p1, p2) {
      return {
        x: p1.x + (p2.x - p1.x) / 2,
        y: p1.y + (p2.y - p1.y) / 2
      };
    }
    
    function getPattern() {
      return ctx.createPattern(img, 'repeat');
    }
    
    
    var el = document.getElementById('c');
    var ctx = el.getContext('2d');
    
    ctx.lineWidth = 50;
    ctx.lineJoin = ctx.lineCap = 'round';
    
    var img = new Image;
    img.onload = function() {
      ctx.strokeStyle = getPattern();
    };
    img.src = "https://placekitten.com/200";
    
    var isDrawing, points = [];
    
    var getXY = function(e) {
      var source = e.touches ? e.touches[0] : e;
    
      return {
        x: source.clientX,
        y: source.clientY
      };
    };
    
    var startDrawing = function(e) {
      isDrawing = true;
      points.push(getXY(e));
    };
    var keepDrawing = function(e) {
      if (!isDrawing) return;
    
      points.push(getXY(e));
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    
      var p1 = points[0];
      var p2 = points[1];
    
      ctx.beginPath();
      ctx.moveTo(p1.x, p1.y);
    
      for (var i = 1, len = points.length; i < len; i++) {
        var midPoint = midPointBtw(p1, p2);
        ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);
        p1 = points[i];
        p2 = points[i + 1];
      }
      ctx.lineTo(p1.x, p1.y);
      ctx.stroke();
    };
    var stopDrawing = function() {
      isDrawing = false;
      points = [];
    };
    
    el.addEventListener('touchstart', startDrawing);
    el.addEventListener('mousedown', startDrawing);
    
    el.addEventListener('touchmove', keepDrawing);
    el.addEventListener('mousemove', keepDrawing);
    
    el.addEventListener('touchend', stopDrawing);
    el.addEventListener('mouseup', stopDrawing);
    canvas {
      border: 5px solid blue
    }
    <canvas id="c" width="500" height="300"></canvas>