简体   繁体   English

javascript + html5 canvas:在移动设备上绘图而不是拖动/滚动?

[英]javascript + html5 canvas: drawing instead of dragging/scrolling on mobile devices?

I'm using a html5 canvas + some javascript (onmousedown/move/up) to create simple draw pad on a webpage. 我正在使用html5画布+一些javascript(onmousedown / move / up)在网页上创建简单的绘图板。

Works OK in Opera, Firefox, Chrome, etc (tried on desktop PCs). 在Opera,Firefox,Chrome等中运行正常(在台式机上试用)。 But if I visit this page with an iPhone, when trying to draw on the canvas, instead it drags or scrolls the page. 但是如果我用iPhone访问这个页面,当试图在画布上绘图时,它会拖动或滚动页面。

This is fine for other page content, by sliding the page up an down you can navigate through the page in a mobile browser as usual. 这适用于其他页面内容,通过向下滑动页面,您可以像往常一样在移动浏览器中浏览页面。 But is there a way to disable this behavior on the canvas, so that also mobile visitors can actually draw something on it? 但有没有办法在画布上禁用此行为,以便移动访问者可以实际绘制一些内容?

For your reference, here's a minimalisic example: 供您参考,这是一个简洁的例子:

<html><head><script type='text/javascript'>
function init()
{
  var canvas = document.getElementById('MyCanvas');
  var ctx = canvas.getContext('2d');
  var x = null;
  var y;
  canvas.onmousedown = function(e)
  {
    x = e.pageX - canvas.offsetLeft;
    y = e.pageY - canvas.offsetTop;
    ctx.beginPath();
    ctx.moveTo(x,y);
  }
  canvas.onmouseup = function(e)
  {
    x = null;
  }  
  canvas.onmousemove = function(e)
  {
    if (x==null) return;
    x = e.pageX - canvas.offsetLeft;
    y = e.pageY - canvas.offsetLeft;
    ctx.lineTo(x,y);
    ctx.stroke();
  }  
}
</script></head><body onload='init()'>
<canvas id='MyCanvas' width='500' height='500' style='border:1px solid #777'>
</canvas></body></html>

Is there some special style or event I have to add to the canvas, in order to avoid dragging/scrolling the page when swiping in the canvas? 是否有一些特殊的样式或事件我必须添加到画布中,以避免在画布中滑动时拖动/滚动页面?

iPad / iPhone doesn't have mouse* events. iPad / iPhone没有鼠标*事件。 You need to use touchstart , touchmove and touchend . 你需要使用touchstarttouchmovetouchend This events can have multiple touches so you need to get first one like this: 这个事件可以有多个触摸,所以你需要得到这样的第一个:

canvas.ontouchstart = function(e) {
  if (e.touches) e = e.touches[0];
  return false;
}

It's important to return false in touch start method because otherwise page scroll is triggered. 在触摸启动方法中return false非常重要,否则会触发页面滚动。

I'm going to add to Grassator's answer by adding a link to this answer that goes more in-depth with the code required to make this solution work: https://stackoverflow.com/a/16630678/5843693 . 我将通过添加此答案的链接来添加Grassator的答案,该链接更深入地了解使此解决方案工作所需的代码: https//stackoverflow.com/a/16630678/5843693

Before I continue, please note that Apple has changed the way iOS handles scrolling on more recent devices. 在我继续之前,请注意Apple已经改变了iOS在更新设备上滚动的方式。 To handle this change, it is necessary to add a few extra functions; 要处理此更改,有必要添加一些额外的功能; thanks to Christopher Vickers for sharing this: 感谢Christopher Vickers分享这个:

function preventDefault(e) {
    e.preventDefault();
}
function disableScroll() {
    document.body.addEventListener('touchmove', preventDefault, { passive: false });
}
function enableScroll() {
    document.body.removeEventListener('touchmove', preventDefault);
}

The methods for canvas are all called upon in a drawer fashion like so: 画布的方法都以抽屉方式调用,如下所示:

var drawer = {
   isDrawing: false,
   touchstart: function (coors) {
      ctx.beginPath();
      ctx.moveTo(coors.x, coors.y);
      this.isDrawing = true;
      disableScroll(); // add for new iOS support
   },
   touchmove: function (coors) {
      if (this.isDrawing) {
         ctx.lineTo(coors.x, coors.y);
         ctx.stroke();
      }
   },
   touchend: function (coors) {
      if (this.isDrawing) {
         this.touchmove(coors);
         this.isDrawing = false;
      }
      enableScroll(); // add for new iOS support
   }
};

In addition, EventListener s are specifically ordered so that touch inputs are taken first: 此外, EventListener是专门排序的,因此首先进行触摸输入:

var touchAvailable = ('createTouch' in document) || ('onstarttouch' in window);

if (touchAvailable) {
   canvas.addEventListener('touchstart', draw, false);
   canvas.addEventListener('touchmove', draw, false);
   canvas.addEventListener('touchend', draw, false);
} else {
   canvas.addEventListener('mousedown', draw, false);
   canvas.addEventListener('mousemove', draw, false);
   canvas.addEventListener('mouseup', draw, false);
}

Finally, the "elastic" scrolling is prevented by adding one more EventListener near the end of the code. 最后,通过在代码末尾附近再添加一个EventListener来防止“弹性”滚动。

document.body.addEventListener('touchmove', function (event) {
   event.preventDefault();
}, false);

All of this is placed inside window.addEventListener('load', function () {}) . 所有这些都放在window.addEventListener('load', function () {})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM