daisy
daisy

Reputation: 675

Draw on a Canvas via mouse and touch

I want to draw on a canvas, works great with a mouse, but how do I have to modify the code to make it run on iPad or Nexus as well?

link

 var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    var width  = window.innerWidth;
    var height = window.innerHeight;
    canvas.height = height;
    canvas.width = width;

    canvas.addEventListener('mousedown', function(e) {
        this.down = true;   
        this.X = e.pageX ;
        this.Y = e.pageY ;
    }, 0);

    canvas.addEventListener('mouseup', function() {
        this.down = false;          
    }, 0);

    canvas.addEventListener('mousemove', function(e) {
      
        if(this.down) {
             with(ctx) {
                beginPath();
                moveTo(this.X, this.Y);
                lineTo(e.pageX , e.pageY );
                ctx.lineWidth=1;
                stroke();
             }
             this.X = e.pageX ;
             this.Y = e.pageY ;
        }
    }, 0);

Upvotes: 11

Views: 10090

Answers (3)

Roobie Nuby
Roobie Nuby

Reputation: 1439

This is an HTML file that works to draw both mouse and touch events.

<!DOCTYPE html>
<html><head><meta charset="utf-8"/><script type='text/javascript'>
window.addEventListener('load', function () {
  // get the canvas element and its context
  var canvas = document.getElementById('sketchpad');
  var context = canvas.getContext('2d');
  var isIdle = true;
  function drawstart(event) {
    context.beginPath();
    context.moveTo(event.pageX - canvas.offsetLeft, event.pageY - canvas.offsetTop);
    isIdle = false;
  }
  function drawmove(event) {
    if (isIdle) return;
    context.lineTo(event.pageX - canvas.offsetLeft, event.pageY - canvas.offsetTop);
    context.stroke();
  }
  function drawend(event) {
    if (isIdle) return;
    drawmove(event);
    isIdle = true;
  }
  function touchstart(event) { drawstart(event.touches[0]) }
  function touchmove(event) { drawmove(event.touches[0]); event.preventDefault(); }
  function touchend(event) { drawend(event.changedTouches[0]) }

  canvas.addEventListener('touchstart', touchstart, false);
  canvas.addEventListener('touchmove', touchmove, false);
  canvas.addEventListener('touchend', touchend, false);        

  canvas.addEventListener('mousedown', drawstart, false);
  canvas.addEventListener('mousemove', drawmove, false);
  canvas.addEventListener('mouseup', drawend, false);

}, false); // end window.onLoad
</script></head><body  encoding='utf8'>
  <canvas id='sketchpad' width='500' height='500' style='border:1px solid #777'/>
</body></html>

Upvotes: 10

rejnok
rejnok

Reputation: 380

Using events touchstart, touchend and touchmove, but it is more complex, because coordinates are not in pageX and pageY, but all fingers coordinates are in the array:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var width  = window.innerWidth;
var height = window.innerHeight;
canvas.height = height;
canvas.width = width;

canvas.addEventListener('touchstart', function(e) {
  this.down = true;   
  this.X = e.touches[0].pageX ;
  this.Y = e.touches[0].pageY ;
}, 0);

canvas.addEventListener('touchend', function() {
  this.down = false;          
}, 0);

canvas.addEventListener('touchmove', function(e) {
  if(this.down) {
    with(ctx) {
      beginPath();
      moveTo(this.X, this.Y);
      lineTo(e.touches[0].pageX , e.touches[0].pageY );
      ctx.lineWidth=1;
      stroke();
    }
    this.X = e.touches[0].pageX ;
    this.Y = e.touches[0].pageY ;
  }
}, 0);

but this not solve common problem, to make it both mouse and touch compatible. I searched for solution and found this solution, if you're interested: http://bencentra.com/code/2014/12/05/html5-canvas-touch-events.html Also if the task will be more complex, you must find solution for default smartphone browsers behaviour that when trigger touchstart browsers also triggers additional events mousedown + mouseup + click (it is for compatibility with non-touch sites). Using Event.preventDefault() can disable this behaviour temporarily for actual touch event.

Upvotes: 0

David Millar
David Millar

Reputation: 1878

The events you need to use are touchstart, touchend, and touchmove, which should correspond with the functions above. I don't know if events can be stacked as easily in plain JS as in jQuery, but you should be able to support both mouse and touch either by turning each event into functions:

var myMoveEvent = function (e) {
    if(this.down) {
         with(ctx) {
            beginPath();
            moveTo(this.X, this.Y);
            lineTo(e.pageX , e.pageY );
            ctx.lineWidth=1;
            stroke();
         }
         this.X = e.pageX ;
         this.Y = e.pageY ;
    }
}

canvas
    .addEventListener('mousemove', function(e) {
        myMoveEvent(e);
    }, 0)
    .addEventListener('touchmove', function(e) {
        myMoveEvent(e);
    }, 0);

Upvotes: 2

Related Questions