Skip to content

nb/webagg: Move mouse events to outer canvas div #24095

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 1 commit into from
Oct 31, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 54 additions & 51 deletions lib/matplotlib/backends/web_backend/js/mpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ mpl.figure.prototype._init_canvas = function () {
var fig = this;

var canvas_div = (this.canvas_div = document.createElement('div'));
canvas_div.setAttribute('tabindex', '0');
canvas_div.setAttribute(
'style',
'border: 1px solid #ddd;' +
Expand All @@ -122,7 +123,8 @@ mpl.figure.prototype._init_canvas = function () {
'outline: 0;' +
'overflow: hidden;' +
'position: relative;' +
'resize: both;'
'resize: both;' +
'z-index: 2;'
);

function on_keyboard_event_closure(name) {
Expand All @@ -145,7 +147,13 @@ mpl.figure.prototype._init_canvas = function () {

var canvas = (this.canvas = document.createElement('canvas'));
canvas.classList.add('mpl-canvas');
canvas.setAttribute('style', 'box-sizing: content-box;');
canvas.setAttribute(
'style',
'box-sizing: content-box;' +
'pointer-events: none;' +
'position: relative;' +
'z-index: 0;'
);

this.context = canvas.getContext('2d');

Expand All @@ -165,7 +173,12 @@ mpl.figure.prototype._init_canvas = function () {
));
rubberband_canvas.setAttribute(
'style',
'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'
'box-sizing: content-box;' +
'left: 0;' +
'pointer-events: none;' +
'position: absolute;' +
'top: 0;' +
'z-index: 1;'
);

// Apply a ponyfill if ResizeObserver is not implemented by browser.
Expand Down Expand Up @@ -215,10 +228,10 @@ mpl.figure.prototype._init_canvas = function () {
canvas.setAttribute('width', width * fig.ratio);
canvas.setAttribute('height', height * fig.ratio);
}
canvas.setAttribute(
'style',
'width: ' + width + 'px; height: ' + height + 'px;'
);
/* This rescales the canvas back to display pixels, so that it
* appears correct on HiDPI screens. */
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';

rubberband_canvas.setAttribute('width', width);
rubberband_canvas.setAttribute('height', height);
Expand All @@ -234,34 +247,53 @@ mpl.figure.prototype._init_canvas = function () {
this.resizeObserverInstance.observe(canvas_div);

function on_mouse_event_closure(name) {
return function (event) {
return fig.mouse_event(event, name);
};
/* User Agent sniffing is bad, but WebKit is busted:
* https://bugs.webkit.org/show_bug.cgi?id=144526
* https://bugs.webkit.org/show_bug.cgi?id=181818
* The worst that happens here is that they get an extra browser
* selection when dragging, if this check fails to catch them.
*/
var UA = navigator.userAgent;
var isWebKit = /AppleWebKit/.test(UA) && !/Chrome/.test(UA);
if(isWebKit) {
return function (event) {
/* This prevents the web browser from automatically changing to
* the text insertion cursor when the button is pressed. We
* want to control all of the cursor setting manually through
* the 'cursor' event from matplotlib */
event.preventDefault()
return fig.mouse_event(event, name);
};
} else {
return function (event) {
return fig.mouse_event(event, name);
};
}
}

rubberband_canvas.addEventListener(
canvas_div.addEventListener(
'mousedown',
on_mouse_event_closure('button_press')
);
rubberband_canvas.addEventListener(
canvas_div.addEventListener(
'mouseup',
on_mouse_event_closure('button_release')
);
rubberband_canvas.addEventListener(
canvas_div.addEventListener(
'dblclick',
on_mouse_event_closure('dblclick')
);
// Throttle sequential mouse events to 1 every 20ms.
rubberband_canvas.addEventListener(
canvas_div.addEventListener(
'mousemove',
on_mouse_event_closure('motion_notify')
);

rubberband_canvas.addEventListener(
canvas_div.addEventListener(
'mouseenter',
on_mouse_event_closure('figure_enter')
);
rubberband_canvas.addEventListener(
canvas_div.addEventListener(
'mouseleave',
on_mouse_event_closure('figure_leave')
);
Expand Down Expand Up @@ -289,7 +321,7 @@ mpl.figure.prototype._init_canvas = function () {
};

// Disable right mouse context menu.
this.rubberband_canvas.addEventListener('contextmenu', function (_e) {
canvas_div.addEventListener('contextmenu', function (_e) {
event.preventDefault();
return false;
});
Expand Down Expand Up @@ -444,7 +476,7 @@ mpl.figure.prototype.handle_figure_label = function (fig, msg) {
};

mpl.figure.prototype.handle_cursor = function (fig, msg) {
fig.rubberband_canvas.style.cursor = msg['cursor'];
fig.canvas_div.style.cursor = msg['cursor'];
};

mpl.figure.prototype.handle_message = function (fig, msg) {
Expand Down Expand Up @@ -556,30 +588,6 @@ mpl.figure.prototype._make_on_message_function = function (fig) {
};
};

// from https://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas
mpl.findpos = function (e) {
//this section is from http://www.quirksmode.org/js/events_properties.html
var targ;
if (!e) {
e = window.event;
}
if (e.target) {
targ = e.target;
} else if (e.srcElement) {
targ = e.srcElement;
}
if (targ.nodeType === 3) {
// defeat Safari bug
targ = targ.parentNode;
}

// pageX,Y are the mouse positions relative to the document
var boundingRect = targ.getBoundingClientRect();
var x = e.pageX - (boundingRect.left + document.body.scrollLeft);
var y = e.pageY - (boundingRect.top + document.body.scrollTop);

return { x: x, y: y };
};

/*
* return a copy of an object with only non-object keys
Expand All @@ -596,15 +604,15 @@ function simpleKeys(original) {
}

mpl.figure.prototype.mouse_event = function (event, name) {
var canvas_pos = mpl.findpos(event);

if (name === 'button_press') {
this.canvas.focus();
this.canvas_div.focus();
}

var x = canvas_pos.x * this.ratio;
var y = canvas_pos.y * this.ratio;
// from https://stackoverflow.com/q/1114465
var boundingRect = this.canvas.getBoundingClientRect();
var x = (event.clientX - boundingRect.left) * this.ratio;
var y = (event.clientY - boundingRect.top) * this.ratio;

this.send_message(name, {
x: x,
Expand All @@ -614,11 +622,6 @@ mpl.figure.prototype.mouse_event = function (event, name) {
guiEvent: simpleKeys(event),
});

/* This prevents the web browser from automatically changing to
* the text insertion cursor when the button is pressed. We want
* to control all of the cursor setting manually through the
* 'cursor' event from matplotlib */
event.preventDefault();
return false;
};

Expand Down