Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differently support multi mouse events #5785

Merged
merged 13 commits into from
Jul 14, 2019
Merged

Differently support multi mouse events #5785

merged 13 commits into from
Jul 14, 2019

Conversation

asturur
Copy link
Member

@asturur asturur commented Jun 29, 2019

This PR is a proof of concepts for handling multi touch / multi pointer events
It aims at taking track of all events that gets generated on the canvas and identify the owner of the transformation, while letting everything else flow to eventually brushes and events firing.

  • Removes old ie < 10 code to handle events ( and so not supported )
  • Register specific events for touch based
  • Put a guard against double re-registering of mouse down

@@ -16,7 +16,7 @@
addEventOptions = { passive: false };

function checkClick(e, value) {
return 'which' in e ? e.which === value : e.button === value - 1;
return e.button === value - 1;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was something pre ie10. We do not need it anymore

*/
_getEventPrefix: function () {
return this.enablePointerEvents ? 'pointer' : 'mouse';
},
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just to allow the minifier to work better and reuse code.


var changedTouches = event.changedTouches;
if (changedTouches) {
return changedTouches[0] && changedTouches[0].identifier;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to verify what changeTouches contains and in what order.

@asturur
Copy link
Member Author

asturur commented Jun 29, 2019

@dirkluijk @ arcatdmz
I'm trying to get a grasp of the pointer event situation.

Today i digged up my pointer event device and formatted/reinstalled it ( forgot password ) so that i can move on with this.

We need to understand how we can:
Uniform pointer/touch/mouse events in a way that up/down make sense in the same way for every device ( a mouse generate down/up with buttons and PER button , while pointer do not do it, but they generate a move event with different button state )

Define if we want hardcode in fabric that object transformations are done with left mouse button and with no buttons for touch/pointer events ( ok fingers do not have button ).

How touch events and pointer events fire things with multiple finger/pencils that move or goes up ath the same time.

if i have 2 fingers down on the screen and i pull up one, do i get a mouse up events? I did not try yet.

if (!this._isMainEvent(e)) {
return;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this repeated for down/up/move is needed to avoid doing stuff in fabricjs object transformations when we are outside the single pointer movement, main touch changes.

@asturur
Copy link
Member Author

asturur commented Jun 30, 2019

For now is broken, but i m here with my multitouch stuff to test it

@@ -60,8 +85,7 @@
functor(canvasElement, 'wheel', this._onMouseWheel);
functor(canvasElement, 'contextmenu', this._onContextMenu);
functor(canvasElement, 'dblclick', this._onDoubleClick);
functor(canvasElement, 'touchstart', this._onMouseDown, addEventOptions);
functor(canvasElement, 'touchmove', this._onMouseMove, addEventOptions);
functor(canvasElement, 'touchstart', this._onTouchStart, addEventOptions);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not register touchMove by default. is not used if not after a touchStart. Use specifct onTouchStart instead of _onMouseDown.

this._willAddMouseDown = setTimeout(function() {
addListener(_this.upperCanvasEl, eventTypePrefix + 'down', _this._onMouseDown);
_this._willAddMouseDown = 0;
}, 400);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add some clearTimeout logic to avoid registering multiple mousedown when another touchend would happen before 400 ms

return pointer;
}

if (fabric.isTouchSupported) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this. isTouchSupport is randomly broken depending on browsers and security and privacy concerns. If the event has a changedTouches then is a touch event.

@asturur
Copy link
Member Author

asturur commented Jun 30, 2019

Ok this starts to work

@dirkluijk
Copy link

Nice work @asturur ! I will test this PR today and come back at you with feedback.

@dirkluijk
Copy link

dirkluijk commented Jul 1, 2019

I tested this on a touch screen. The fix does not seem to work.

Steps to reproduce

  1. Start drawing with one finger.
  2. Start drawing with second finger (don't release first finger)
  3. Release either first or second finger.

Expected result
I expect either the second finger to be ignored at all, or a second path to be created which is not connected to the first one.

Actual result

  • First part of the path (until when the second finger touches) is removed
  • Remaining part of the path are lines between both fingers

Demo: https://a.uguu.se/ZAbwS2hT3Bs0.mov

@asturur
Copy link
Member Author

asturur commented Jul 2, 2019

This is not going to fix brushes.
This allows you to fix the brush in the brush file, without bringing specific pencil logic on the canvas.

You can add to the brush events informations like pointerId, activePointers, and mainPointer andavoid it do stop drawing or drawing too much when there are too many fingers, or when the finger is not the main one.

@dirkluijk
Copy link

dirkluijk commented Jul 2, 2019

All right, I'll check if this PR is OK for a brush fix. I'll get back at you with feedback.

@dirkluijk
Copy link

dirkluijk commented Jul 2, 2019

Some comments:

  • maybe rename activePointers to activePointerIds?
  • if feels a bit weird to have both activePointers and mainPointerId. For example, the _isMainEvent() method checks them both.

I tried to fix the brush issue in this branch, but I encountered very strange behaviour:

  • with touch events, I still cannot prevent issues with second pointers. The second path is not drawn, but the touchend of the second pointer is still messing things up.
  • with pointer events, things get even worse (different behaviour). Everything seems to break.

In pencil_brush.class.js I tried several things, including:

onMouseDown: function(pointer, data) {
    if (this.canvas.activePointerIds.length > 1) {
      return;
    }

  /* ... */
}

onMouseMove: function(pointer, data) {
    if (this.canvas.getPointerId(data.e) !== this.canvas.mainPointerId) {
      return;
    }

  /* ... */
}

onMouseUp: function(data) {
    if (this.canvas.getPointerId(data.e) !== this.canvas.mainPointerId) {
      return;
    }

  /* ... */
}

However, I cannot get it working. I feel a bit more comfortable with my original PR.

Can you take a look?

@asturur
Copy link
Member Author

asturur commented Jul 2, 2019

Yes but your original PR makes an hard choice of locking events completely when are from more than one finger. That feels bad to me.
I'll put up the touch device again later today and continue.

@asturur
Copy link
Member Author

asturur commented Jul 2, 2019

if feels a bit weird to have both activePointers and mainPointerId. For example, the _isMainEvent() method checks them both.

Can you explain me this a bit more? activePointers give us a glimps of how many touches are there, mainPointerId is just a memo to know what event started the current ongoing event flow.

@dirkluijk
Copy link

dirkluijk commented Jul 2, 2019

Yes but your original PR makes an hard choice of locking events completely when are from more than one finger. That feels bad to me.

Yeah, I agree with that.

I'll put up the touch device again later today and continue.

Awesome! 🎉

Can you explain me this a bit more? activePointers give us a glimps of how many touches are there, mainPointerId is just a memo to know what event started the current ongoing event flow.

Yeah, my comment was about _isMainEvent():

_isMainEvent: function(evt) {
  return this.activePointers.length <= 1 || this.getPointerId(evt) === this.mainPointerId;
},

I don't understand this function really. What does it really do? Shouldn't it only check this.activePointers.length <= 1? Because is there a difference when I release the "main" pointer before the "second" pointer or vice versa?

@asturur
Copy link
Member Author

asturur commented Jul 3, 2019

well i wrote it so it would work most of the time.
I think we can call an experimental phase, we do not know if moving away the main finger should interrupt fabricJS transformation or not.

@dirkluijk
Copy link

Any chance to take a look at my issue? 😎

@asturur
Copy link
Member Author

asturur commented Jul 8, 2019

To be totally honest i didn't. I have been taken by some videogame ( wow, new patch, new farming ).

@asturur
Copy link
Member Author

asturur commented Jul 13, 2019

here i am, wired with the touch device, resuming work.

@asturur
Copy link
Member Author

asturur commented Jul 13, 2019

I was about to give up today.
Then i decided for this compromise: when pointer events are enabled, touch events are disabled.
This allow for simpler code all around.
Ie10 works nice too.

I did not get to the brush problem yet.

@asturur
Copy link
Member Author

asturur commented Jul 13, 2019

This is not perfect by any mean, but the brush now works correctly. There is some strange interaction with firefox but ie10, ie11, edge, chrome work good.

@asturur
Copy link
Member Author

asturur commented Jul 14, 2019

Ok i m going to merge it. The pencil works good now with many fingers on the screen.
At works is as broken as before!

@asturur asturur merged commit 01a7ec6 into master Jul 14, 2019
@asturur asturur mentioned this pull request Jul 14, 2019
@dirkluijk
Copy link

Thanks @asturur! I'll test it tomorrow morning right away.

@dirkluijk
Copy link

Works perfect!!

@asturur
Copy link
Member Author

asturur commented Jul 15, 2019

I have microsoft surface, a stylus , firefox and i could freedraw both with finger and pencil.

can you start a fiddle with latest 3.3.2 where the freedrawing does not work?

@bricejar
Copy link

@asturur it works, sorry about that.

@@ -49,7 +52,10 @@
* Inovoked on mouse move
* @param {Object} pointer
*/
onMouseMove: function(pointer) {
onMouseMove: function(pointer, options) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add extra options parameter in doc

thiagocunha pushed a commit to thiagocunha/fabric.js that referenced this pull request Nov 18, 2019
@asturur asturur deleted the event-mouse-up branch January 15, 2020 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants