-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Do not rely on targetTouches for determining "relevant" touch #424
Conversation
|
I think this is a good patch :-) Anything I can do to get this reviewed? |
|
Any change to get this reviewed? Anything I can do on my side? Thanks. |
|
Unfortunately, it looks like the original change this was based on got clobbered in 889d16a. This could make merging messy. I'll take a look at a PR based off the current master, if you're still interested. |
Yes, I am very much interested in this PR. I do think this is a good change. I'll look at updating the PR. |
|
Does this PR make #337 obsolete? |
|
@joeltine, I updated my
Both commits include more details about the changes they hold. |
|
Overall, the PR LGTM, but I just want to be 100% sure I understand the issue with targetTouches. Is it this phrase that can cause unexpected results: |
Currently, on touch devices, goog.fx.Dragger calls "init" on the browser event, to re-configures it with something (a Touch object) it can calculate clientX, clientY, screenX and screenY values from. And, in handleMove_, goog.fx.Dragger calls "preventDefault" on the browser event, to prevent the page to scroll while dragging. This doesn't work on touch devices, because the browser event was re-initialized with something (a Touch object) that doesn't have a "preventDefault" method. This commit fixes the problem by making goog.events.BrowserEvent aware of touch events. In init, when a touch event is detected, the clientX, clientY, screenX and screenY values are calculated from the "relevant" Touch object. And with this, the "maybeReinitTouchEvent_" hack can be removed from goog.fx.Dragger. Closes #162
|
The comment attached to d9c1478 explains the problem.
But the question is: what is the "relevant touch"? As indicated in the comment attached to d9c1478 changedTouches is the list of "all the Touch objects for touch points that contributed to this touch event", so it makes more sense to use Hope this clarifies it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is exactly the same as createChangedTouchEvent below. Can you consolidate into one?
|
Thanks for the additional comments. I'll update the PR. |
|
Fixes #41 |
With multiple touches on the touch surface targetTouches[0] is unlikely to be the "relevant touch", i.e. the touch we want to get clientX, clientY, screenX, and screenY from. See <https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/targetTouches> for more details.
|
PR updated. Thanks again for the comments. |
|
Cool, LGTM. Ignore the Travis failure. It's from an unrelated change. |
|
Looks like a lint error in this PR. ---- FILE : /home/travis/build/google/closure-library/closure/goog/fx/dragger.js ----- |
Really? That doesn't seem to be related to my changes to me. |
|
Haha! You're right. I'm surprised this was never caught internally. |
|
I'm happy to add a commit that removes it if you think it makes sense to do it as part of this PR. |
|
No worries, I can do it internally. |
|
FYI lint fixed in af3bd97 |
Do not rely on targetTouches for determining "relevant" touch
|
Thanks for your work and persistence on this. |
Fixed upstream with google/closure-library#424
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR ended up breaking tests internally. This change was the cause of some of them. It's mainly due to tests that mock the touch event and don't include "target".
The question I have is, how confident are we that using the "target" of the touch instead of the event, "e", is the right thing? Per MDN the touch.target is:
The Element on which the touch point started when it was first placed on the surface, even if the touch point has since moved outside the interactive area of that element or even been removed from the document.
Do you have any clue how this could differ from e.target?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, to do today's external push, I'll likely be pushing the rollback of this change out. Once we decide on the correct fix, this will be pushed out again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any clue how this could differ from e.target?
FYI, that particular change (this.target) came from an old patch: https://code.google.com/p/closure-library/issues/detail?id=382.
So here we're talking about initializing a goog.events.BrowserEvent instance from a touch event, i.e. a browser event resulting from a touch action on the touch surface.
And we want to provide the most relevant values for this.client*, this.screen* and this.target, this being the goog.events.BrowserEvent instance.
This PR suggests relying on e.changedTouches[0] for this.client* and this.screen*, as discussed already.
Now we're discussing this.target, trying to figure out whether it should be set to e.target or e.changedTouches[0].target.
So e.target refers to the Element the browser event was dispatched to (see this mdn page for a good reference). e.changedTouches[0].target is the Element associated with the touch itself, which may be totally unrelated to the e.target. this.target should refer to the event's target, so I think it makes more sense to set always set it to e.target, even when e is a touch event.
If you agree, I can just remove that particular change from my branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be the new commits: master...elemoine:changedtouches
I can create a new PR if you agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
e.target does seem correct. Specifically the docs for this.target says Target that fired the event., which is exactly what e.target represents.
I'll just make this fix internally when I try to roll forward the change.
|
I'll have a closer look Monday or Tuesday. |
Do not rely on targetTouches for determining "relevant" touch. targetTouches[0] is unlikely to be the "relevant touch" when there are multiple touches on the touch surface, because, as documented on MDN, targetTouches is the list of "all the Touch objects for touch points that are still in contact with the touch surface". targetTouches[0] may be unrelated to the current touch event, so using its clientX, clientY, screenX and screenY values does not make sense. changedTouches is the list of "all the Touch objects for touch points that contributed to this touch event", so it makes more sense to use changedTouches[0] as the "relevant touch" when setting the BrowserEvent's clientX, clientY, screenX and screenY values. See #424 for context. ------------- Created by MOE: http://code.google.com/p/moe-java ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=100621715
*** Reason for rollback *** It has broken some tests: *** Original change description *** Merge pull request #424 from elemoine/targettouches Do not rely on targetTouches for determining "relevant" touch. targetTouches[0] is unlikely to be the "relevant touch" when there are multiple touches on the touch surface, because, as documented on MDN, targetTouches is the list of "all the Touch objects for touch points that are still in contact with the touch surface". targetTouches[0] may be unrelated to the current touch event, so using its clientX, clientY, screenX and screenY values do... *** ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=100634635
|
Chiming in because I use touch events and have had perhaps related difficulties. My comments:
a. A single touch in the target element (a Canvas) is treated like a mouseDown, and I start a mouse drag operation. This is in response to a TOUCHSTART event. b. Multiple touches during TOUCHSTART or TOUCHMOVE events (or a TOUCHEND event) ends an ongoing mouse drag. This works for me on Android, iPhone, iPad, Mac, Windows. |
|
Can you expand on why you don't trust |
|
I think because both of At the time I was working on this (October 2014) I read this old post from 2010 on the closure list; this seemed to be the most current info I could find about using touch events with closure-library The recommendation given there was:
So that's what I'm still doing: SimController.prototype.touchStart = function(evt) {
if (evt.target == this.labCanvas_.getCanvas()) {
var bevt = /** @type {!TouchEvent} */(evt.getBrowserEvent());
if (bevt != null) {
var touches = bevt.touches;
if (touches.length == 1) {
// single touch in our canvas is treated as mouseDown.
this.doMouseDown(evt, touches[0].clientX, touches[0].clientY);
} else {
// Multiple touch cancels an ongoing mouse drag.
this.finishDrag(evt);
}
}
}
};From my point of view I would like a "patched cross platform" way of getting all the current touches during any touch event. |
|
@myphysicslab I can understand your skepticism. In general, dealing with touch events uniformly is non-trivial. Unfortunately, not being confident in how browsers handle it isn't enough to affect this PR. If you can provide reproducible evidence, I'd be happy to take a look. |
Merge pull request #424 from elemoine/targettouches Do not rely on targetTouches for determining "relevant" touch goog.events.BrowserEvent#init and goog.style.getClientPosition currently make the same mistake: they use event.targetTouches[0] as the "relevant" touch. As mdn documents it, targetTouches includes « the Touch objects for touch points that are still in contact with the touch surface and whose touchstart event occurred inside the same target element as the current target element ». So if there are multiple touches on the surface targetTouches[0] may not be the touch that caused the current event to happen! This pull request fixes both goog.events.BrowserEvent#init and goog.style.getClientPosition by relying on changedTouches[0] instead. changedTouches includes « the Touch objects for touch points that contributed to this touch event », so using changedTouches[0] rather than targetTouches[0] is more correct. See #424 for full context ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=100866806
|
FYI: finally got this to stick internally. Rolled forward in b2cc62a |
|
Cool. Thanks for following up on this @joeltine. |
Fixed upstream with google/closure-library#424
Fixed upstream with google/closure-library#424
goog.events.BrowserEvent#initandgoog.style.getClientPositioncurrently make the same mistake: they useevent.targetTouches[0]as the "relevant" touch.As mdn documents it,
targetTouchesincludes « the Touch objects for touch points that are still in contact with the touch surface and whose touchstart event occurred inside the same target element as the current target element ». So if there are multiple touches on the surfacetargetTouches[0]may not be the touch that caused the current event to happen!This pull request fixes both
goog.events.BrowserEvent#initandgoog.style.getClientPositionby relying onchangedTouches[0]instead.changedTouchesincludes « the Touch objects for touch points that contributed to this touch event », so usingchangedTouches[0]rather thantargetTouches[0]is more correct.Please review.
Fixes #337.