-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Js fixes for key events + ipython notebooks #3965
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
Conversation
Reported by @eyurtsev
It was unhappy without it (no idea why)
- added hooks to inject style onto elements before they are added to the DOM (this might be excessive/an anti pattern, but I have been doing js for < 6 hrs and this worked) - re-ordered to group things in a way that made more sense to me
Changed from the canvas to the canvas div Not strictly sure this is the right thing to do, but it was on the path to get things working.
Don't let the handling keep bubbling up from this function. Again, not sure this is the right thing to do/if it matters.
- need to make the canvas_div 'focusable' - register the element with the keyboard manager
I broke this up into a bunch of commits as I spent a long time wandering before I sorted out what the problem was. They can be squashed/discarded before merge. Also just realized that I should have been doing this against 1.4.x..... |
Works for me! Yay! |
I'd say that it should lose focus when the mouse is not there. Also, there is probably a CSS setting to not draw a box around it when it has focus (it interferes with the navigation bar). |
The following diff removes the outline: diff --git a/lib/matplotlib/backends/web_backend/mpl.js b/lib/matplotlib/backends/web_backend/mpl.js
index 1836488..b619018 100644
--- a/lib/matplotlib/backends/web_backend/mpl.js
+++ b/lib/matplotlib/backends/web_backend/mpl.js
@@ -112,8 +112,7 @@ mpl.figure.prototype._init_canvas = function() {
function(event, ui) { fig.request_resize(ui.size.width, ui.size.height); }
, 50)});
- canvas_div.attr('style', 'position: relative; clear: both;');
-
+ canvas_div.attr('style', 'position: relative; clear: both; outline: 0');
function canvas_keyboard_event(event) {
return fig.key_event(event, event['data']); |
Diff including mouseout handling: diff --git a/lib/matplotlib/backends/web_backend/mpl.js b/lib/matplotlib/backends/web_backend/mpl.js
index 1836488..2adcb2f 100644
--- a/lib/matplotlib/backends/web_backend/mpl.js
+++ b/lib/matplotlib/backends/web_backend/mpl.js
@@ -112,8 +112,7 @@ mpl.figure.prototype._init_canvas = function() {
function(event, ui) { fig.request_resize(ui.size.width, ui.size.height); }
, 50)});
- canvas_div.attr('style', 'position: relative; clear: both;');
-
+ canvas_div.attr('style', 'position: relative; clear: both; outline: 0');
function canvas_keyboard_event(event) {
return fig.key_event(event, event['data']);
@@ -145,6 +144,11 @@ mpl.figure.prototype._init_canvas = function() {
canvas_div.append(canvas);
canvas_div.append(rubberband);
+ function mouse_out_fn(event) {
+ canvas_div.blur();
+ }
+ canvas_div.on("mouseout", mouse_out_fn);
+
this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d"); |
- remove frame around canvas_div - add mouse-out event to release focus (restoring the keyboard manager snarfing of the keyevents) when the mouse leaves the
@blink1073 added your diff (faking you as the author). |
// off when our div gets focus | ||
|
||
// location in version 3 | ||
// IPython.notebook.keyboard_manager.register_events(canvas_div); |
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.
Yeah, we're going to have to know the IPython version in our JS aren't we? I wanted to avoid it, but there is no alternative as fas as I can see.
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.
FWIW, they kept IPython.keyboard_manager
as an alias for backward compatibility.
@tacaswell - great work. Congratulations on digging into such a complex codebase - there is a lot going on here (mpl backends, mpl web agg backend, mpl nbagg backend, IPython, IPython's JS, browser interactions etc etc.) and you seem to have kept the changes in keeping with the existing codebase. 👍 Can you put a UAT in https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/web_backend/nbagg_uat.ipynb which describes and tests the functionality? Sadly, I'm not a sophisticated enough JS developer to have automated testing so I pumped for the manual testing approach instead. Also, could you confirm that you've tested these changes and they don't break the web_agg backend? As for when the keyboard event should get focus, I'm not the biggest fan of needing the mouse over the figure, but equally, I can't think of a better approach on a page which potentially has multiple figures. Finally, it would be good to figure out what is needed to get I think this can certainly be targeted at v1.4.x (one could argue it is adding a feature, but nbagg is sufficiently experimental in v1.4 that I'm comfortable with making minor improvements for the benefit of fixing a few compatibility issues). Other than that, awesome! 👍 |
I started to look at the I am enthusiastic about getting these fixes into 1.4.3 as skimage is looking at using nbagg to replace their qt-based image-viewer code so we should do our best to support that. It also means that nbagg will get it's tires kicked/exposure which is good. |
I am not an expert in focus issues, but from what I have encountered OTOH, perhaps nbagg is probably more akin to an embedding situation rather As a side note, if the focus terminates when the mouse leaves the figure, On Sun, Jan 4, 2015 at 10:47 AM, Thomas A Caswell notifications@github.com
|
The following diff makes it behave more like a figure in a Qt window (focus on creation and when the user clicks on the figure): diff --git a/lib/matplotlib/backends/web_backend/mpl.js b/lib/matplotlib/backends/web_backend/mpl.js
index d9053d8..7aee81c 100644
--- a/lib/matplotlib/backends/web_backend/mpl.js
+++ b/lib/matplotlib/backends/web_backend/mpl.js
@@ -120,6 +120,7 @@ mpl.figure.prototype._init_canvas = function() {
canvas_div.keydown('key_press', canvas_keyboard_event);
canvas_div.keydown('key_release', canvas_keyboard_event);
+
this.canvas_div = canvas_div
this._canvas_extra_style(canvas_div)
this.root.append(canvas_div);
@@ -144,11 +145,6 @@ mpl.figure.prototype._init_canvas = function() {
canvas_div.append(canvas);
canvas_div.append(rubberband);
- function mouse_out_fn(event) {
- canvas_div.blur();
- }
- canvas_div.on("mouseout", mouse_out_fn);
-
this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d");
@@ -412,7 +408,7 @@ mpl.findpos = function(e) {
mpl.figure.prototype.mouse_event = function(event, name) {
var canvas_pos = mpl.findpos(event)
- if (this.focus_on_mouseover && name === 'motion_notify')
+ if (name === 'button_press')
{
this.canvas_div.focus();
}
diff --git a/lib/matplotlib/backends/web_backend/nbagg_mpl.js b/lib/matplotlib/backends/web_backend/nbagg_mpl.js
index 7706891..d08b7ca 100644
--- a/lib/matplotlib/backends/web_backend/nbagg_mpl.js
+++ b/lib/matplotlib/backends/web_backend/nbagg_mpl.js
@@ -49,6 +49,8 @@ mpl.mpl_figure_comm = function(comm, msg) {
return false;
});
+ fig.canvas_div.focus();
+
};
mpl.figure.prototype.handle_close = function(fig, msg) { |
Better version of the previous (affects webagg as well): diff --git a/lib/matplotlib/backends/web_backend/mpl.js b/lib/matplotlib/backends/web_backend/mpl.js
index d9053d8..54bccdb 100644
--- a/lib/matplotlib/backends/web_backend/mpl.js
+++ b/lib/matplotlib/backends/web_backend/mpl.js
@@ -120,6 +120,7 @@ mpl.figure.prototype._init_canvas = function() {
canvas_div.keydown('key_press', canvas_keyboard_event);
canvas_div.keydown('key_release', canvas_keyboard_event);
+
this.canvas_div = canvas_div
this._canvas_extra_style(canvas_div)
this.root.append(canvas_div);
@@ -144,11 +145,6 @@ mpl.figure.prototype._init_canvas = function() {
canvas_div.append(canvas);
canvas_div.append(rubberband);
- function mouse_out_fn(event) {
- canvas_div.blur();
- }
- canvas_div.on("mouseout", mouse_out_fn);
-
this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d");
@@ -170,6 +166,8 @@ mpl.figure.prototype._init_canvas = function() {
// Set the figure to an initial 600x600px, this will subsequently be updated
// upon first draw.
this._resize_canvas(600, 600);
+
+ this.canvas_div.focus();
}
mpl.figure.prototype._init_toolbar = function() {
@@ -412,7 +410,7 @@ mpl.findpos = function(e) {
mpl.figure.prototype.mouse_event = function(event, name) {
var canvas_pos = mpl.findpos(event)
- if (this.focus_on_mouseover && name === 'motion_notify')
+ if (name === 'button_press')
{
this.canvas_div.focus();
} |
Sad panda 😦, |
It looks like |
I may have been mistaken about |
Another diff for you, that allows keyboard events in both diff --git a/lib/matplotlib/backends/web_backend/mpl.js b/lib/matplotlib/backends/web_backend/mpl.js
index d9053d8..6ff5f33 100644
--- a/lib/matplotlib/backends/web_backend/mpl.js
+++ b/lib/matplotlib/backends/web_backend/mpl.js
@@ -414,6 +414,7 @@ mpl.figure.prototype.mouse_event = function(event, name) {
if (this.focus_on_mouseover && name === 'motion_notify')
{
+ this.canvas.focus();
this.canvas_div.focus();
} |
Steven, it is great that you are helping Thomas out with this, I know I On Sun, Jan 4, 2015 at 12:56 PM, Steven Silvester notifications@github.com
|
@WeatherGod, I'm more throwing out ideas than anything (shots in the dark), but point taken. I still can't figure out how to get |
If I can help with anything specific, just shout - I don't have a huge amount of bandwidth, but I'll happily try to help. |
Victory! (PR sent). |
@tacaswell, we'll have to tackle |
Right, sorry forgot about that last night. On Tue, Jan 6, 2015, 02:02 Phil Elson notifications@github.com wrote:
|
// off when our div gets focus | ||
|
||
// location in version 3 | ||
if (typeof IPython.notebook.keyboard_manager != 'undefined') { |
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.
I think the canonical way of doing this is if (IPython.notebook.keyboard_manager)
.
@pelson Is that what you had in mind for the UAT? |
Exactly. I didn't run it yet, but the test seems well described and I imagine it is working for you so 👍 from me. |
@@ -93,6 +94,15 @@ mpl.figure.prototype._init_header = function() { | |||
this.header = titletext[0]; | |||
} | |||
|
|||
mpl.figure.prototype._canvas_extra_style = function(canvas_div){ |
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.
Please insert a space before the {
Just the one minor style nit. Other than that this seems to "work for me"[TM], so 👍 |
@tacaswell, it looks like the error is tangential, perhaps just restart that one job? |
Restarted |
@@ -394,9 +413,10 @@ mpl.findpos = function(e) { | |||
mpl.figure.prototype.mouse_event = function(event, name) { | |||
var canvas_pos = mpl.findpos(event) | |||
|
|||
if (this.focus_on_mouseover && name === 'motion_notify') | |||
if (name === 'button_press') |
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.
I'm not entirely certain why motion notify is no longer important. Would you mind talking me through it? Does the status bar (with the x and y coordinates) still work with this change?
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.
My take: we switched to a more Qt-like focus policy, in that the figure takes focus immediately and upon clicking. When the figure has focus, the status bar receives updates.
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.
I stand corrected, the motion_notify event is triggered regardless of focus, and the coordinates are updated (I just ran the example code).
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.
The mouse-move events fire independent of the focus state of the figure. The reason that we had to go through such contortions to get the key events to work is that IPython has a handler at the top of the document tree that eats all of the keyboard events and uses them for their own shortcuts.
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.
er, sorry, for the repeat, my gh got logged out due to having issues with ipython + js + clearing the cache and didn't see above until I had already posted.
Js fixes for key events + ipython notebooks
Thanks @tacaswell. I merged, though I still have one outstanding question (see above re status bar). |
It should have been against 1.4.x, but I screwed up, I will back-port. |
and @blink1073 should get much of the credit here |
Yay! Where do I redeem my bitcoin-XP? 😄 |
A bar in Austin in July? 😄 |
Perfect. |
Say that after experiencing Austin in July... On Sun, Jan 11, 2015 at 4:52 PM, Steven Silvester notifications@github.com
|
I was at the conference last year, and being from Florida it was actually quite nice (less humid). |
Js fixes for key events + ipython notebooks
backported as 893352f |
First pass at getting key events to work in ipython notebooks
Closes #3963
Demo, mouse over the figure to give it focus. Clicking any mouse button or pushing any key should color-cycle the line.
Remaining issues: