Repository: holoviz/panel

Issue:
[vtk] keypress event bug
When using `panel`'s new VTK functionality in a Joptyer notebook, the panel listens to key events outside of its scope. 

When writing new code in a different cell, buttons like `v` and `s` alter the scene - this is unexpected behavior. See example below using `vtki` which sends its renderer to panel's VTK code:

![ezgif com-video-to-gif-3](https://user-images.githubusercontent.com/22067021/56014852-24a25d80-5cb4-11e9-991e-2f48bae53b61.gif)



Discussion:
I don't know if we can do something about it. However we sould document the key bindings somwhere.
> we should document the key bindings somewhere.

I definitely agree that they should be documented - I only discovered `v` for vertex/point representation and `s` for surface by typing code slowly.

> I don't know if we can do something about it.

I think this is a `panel` issue. If you display a VTKjs rendering via HTML this behavior is not experienced:

```py

from IPython.core.display import display, HTML
display(HTML(
'''
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; height: auto;">
        <iframe src="http://volcano.pvgeo.org" frameborder="0" allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
    </div>
'''))
```


![ezgif com-video-to-gif-5](https://user-images.githubusercontent.com/22067021/56016089-6c2ae880-5cb8-11e9-8e41-15e4639a3b5c.gif)


`panel` is on top, HTML is bottom. Note that the HTML output is simply pointing to this url: http://volcano.pvgeo.org which has keyboard shortcuts when on the webpage but not in the notebook
The other thing to note is that this is causing a noticeable lag when typing `s`, `v`, `w`, or other keys that affect the `panel` scene.

If a notebook has more than a few VTK panel scenes, then adding new code with the letters `v`, `s`, or `w` will heavily lag the notebook (and be quite an annoyance). For example, typing `examples.download_st_helens().warp_by_scalar().plot()` took almost a minute after loading up 5 other scenes:

![ezgif com-video-to-gif-6](https://user-images.githubusercontent.com/22067021/56016659-3edf3a00-5cba-11e9-900d-6c681be66a14.gif)



key events are set by vtkjs interactor:
https://github.com/Kitware/vtk-js/blob/cc48e943037e0ed980c5e370b0e716df3309a5b2/Sources/Rendering/Core/RenderWindowInteractor/index.js#L214-L222

They are attached to the document body so it's not a panel bug.
What I can try to do is to add an option to activate or deactivate keybindings
Does something like this would be sufficient?

![ezgif com-video-to-gif (7)](https://user-images.githubusercontent.com/18531147/56023289-d91c9d80-5d0d-11e9-95c3-d221cdb9963e.gif)


Resolving patch:
diff --git a/panel/models/vtk.py b/panel/models/vtk.py
--- a/panel/models/vtk.py
+++ b/panel/models/vtk.py
@@ -31,6 +31,8 @@ class VTKPlot(HTMLBox):
 
     camera = Dict(String, Any)
 
+    enable_keybindings = Bool(default=False)
+
     height = Override(default=300)
 
     width = Override(default=300)
diff --git a/panel/pane/vtk.py b/panel/pane/vtk.py
--- a/panel/pane/vtk.py
+++ b/panel/pane/vtk.py
@@ -331,6 +331,13 @@ class VTK(PaneBase):
 
     camera = param.Dict(doc="""State of the rendered VTK camera.""")
 
+    enable_keybindings = param.Boolean(default=False, doc="""
+        Activate/Deactivate keys binding.
+
+        Warning: These keys bind may not work as expected in a notebook
+        context if they interact with already binded keys
+    """)
+
     _updates = True
 
     @classmethod
@@ -358,7 +365,7 @@ def _get_model(self, doc, root=None, parent=None, comm=None):
         model = VTKPlot(data=data, **props)
         if root is None:
             root = model
-        self._link_props(model, ['data', 'camera'], doc, root, comm)
+        self._link_props(model, ['data', 'camera', 'enable_keybindings'], doc, root, comm)
         self._models[root.ref['id']] = (model, parent)
         return model
 
@@ -404,7 +411,7 @@ def _vtksjs_from_render_window(self, render_window):
                     mapper = renProp.GetMapper()
                     if mapper is None:
                         continue
-                    dataObject = mapper.GetInputDataObject(0, 0);
+                    dataObject = mapper.GetInputDataObject(0, 0)
                     dataset = None
 
                     if dataObject.IsA('vtkCompositeDataSet'):
@@ -422,7 +429,7 @@ def _vtksjs_from_render_window(self, render_window):
                         dataset = gf.GetOutput()
                     else:
                         dataset = mapper.GetInput()
-                        
+
                     if dataset and not isinstance(dataset, (vtk.vtkPolyData)):
                         # All data must be PolyData surfaces!
                         gf = vtk.vtkGeometryFilter()
@@ -471,7 +478,7 @@ def _vtksjs_from_render_window(self, render_window):
 
                         if dataArray:
                             # component = -1 => let specific instance get scalar from vector before mapping
-                            colorArray = lookupTable.MapScalars(dataArray, colorMode, -1);
+                            colorArray = lookupTable.MapScalars(dataArray, colorMode, -1)
                             colorArrayName = '__CustomRGBColorArray__'
                             colorArray.SetName(colorArrayName)
                             colorMode = 0
@@ -489,7 +496,7 @@ def _vtksjs_from_render_window(self, render_window):
                         textureName = None
                         if renProp.GetTexture() and renProp.GetTexture().GetInput():
                             textureData = renProp.GetTexture().GetInput()
-                            textureName = 'texture_%d' % _get_object_id(textureData, objIds);
+                            textureName = 'texture_%d' % _get_object_id(textureData, objIds)
                             textureToSave[textureName] = textureData
 
                         representation = renProp.GetProperty().GetRepresentation() if hasattr(renProp, 'GetProperty') else 2


Test patch: