From 5f91d86693b3330d1e88eb29631fd2bccfa3181e Mon Sep 17 00:00:00 2001 From: martinRenou Date: Tue, 25 Feb 2020 11:54:01 +0100 Subject: [PATCH] Add stop button Signed-off-by: martinRenou --- ipympl/backend_nbagg.py | 9 ++++++--- js/src/mpl_widget.js | 40 ++++++++++++++++++++++++++++++++-------- js/src/toolbar_widget.js | 17 +++++++++++++++++ 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/ipympl/backend_nbagg.py b/ipympl/backend_nbagg.py index b5f04c58..1ba2c2b6 100644 --- a/ipympl/backend_nbagg.py +++ b/ipympl/backend_nbagg.py @@ -152,7 +152,12 @@ class Canvas(DOMWidget, FigureCanvasWebAggCore): header_visible = Bool(True).tag(sync=True) + width = Float(0, read_only=True).tag(sync=True) + height = Float(0, read_only=True).tag(sync=True) + _closed = Bool(True) + closed = Bool(False, read_only=True).tag(sync=True) + _data_url = Unicode(None, allow_none=True, read_only=True).tag(sync=True) # Must declare the superclass private members. _png_is_old = Bool() @@ -174,9 +179,7 @@ def __init__(self, figure, *args, **kwargs): def _handle_message(self, object, content, buffers): # Every content has a "type". - if content['type'] == 'closing': - self._closed = True - elif content['type'] == 'initialized': + if content['type'] == 'initialized': _, _, w, h = self.figure.bbox.bounds self.manager.resize(w, h) else: diff --git a/js/src/mpl_widget.js b/js/src/mpl_widget.js index 4768b63b..bacd6260 100644 --- a/js/src/mpl_widget.js +++ b/js/src/mpl_widget.js @@ -19,6 +19,10 @@ var MPLCanvasModel = widgets.DOMWidgetModel.extend({ header_visible: true, toolbar: null, toolbar_visible: true, + closed: false, + _data_url: null, + width: 0, + height: 0, toolbar_position: 'horizontal' }); } @@ -38,7 +42,6 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ this.image_mode = 'full'; this.figure = document.createElement('div'); - this.figure.addEventListener('remove', this.close.bind(this)); this.figure.classList = 'jupyter-matplotlib-figure jupyter-widgets widget-container widget-box widget-vbox'; this._init_header(); @@ -53,6 +56,8 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ return this.create_child_view(this.model.get('toolbar')).then(function(toolbar_view) { that.toolbar_view = toolbar_view; + toolbar_view.on('close',that.handle_close.bind(that)); + that.update_toolbar_position(); that.update_header_visible(); @@ -72,6 +77,10 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ }, send_initialization_message: function() { + if (this.model.get('closed')) { + return; + } + if (this.ratio != 1) { this.send_message('set_dpi_ratio', {'dpi_ratio': this.ratio}); } @@ -86,7 +95,7 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ }, update_toolbar_visible: function() { - this.toolbar_view.el.style.display = this.model.get('toolbar_visible') ? '' : 'none'; + this.toolbar_view.el.style.display = this.model.get('toolbar_visible') && !this.model.get('closed') ? '' : 'none'; }, update_toolbar_position: function() { @@ -126,6 +135,14 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ } }, + handle_close: function() { + this.model.set('_data_url', this.canvas.toDataURL()); + this.model.set('closed', true); + this.model.save_changes(); + + this.update_toolbar_visible(); + }, + _init_header: function() { this.header = document.createElement('div'); this.header.style.textAlign = 'center'; @@ -208,6 +225,9 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ // almost always do), so we need to clear the canvas so that // there is no ghosting. that.context.clearRect(0, 0, that.canvas.width, that.canvas.height); + if (that.model.get('width') != that.canvas.width || that.model.get('height') != that.canvas.height) { + that._resize_canvas(that.model.get('width'), that.model.get('height')); + } } that.context.drawImage(that.image, 0, 0); }; @@ -215,6 +235,12 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ this.image.onunload = function() { that.close(); } + + // Draw saved state if the communication is closed + if (this.model.get('closed')) { + this.image_mode = 'full'; + this.image.src = this.model.get('_data_url'); + } }, _init_footer: function() { @@ -266,7 +292,10 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ if (size[0] != this.canvas.width || size[1] != this.canvas.height) { this._resize_canvas(size[0], size[1]); this.send_message('refresh'); - }; + } + this.model.set('width', size[0]); + this.model.set('height', size[1]); + this.model.save_changes(); }, handle_rubberband: function(msg) { @@ -442,11 +471,6 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ that.send_message(name, {key: value, guiEvent: utils.get_simple_keys(event)}); return false; }; - }, - - close: function(){ - this.send_message('closing'); - this.trigger('close'); } }); diff --git a/js/src/toolbar_widget.js b/js/src/toolbar_widget.js index 90282249..2fb95796 100644 --- a/js/src/toolbar_widget.js +++ b/js/src/toolbar_widget.js @@ -44,6 +44,19 @@ var ToolbarView = widgets.DOMWidgetView.extend({ icon.classList = 'center fa fa-bars'; this.toggle_button.appendChild(icon); + this.stop_button = document.createElement('button'); + + this.stop_button.classList = 'jupyter-matplotlib-button jupyter-widgets jupyter-button mod-danger'; + this.stop_button.setAttribute('href', '#'); + this.stop_button.setAttribute('title', 'Stop Interactions and embed'); + this.stop_button.style.outline = 'none'; + this.stop_button.addEventListener('click', this.handle_stop.bind(this)); + + var close_icon = document.createElement('i'); + close_icon.classList = 'center fa fa-times'; + this.stop_button.appendChild(close_icon); + + this.el.appendChild(this.stop_button); this.el.appendChild(this.toggle_button); this.toolbar = document.createElement('div'); this.toolbar.classList = 'widget-container widget-box'; @@ -152,6 +165,10 @@ var ToolbarView = widgets.DOMWidgetView.extend({ this.toolbar.style.display = visible ? 'none' : ''; }, + handle_stop: function() { + this.trigger('close'); + }, + model_events: function() { this.model.on('change:orientation', this.update_orientation.bind(this)); this.model.on('change:button_style', this.set_buttons_style.bind(this));