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

Adding movementX and movementY to synthenticMouseEvent fixes #6723 #9018

Merged
merged 3 commits into from
Jun 15, 2018

Conversation

jasonwilliams
Copy link
Contributor

@jasonwilliams jasonwilliams commented Feb 16, 2017

This will now give full support for movementX and movementY including for browsers which don't support these events.
Not sure how to test this so any help is welcome

@facebook-github-bot
Copy link

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla - and if you have received this in error or have any questions, please drop us a line at cla@fb.com. Thanks!

If you are contributing on behalf of someone else (eg your employer): the individual CLA is not sufficient - use https://developers.facebook.com/opensource/cla?type=company instead. Contact cla@fb.com if you have any questions.

@jasonwilliams
Copy link
Contributor Author

hmm, already registered but it was with a lower case 'j'. Hope someone can change that

@jasonwilliams jasonwilliams changed the title Adding movementX and movementY to synthenticMouseEvent Adding movementX and movementY to synthenticMouseEvent fixes #6723 Feb 16, 2017
@facebook-github-bot
Copy link

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@gaearon
Copy link
Collaborator

gaearon commented Apr 21, 2017

Hey, sorry for no review. 😞

We have a large backlog of existing PRs and can’t dedicate enough time to the DOM right now because we’re finishing up the core rewrite.

We’ll try to get look at this when there is some time available!

@aweary
Copy link
Contributor

aweary commented Apr 21, 2017

I had a PR for this a long time ago at #6727 with the same implementation. I closed it because it also never got reviewed 😄 For what its worth, I think this is a ~reasonable way to support this feature.

Copy link
Contributor

@nhunzaker nhunzaker left a comment

Choose a reason for hiding this comment

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

This seems legit to me. According to MDN, this is definitely the way to calculate it:

currentEvent.movementX = currentEvent.screenX - previousEvent.screenX.

https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX

Just left a quick formatting request. Could you also run:

yarn prettier

This will format the project according to React's coding conventions (though it might not take out that extra new line).

var previousScreenX = MouseMetrics.previousScreenX;
MouseMetrics.setPreviousScreenX(event.screenX);
return (previousScreenX) ? event.screenX - previousScreenX : 0;

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you drop the extra new line here?

@aweary
Copy link
Contributor

aweary commented Jan 11, 2018

Could we get rid of MouseMetrics and just inline the logic into SyntheticMouseEvent? We could just use two local variables previousScreenY and previousScreenX and avoid the indirection of tracking it as an object property and updating it with a function call.

movementY: function(event) {
  if ('movementY' in event) {
     return event.movementY;
  }

 var screenY = previousScreenY;
 previousScreenY = event.screenY;
 return screenY ? event.screenY - screenY : 0;
 },

@nhunzaker
Copy link
Contributor

nhunzaker commented Jun 8, 2018

Just checking in here. It's been a while, I apologize for that, @jasonwilliams!

It seems like the next steps would be:

  1. Upstream this with master
  2. Inline the MouseMetrics code into movementX and movementY ( we removed MouseMetrics)

@aweary do you still have interest on getting this in too? There's been a significant enough amount of changes to the repo that I wonder if we should help out on a rebase.

@jasonwilliams
Copy link
Contributor Author

jasonwilliams commented Jun 8, 2018

Sure, ill take a look,
ill start off with a rebase

@aweary
Copy link
Contributor

aweary commented Jun 8, 2018

@aweary do you still have interest on getting this in too?

Sure, might as well! It's not a frequently requested feature, but it's a small enough change that we might as well include it.

@jasonwilliams happy to help with any rebase issues you encounter!

@pull-bot
Copy link

pull-bot commented Jun 11, 2018

ReactDOM: size: 🔺+0.2%, gzip: 🔺+0.3%

Details of bundled changes.

Comparing: c78957e...2cff055

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js +0.1% +0.1% 626.65 KB 627.15 KB 145.88 KB 145.99 KB UMD_DEV
react-dom.production.min.js 🔺+0.2% 🔺+0.3% 94.25 KB 94.47 KB 30.52 KB 30.6 KB UMD_PROD
react-dom.development.js +0.1% +0.1% 611.01 KB 611.51 KB 141.88 KB 141.98 KB NODE_DEV
react-dom.production.min.js 🔺+0.2% 🔺+0.2% 92.75 KB 92.97 KB 29.51 KB 29.58 KB NODE_PROD
ReactDOM-dev.js +0.1% +0.1% 620.2 KB 620.7 KB 141.22 KB 141.33 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+0.2% 🔺+0.3% 269.15 KB 269.64 KB 50.57 KB 50.71 KB FB_WWW_PROD

