Skip to content

Feature Request: Make plotly_click events in 3d plots consistent with 2d #6185

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

Closed
CmpCtrl opened this issue May 10, 2022 · 2 comments
Closed

Comments

@CmpCtrl
Copy link

CmpCtrl commented May 10, 2022

There are some issues/limitations with the 3d plot events, particularly the click event, that aren't present in the equivalent 2d plots. It would really help their functionality to be consistent with the 2d events.

I've been working specifically with scatter3d (or surface) plots and the plotly_click event.

My biggest issue is that the plotly_click event is fired on mousedown (in a 2d scatter it is fired on mouseup). That makes it impossible to tell if the user is intending to select a point, or to click and drag to rotate/pan/zoom, etc. That is an issue since typically a callback related to selecting a point conflicts with a drag to rotate operation. Again, the 2d scatter behaves as intended.

Here is a simple demo, the click events are logged to the console, you'll note that in the 2d scatter, click and drag (to zoom) does not fire a plotly_click event, but doing the same thing in the 3d surface plot does fire the ploty_click before the drag functionality.
https://codepen.io/cmpctrl/pen/rNJLNLd

One thing i hoped to use to workaround this issue was to detect if the user right clicked on the plot. Unfotunately, the DOM MouseEvent data that is, very usefully, included in the 2d click_data is missing in the 3d plots.

Similarly, there is no plotly_doubleclick event for 3d.

Some related issues, there may be more.
#2565
#3266
#5590

@CmpCtrl
Copy link
Author

CmpCtrl commented May 10, 2022

I did a little more digging and it seems like it won't be easy to add the DOM MouseEvent data to the eventData but it should be relatively easy to add some more data to it, which at least would help with detecting which button is clicked..

I think the relevant section is here:

var pointData = {
x: selection.traceCoordinate[0],
y: selection.traceCoordinate[1],
z: selection.traceCoordinate[2],
data: traceNow._input,
fullData: traceNow,
curveNumber: traceNow.index,
pointNumber: ptNumber
};
Fx.appendArrayPointValue(pointData, traceNow, ptNumber);
if(trace._module.eventData) {
pointData = traceNow._module.eventData(pointData, selection, traceNow, {}, ptNumber);
}
var eventData = {points: [pointData]};

What about adding something like the following? Any other useful tidbits we could include here?

var eventData = {
    points: [pointData],
    buttons: selection.buttons,
    distance: selection.distance,
};

Then it seems like the plotly_click event could be moved from here, which happens at the start of a click and drag.

if(selection.buttons && selection.distance < 5) {
gd.emit('plotly_click', eventData);
} else {
gd.emit('plotly_hover', eventData);
}
this.oldEventData = eventData;
} else {
Fx.loneUnhover(svgContainer);
if(this.oldEventData) gd.emit('plotly_unhover', this.oldEventData);
this.oldEventData = undefined;
}
scene.drawAnnotations(scene);
};

While i was looking at this, i also noticed that the plotly_unhover fires at every step of a click or drag, which doesn't seem helpful. Perhaps that could be addressed at the same time.

Something like the following? This is completely untested...

        if (!selection.buttons && !selection.distance < 5) {
            gd.emit('plotly_hover', eventData);
            this.oldHoverState = true;
        }

        this.oldEventData = eventData;
    } else {
        Fx.loneUnhover(svgContainer);
        if (this.oldHoverState) {
            gd.emit('plotly_unhover', this.oldEventData);
        }
        this.oldHover = undefined;
        if (this.oldEventData && this.oldEventData.buttons && this.oldEventData.distance < 5) {
            gd.emit('plotly_click', this.oldEventData);
        }
        this.oldEventData = undefined;
    }

    scene.drawAnnotations(scene);
};

I hesitate to try to make a pr for this since i have almost no experience with js and dont feel like i understand it well enough to make a reliable change. Can i just add this.oldHoverState like that? or does that need to be defined elsewhere?

@gvwilson
Copy link
Contributor

gvwilson commented Jul 3, 2024

Hi - we are trying to tidy up the stale issues and PRs in Plotly's public repositories so that we can focus on things that are still important to our community. Since this one has been sitting for several years, I'm going to close it; if it is still a concern, please add a comment letting us know what recent version of our software you've checked it with so that I can reopen it and add it to our backlog. Thanks for your help - @gvwilson

@gvwilson gvwilson closed this as completed Jul 3, 2024
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

No branches or pull requests

2 participants