Pointer Event issue: pointercancel with pressure input (pen)
Asked Answered
M

2

7

Thank you for your help in advance. I'm a bit stumped with an issue I am having. I am developing a web app in chrome using react and canvas. This issue seems to be a PointerEvent issue with pressure pen input.

The issue: When I start to draw with my tablet and pen, the pointercancel event is triggered after a short distance has been drawn, even when pressure is still applied with the pen. (while using the mouse this works as intended and there is no issue)

To better describe the issue, this is a visual of what is happening. (.gif starts as a white screen)

A .gif of the pointercancel issue

The first line is a straight line with the pen input, which I attempt to draw across the screen, but as you can see, it is abruptly interrupted (this is where the pointercancel event is triggered) even though the pen pressure is still being applied. This also shows the area size that is possible before the event is triggered.

The second shows that as long as I stay in a small area with the pen input, the pointercancel does not trigger, but once I try and leave that area, the pointercancel event is triggered and stops the line from being drawn.

The third shows the input from the mouse, being able to move around the canvas without the pointercancel event being triggered.

Any help would be appreciated to figure out this issue, it does look like there is support since chrome 55 for this feature, so I am uncertain as to what could be causing the pointercancel to be triggered.

Although I don't think it's really relevant to the question, in case it is here is the code for the project, re-written a touch just to make it more legible. It's not very complex, just a simple canvas to test input on.

The HTML for the canvas area is as follows (it's inside a react component):

<div className="session-container">
  <canvas ref="canvas" className="canvas"></canvas>
</div>

and the javascript, which is all within a component in react, is as follows:

componentDidMount() {
  this.canvas = this.refs.canvas;
  this.context = this.canvas.getContext("2d");

  this.canvas.addEventListener('pointerdown', this.onDown, false);
  this.canvas.addEventListener('pointerup', this.onUp, false);
  this.canvas.addEventListener('pointercancel', this.onUp, false);
  this.canvas.addEventListener('pointermove', this.onMove, false);
}

onDown(e) {
  this.drawing = true;

  current.x = e.clientX || e.touches[0].clientX;
  current.y = e.clientY || e.touches[0].clientY;
}

onUp(e) {
  this.drawing = false;
}

onMove(e) {
  if (!this.drawing) return;

  this.drawLine(current.x, current.y, e.clientX || e.touches[0].clientX, e.clientY || e.touches[0].clientY, e.pressure, true);
  current.x = e.clientX || e.touches[0].clientX;
  current.y = e.clientY || e.touches[0].clientY;
}


drawLine(x0, y0, x1, y1, pressure, emit){
  this.context.beginPath();
  this.context.moveTo(x0, y0);
  this.context.lineTo(x1, y1);
  this.context.strokeStyle = 'black';
  this.context.lineWidth = 2;
  this.context.stroke();
  this.context.closePath();
}

A full view of the component can be found here Gist

Militarism answered 23/11, 2019 at 18:20 Comment(0)
K
13

to those who have the same problem :

the solution was in adding a css property touch-action: none;

it changes the behavior of pointer events, which seems to be by default : use any pointer as a clicking device, not a drawing one

Krick answered 23/11, 2019 at 21:39 Comment(3)
But touch-action also prevents the scrolling mecanism for touch devices. Any toughts on that?Lamelliform
It's been a while so I dug up some info, but I think you can add the property only on the canvas you want to draw in, and the rest of the page will still behave normallyKrick
of course if your canvas is bigger than the display, you will have to implement your own way of moving inside (like a drawing mode/tool and a moving tool)Krick
K
2

found this here

The pointercancel event is fired when the browser determines that there are unlikely to be any more pointer events, or if after the pointerdown event is fired, the pointer is then used to manipulate the viewport by panning, zooming, or scrolling.

seems like this event is thrown as soon as you leave the click zone because it changes the nature of the click...

I suggest you simply remove your listenner, pointerup event should be enought to detect an end of input


  this.canvas.addEventListener('pointerdown', this.onDown, false);
  this.canvas.addEventListener('pointerup', this.onUp, false);
  //this.canvas.addEventListener('pointercancel', this.onUp, false);
  this.canvas.addEventListener('pointermove', this.onMove, false);
Krick answered 23/11, 2019 at 19:29 Comment(3)
I did try that, what happens is that when you are no longer pressed down with the pen, the drawing continues to happen (on hover), as the up event is never triggered. Also the pressure is no longer recorded as there is no pressure due to the pen not being pressed against the surface.Militarism
ah... did you set a css touch-action: none; property on the canva ? it seems to correct this kind of bugsKrick
Wow, that worked, thanks a lot, I appreciate the help. Want to add that to your answer or make a new answer and I'll mark it.Militarism

© 2022 - 2024 — McMap. All rights reserved.