Skip to content

Right click fix #2241

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

Merged
merged 5 commits into from
Jan 10, 2018
Merged

Right click fix #2241

merged 5 commits into from
Jan 10, 2018

Conversation

alexcjohnson
Copy link
Collaborator

fixes #2101
supersedes #2105 - @AlexVvx I started with your PR, thinking I could just add the right tests to it and be done... unfortunately I found that we had some deeper problems in both the source code and in the tests so it became a much bigger project.

The test problem is that assets/click was unrealistic - it generated a sequence of events that's fine for regular clicks, but right clicks and ctrl-clicks (which we were using all over the place to test "modified click behavior", making a bunch of trace types look like they supported right-click when they really didn't) take a different pathway, and importantly for some users, it also matters whether the contextmenu event is canceled.

The source problem is that we're inconsistent with what we call a click - we have parallel systems handling drag and click events. This isn't only a problem for right clicks (which don't trigger click events at all, so it's a huge problem for them.), it's also inconsistent in subtle ways for our other interactions. For example, independent systems might see both a drag (to make a pan, zoom, or select) AND a click; or they might see neither one! Neither situation is desirable: users should be able to expect that one mouse action will create one response. So I changed the way dragElement works: it now takes an extra option, clickFn, ie what to do in the event of a click. Now you know that the sequence of events in a dragElement action will be either:

prepFn -> moveFn 1 or more times -> doneFn (a drag, even if it ends exactly where it started)

or:

prepFn -> clickFn (a click)

This has a nice side effect that doneFn can be much simpler, it only has one argument (the original event) and doesn't need all the if(dragged) branches it had before. clickFn is also pretty simple, and to my eye keeping the two separate makes them much more readable.

There are a whole bunch of TODOs scattered about in here. Before we merge this we should probably collect them into a new issue or two and 🔪 them from the code - most are about right-click scenarios we could support but currently do not, there's at least one about an unrelated interaction issue I encountered along the way. I don't think any are necessary for 1.32 though.

@etpinard please take a look!

Alex Vinober and others added 3 commits January 9, 2018 12:44
also fix a bunch of incorrect tests because assets/click didn't have the right behavior
and document places we don't have any right-click support presently
@alexcjohnson alexcjohnson added this to the v1.32.0 milestone Jan 10, 2018
}
}
},
clickFn: function(numClicks, e) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wow. This looks so much cleaner by splitting done and click logic. 💯

@@ -84,10 +84,6 @@ module.exports = function initInteractions(gd) {
dragElement.unhover(gd, evt);
};

maindrag.onclick = function(evt) {
Fx.click(gd, evt, subplot);
Copy link
Contributor

@etpinard etpinard Jan 10, 2018

Choose a reason for hiding this comment

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

this is now defined in cartesian/dragbox.js, correct?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is now defined in cartesian/dragbox.js, correct?

yep, now it's here: https://github.com/plotly/plotly.js/pull/2241/files#diff-1bd3dd52cddb8638876bbe17cef28a0dR175

@@ -170,6 +170,11 @@ module.exports = function plot(gd, cdpie) {
}

function handleClick() {
// TODO: this does not support right-click. If we want to support it, we
// would likely need to change mapbox to use dragElement instead of straight
Copy link
Contributor

Choose a reason for hiding this comment

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

we would need to change pie to use dragElement,

correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we could discuss future dragElement generalizations in #2057?

table, sankey and parcoords would also benefit from using dragElement.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

comment added to #2057 - I'll leave the TODOs present in the code then unless you object.

});

it('should contain the correct fields', function() {
click(pointPos[0], pointPos[1]);
expect(futureData.points.length).toEqual(1);
expect(clickPassthroughs).toBe(2);
Copy link
Contributor

Choose a reason for hiding this comment

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

so, in a real world scenario, this here would be .toBe(0)?

Copy link
Contributor

@etpinard etpinard Jan 10, 2018

Choose a reason for hiding this comment

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

i.e. plotly_click eats up gd.on('click')?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

real world it would be 1. dragElement eats up one click event but generates a new one. That was important in certain cases when we were using that synthetic event to trigger the selection.on('click') to trigger the plotly_click. We could consider removing it now, per this TODO so it doesn't bubble up the tree after we've already generated our own events from it, but leaving it in is the most backward-compatible way to handle this.

// then we pass right-click on data points through to plotly_click events.
// Devs using this need to be aware then to check eventData.event
// and figure out if it had a button or ctrlKey etc.
it('should contain the correct fields', function() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Amazing. Thanks for 🔒 this down!

expect('should not call moveFn').toBe(true);
},
doneFn: function() {
expect('should not call doneFn').toBe(true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh nice. I forget we had unit tests for dragElement 👌

// event data is undefined
var BOXEVENTS = [1, 2, 1];
// deselect used to give an extra plotly_selected event on the first click
// with undefined event data - but now that's gone, since `clickFn` handles this.
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh. Some users might currently rely on plotly_selected sending undefined as event data.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

put back the old behavior in 974cebf and commented in #420 about removing it later.

@etpinard
Copy link
Contributor

Well done. I'm a big fan of the doneFn / clickFn split in dragElement 🎉

I'm a little concern with how that affects plotly_selected event listeners that expect undefined (see #2241 (comment)). I hope there's a way to patch cartesian/select.js to leave the select_test.js suite unchanged, I don't think we can consider this a bug fix (in v1 at least).

@etpinard
Copy link
Contributor

Looks amazing 💃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Some folks are using right-click on data points in their apps
2 participants