在 HTML 画布上绘制的线条未出现在触摸事件中

Posted

技术标签:

【中文标题】在 HTML 画布上绘制的线条未出现在触摸事件中【英文标题】:Lines Drawn on HTML Canvas Not Appearing with Touch Events 【发布时间】:2022-01-12 01:18:16 【问题描述】:

我有一个画布元素,用于在我的页面上的面板中练习绘图,并且当人们在其中触摸时,我设法禁用了滚动事件。我重新设计了代码以创建一组单独的操作来处理触摸事件,但是这些行没有显示出来,即使我已经在控制台中标记了这些事件并且触摸正在正确注册。

我错过了什么?

html

<canvas class="js-paint paint-canvas"  ></canvas>

CSS

canvas 
  touch-action: none; /* Prevent scrolling when trying to use the canvas in touch mode */


.paint-canvas 
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  background-color: rgba(255, 255, 255, 0.5);
  border: 1px black solid;
  display: block;
  margin: 0 auto;

JS

const paintCanvas = document.querySelector( '.js-paint' );
const context = paintCanvas.getContext( '2d' );
context.lineCap = 'round';
context.strokeStyle = '#222222'; // Hex code with preceding #
context.lineWidth = 10; // Integer value

const lineWidthRange = document.querySelector( '.js-line-range' );
const lineWidthLabel = document.querySelector( '.js-range-value' );

let x = 0, y = 0;

// Drawing with mouse
let isMouseDown = false;

const stopDrawing = () =>  isMouseDown = false; 

const startDrawing = event => 
  isMouseDown = true;
  [x, y] = [event.offsetX, event.offsetY];


const drawLine = event => 
  if ( isMouseDown ) 
    const newX = event.offsetX;
    const newY = event.offsetY;
    context.beginPath();
    context.moveTo( x, y );
    context.lineTo( newX, newY );
    context.stroke();
    //[x, y] = [newX, newY];
    x = newX;
    y = newY;
  


paintCanvas.addEventListener( 'mousedown', startDrawing );
paintCanvas.addEventListener( 'mousemove', drawLine );
paintCanvas.addEventListener( 'mouseup', stopDrawing );
paintCanvas.addEventListener( 'mouseout', stopDrawing );

// For tablets
let isTouchDown = false;

const stopDrawingTouch = () => 
  isTouchDown = false;

const startDrawingTouch = event => 
  isTouchDown = true;
  [x, y] = [event.offsetX, event.offsetY];

const drawLineTouch = event => 
  if ( isTouchDown ) 
    const newX = event.offsetX;
    const newY = event.offsetY;
    context.beginPath();
    context.moveTo( x, y );
    context.lineTo( newX, newY );
    context.stroke();
    //[x, y] = [newX, newY];
    x = newX;
    y = newY;
  


paintCanvas.addEventListener( 'touchstart', startDrawingTouch );
paintCanvas.addEventListener( 'touchmove', drawLineTouch );
paintCanvas.addEventListener( 'touchend', stopDrawingTouch );
    // Not sure if there's a touch equivalent to 'mouseout'; OK with skipping it for now in the name of simplicity

【问题讨论】:

【参考方案1】:

在写问题的时候想出了答案,所以为了不拉扯 DenverCoder9,我想我最好为社区做一个快速的写。

开始吧,这里有一个可行的解决方案:https://jsfiddle.net/Kaji_Sensei/hvusjx9L/10/

所以问题的第一部分是,作为一个触摸事件,我们需要实际捕获触摸本身以获取其坐标。为此,对event.offsetXevent.offsetY 的调用将变为对event.touches[0].screenXevent.touches[0].screenY 的调用。

然而,这本身是不够的,因为我们仍然需要偏移信息,以便坐标保持在画布内。为此,我们使用jQuery('.js-paint').offset().leftjQuery('.js-paint').offset().top 来获取这些距离。

对于 X,我们只需从 event.touches[0].screenX 中减去偏移量即可到达正确的位置。

Y 有点复杂,并进行了一些测试。测试在 fiddle cmets 中有说明,但简短的回答是,出于某种原因,我们需要将 Y 偏移量分成两半,然后再从 event.touches[0].screenY 中减去它,以便将点放在发生触摸的正下方。

HTML

<canvas class="js-paint paint-canvas"  ></canvas>

CSS

canvas 
  touch-action: none; /* Prevent scrolling when trying to use the canvas in touch mode */


.paint-canvas 
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  background-color: rgba(255, 255, 255, 0.5);
  border: 1px black solid;
  display: block;
  margin: 0 auto;

JS

const paintCanvas = document.querySelector( '.js-paint' );
const context = paintCanvas.getContext( '2d' );
context.lineCap = 'round';
context.strokeStyle = '#222222'; // Hex code with preceding #
context.lineWidth = 10; // Integer value

const lineWidthRange = document.querySelector( '.js-line-range' );
const lineWidthLabel = document.querySelector( '.js-range-value' );

let x = 0, y = 0;

// Drawing with mouse
let isMouseDown = false;

const stopDrawing = () =>  isMouseDown = false; 

const startDrawing = event => 
  isMouseDown = true;
  [x, y] = [event.offsetX, event.offsetY];


const drawLine = event => 
  if ( isMouseDown ) 
    const newX = event.offsetX;
    const newY = event.offsetY;
    context.beginPath();
    context.moveTo( x, y );
    context.lineTo( newX, newY );
    context.stroke();
    //[x, y] = [newX, newY];
    x = newX;
    y = newY;
  


paintCanvas.addEventListener( 'mousedown', startDrawing );
paintCanvas.addEventListener( 'mousemove', drawLine );
paintCanvas.addEventListener( 'mouseup', stopDrawing );
paintCanvas.addEventListener( 'mouseout', stopDrawing );

// For tablets
let isTouchDown = false;
let touchXOffset = jQuery('.js-paint').offset().left;
let touchYOffset = jQuery('.js-paint').offset().top / 2;
// Subtracting the offset isn't working
// Offset to 0 isn't working
// Add offset instead of dividing isn't working
// TEST: Offset divided by 2 <-- WORKS!

const stopDrawingTouch = () => 
  isTouchDown = false;

const startDrawingTouch = event => 
  isTouchDown = true;
  console.log(event.touches[0]);
  [x, y] = [(event.touches[0].screenX - touchXOffset), (event.touches[0].screenY - touchYOffset)];

  console.log('X: ' + event.touches[0].screenX + ' offset by ' + touchXOffset);
  console.log('Y: ' + event.touches[0].screenY + ' offset by ' + touchYOffset);

const drawLineTouch = event => 
  if ( isTouchDown ) 
    const newX = event.touches[0].screenX - touchXOffset;
    const newY = event.touches[0].screenY - touchYOffset;
    context.beginPath();
    context.moveTo( x, y );
    context.lineTo( newX, newY );
    context.stroke();
    //[x, y] = [newX, newY];
    x = newX;
    y = newY;
  


paintCanvas.addEventListener( 'touchstart', startDrawingTouch );
paintCanvas.addEventListener( 'touchmove', drawLineTouch );
paintCanvas.addEventListener( 'touchend', stopDrawingTouch );
    // Not sure if there's a touch equivalent to 'mouseout'; OK with skipping it for now in the name of simplicity

【讨论】:

@ggorlen 明白了!好久没发帖了,没想到做法变了。现在正在编辑代码。

以上是关于在 HTML 画布上绘制的线条未出现在触摸事件中的主要内容,如果未能解决你的问题,请参考以下文章

在画布 (HTML5) 上绘制好看的(如在 Flash 中)线条 - 可能吗?

触摸事件未注册使用 Flash CC 的 HTML5 画布创作

无法在 Android 设备上的 Javascript 中获取触摸事件的坐标

如何在画布上动画绘制线条

在 HTML5 画布上绘制旋转文本

canvas绘制线条怎么改变线条长度