在 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.offsetX
和event.offsetY
的调用将变为对event.touches[0].screenX
和event.touches[0].screenY
的调用。
然而,这本身是不够的,因为我们仍然需要偏移信息,以便坐标保持在画布内。为此,我们使用jQuery('.js-paint').offset().left
和jQuery('.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 画布创作