Generated by 🚫 dangerJS

Copy link
Contributor

@nhunzaker nhunzaker left a comment

Choose a reason for hiding this comment

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

Just left a final request about event.ScreenX.

Otherwise, I think this looks good.

Is there any concern about saving the prior screenX/screenY globally? Like if React is used with shadow DOM - does that matter?

I don't want this to become too much of a rabbit hole. I'll block out some time later today to look into this and do some quick testing.

Thanks for updating this, and for sticking with us!

}

const screenX = previousScreenX;
previousScreenX = event.ScreenX;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be event.screenX?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops, yes it should

@jasonwilliams
Copy link
Contributor Author

jasonwilliams commented Jun 11, 2018

Is there any concern about saving the prior screenX/screenY globally?

Is it global, or just local to that module? if so, would that matter?

@nhunzaker
Copy link
Contributor

nhunzaker commented Jun 11, 2018

Ah, by globally I meant like in the same browser window. I wanted to make sure that there wasn't anything odd about custom elements, which have caused some issues in the past because they get put into an island.

But I don't think that's a problem here. Take a look at the following Codepen:

https://codepen.io/nhunzaker/pen/xzqeXp

Here, I created a custom component and added a mouse-move listener to it so that I could make sure that the parent element (the body of the page) had the same values as shadow DOM:

screen shot 2018-06-11 at 5 59 47 pm

I wanted to make sure we didn't have to track this per document root. Looks like we're in the clear!

Copy link
Contributor

@nhunzaker nhunzaker left a comment

Choose a reason for hiding this comment

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

This looks good on my end. @aweary or @jquense would you be willing to take a second look at this?

@nhunzaker
Copy link
Contributor

nhunzaker commented Jun 12, 2018

Did some additional testing. Judging from MDN, movementX/Y isn't supported in Safari or IE.

Comparing the values between FF/Chrome and Safari/IE. This checks out. I've tested specifically in:

  • Chrome 66
  • Firefox 60
  • IE9, IE10, IE11
  • Safari 7.1, 11.1

Looks like all values consistently round to integers in both the native and synthetic implementation as well.

@jasonwilliams excellent work! I'll leave this out a bit longer to give others a chance to weigh in, but this is good to 🚢 in my ⛵️.

@nhunzaker
Copy link
Contributor

Added a quick fixture for mouse movement for good measure. Thanks, @jasonwilliams!

@nhunzaker nhunzaker merged commit 64c54ed into facebook:master Jun 15, 2018

const screenX = previousScreenX;
previousScreenX = event.screenX;
return screenX ? event.screenX - screenX : 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the check here intends to check against null but will accidentally also be falsy if screenX is actually equal to 0. Please avoid truthy checks like this, they tend to hide bugs.

Copy link
Contributor

@aweary aweary Jun 15, 2018

Choose a reason for hiding this comment

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

If it's equal to 0 then it will still return 0 since that's the second expression in the ternary.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think that if saved screenX is 0, but then you moved to 200, you want to return 200 - 0 rather than 0.

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe Dan is right, and we need to correct this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

https://github.com/tc39/proposal-nullish-coalescing would have helped a lot with this, yes we should check if equal to null

Copy link
Collaborator

Choose a reason for hiding this comment

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

Another thing is that using the same variable for both null and numeric values can mess with VM optimizations. I think it would be better to use a separate boolean flag here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also, are we happy to assume screenX on event? If undefined we could end up with undefined - null

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

@jasonwilliams jasonwilliams Jun 20, 2018

Choose a reason for hiding this comment

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

Ok so if screenX will always be an Number, could we not just initiate previousScreenX as 0 Instead of null, and then instead of a ternary or null checking, always perform the minus operation. Because we can guarantee both operands will be Numbers by this point .

Copy link
Collaborator

Choose a reason for hiding this comment

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

Wouldn't make the first movementX equal to the current screen coordinate, instead of 0? I think 0 would be expected (because the cursor didn't "jump" from top left point).


const screenY = previousScreenY;
previousScreenY = event.screenY;
return screenY ? event.screenY - screenY : 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same.

@gaearon gaearon mentioned this pull request Sep 5, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants