8000 Js fixes for key events + ipython notebooks by tacaswell · Pull Request #3965 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

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

Merged
merged 14 commits into from
Jan 11, 2015
Merged
Show file tree
Hide file tree
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
59 changes: 40 additions & 19 deletions lib/matplotlib/backends/web_backend/mpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ mpl.figure = function(figure_id, websocket, ondownload, parent_element) {
this.rubberband_context = undefined;
this.format_dropdown = undefined;

this.focus_on_mousover = false;
this.image_mode = 'full';

this.root = $('<div/>');
this._root_extra_style(this.root)
this.root.attr('style', 'display: inline-block');

$(parent_element).append(this.root);

this._init_header(this);
Expand Down Expand Up @@ -93,6 +94,15 @@ mpl.figure.prototype._init_header = function() {
this.header = titletext[0];
}

mpl.figure.prototype._canvas_extra_style = function(canvas_div) {

}


mpl.figure.prototype._root_extra_style = function(canvas_div) {

}

mpl.figure.prototype._init_canvas = function() {
var fig = this;

Expand All @@ -101,17 +111,22 @@ 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;');
this.root.append(canvas_div);

var canvas = $('<canvas/>');
canvas.addClass('mpl-canvas');
canvas.attr('style', "left: 0; top: 0; z-index: 0;")
canvas_div.attr('style', 'position: relative; clear: both; outline: 0');

function canvas_keyboard_event(event) {
return fig.key_event(event, event['data']);
}

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);

var canvas = $('<canvas/>');
canvas.addClass('mpl-canvas');
canvas.attr('style', "left: 0; top: 0; z-index: 0; outline: 0")

this.canvas = canvas[0];
this.context = canvas[0].getContext("2d");

Expand All @@ -128,9 +143,6 @@ mpl.figure.prototype._init_canvas = function() {
canvas_div.append(canvas);
canvas_div.append(rubberband);

canvas_div.keydown('key_press', canvas_keyboard_event);
canvas_div.keydown('key_release', canvas_keyboard_event);

this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d");
Expand All @@ -152,6 +164,13 @@ 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);

function set_focus () {
canvas.focus();
canvas_div.focus();
}

window.setTimeout(set_focus, 100);
}

mpl.figure.prototype._init_toolbar = function() {
Expand All @@ -169,7 +188,7 @@ mpl.figure.prototype._init_toolbar = function() {
return fig.toolbar_button_onmouseover(event['data']);
}

for(var toolbar_ind in mpl.toolbar_items){
for(var toolbar_ind in mpl.toolbar_items) {
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
Expand Down Expand Up @@ -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')
Copy link
Member

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?

Copy link
Member

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.

Copy link
Member

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).

Copy link
Member Author

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.

Copy link
Member Author

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.

{
this.canvas.focus();
this.canvas_div.focus();
}

var x = canvas_pos.x;
Expand All @@ -419,7 +439,7 @@ mpl.figure.prototype.key_event = function(event, name) {
return;
}

value = '';
var value = '';
if (event.ctrlKey) {
value += "ctrl+";
}
Expand All @@ -429,6 +449,7 @@ mpl.figure.prototype.key_event = function(event, name) {
value += String.fromCharCode(event.keyCode).toLowerCase();

this.send_message(name, {key: value});
return false;
}

mpl.figure.prototype.toolbar_button_onclick = function(name) {
Expand All @@ -445,18 +466,18 @@ mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {
this.message.textContent = tooltip;
};

mpl.debounce_event = function(func, time){
mpl.debounce_event = function(func, time) {
var timer;
return function(event){
return function(event) {
clearTimeout(timer);
timer = setTimeout(function(){ func(event); }, time);
timer = setTimeout(function() { func(event); }, time);
};
}

mpl.debounce_resize = function(func, time){
mpl.debounce_resize = function(func, time) {
var timer;
return function(event, ui){
return function(event, ui) {
clearTimeout(timer);
timer = setTimeout(function(){ func(event, ui); }, time);
timer = setTimeout(function() { func(event, ui); }, time);
};
}
19 changes: 19 additions & 0 deletions lib/matplotlib/backends/web_backend/nbagg_mpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,25 @@ mpl.figure.prototype._init_toolbar = function() {
titlebar.prepend(buttongrp);
}


mpl.figure.prototype._canvas_extra_style = function(el){
// this is important to make the div 'focusable
el.attr('tabindex', 0)
// reach out to IPython and tell the keyboard manager to turn it's self
// off when our div gets focus

// location in version 3
if (IPython.notebook.keyboard_manager) {
IPython.notebook.keyboard_manager.register_events(el);
}
else {
// location in version 2
IPython.keyboard_manager.register_events(el);
}

}


mpl.find_output_cell = function(html_output) {
// Return the cell and output element which can be found *uniquely* in the notebook.
// Note - this is a bit hacky, but it is done because the "notebook_saving.Notebook"
Expand Down
48 changes: 46 additions & 2 deletions lib/matplotlib/backends/web_backend/nbagg_uat.ipynb
1E0A
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
{
"metadata": {
"name": "",
"signature": "sha256:1d491e506b54b126f6971897d3249a9e6f96f9d50bf4e4ba8d179c6b7b1aefa8"
"signature": "sha256:43daeaae8ae9fd496fc33d7a64639194bc009b755d28c23cd6329f225628197c"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": false,
"input": [
"from __future__ import print_function\n",
"from imp import reload"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -152,7 +163,7 @@
"cell_type": "code",
"collapsed": false,
"input": [
"print matplotlib.backends.backend_nbagg.connection_info()"
"print(matplotlib.backends.backend_nbagg.connection_info())"
],
"language": "python",
"metadata": {},
Expand Down Expand Up @@ -384,6 +395,39 @@
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### UAT 16 - key events\n",
"\n",
"Pressing any keyboard key or mouse button should cycle the line line while the figure has focus. The figure should have focus by default when it is created and re-gain it by clicking on the canvas. Clicking anywhere outside of the figure should release focus, but moving the mouse out of the figure should not release focus."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import itertools\n",
"fig, ax = plt.subplots()\n",
"x = np.linspace(0,10,10000)\n",
"y = np.sin(x)\n",
"ln, = ax.plot(x,y)\n",
"evt = []\n",
"colors = iter(itertools.cycle(['r', 'g', 'b', 'k', 'c']))\n",
"def on_event(event):\n",
" evt.append(event)\n",
" ln.set_color(next(colors))\n",
" fig.canvas.draw()\n",
" fig.canvas.draw_idle()\n",
"fig.canvas.mpl_connect('button_press_event', on_event)\n",
"fig.canvas.mpl_connect('key_press_event', on_event)\n",
"plt.show()"
],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
Expand Down
0