Hi!
First of all, thank you so much for your work on Trame/VTK/WASM.
I’ve got an issue where zooming while hovering the cursor over different render viewports always zoomes the first renderer. I’m using the LocalView
from trame.widgets.vtklocal
.
Relevant package versions:
$ python -V
Python 3.13.1
$ pip list | grep -e 'vtk' -e 'trame'
trame 3.12.0
trame-client 3.10.1
trame-common 1.0.1
trame-components 2.5.0
trame-server 3.6.0
trame-vtk 2.9.1
trame-vtklocal 0.15.2
trame-vuetify 3.0.2
vtk 9.5.20250531.dev0
Here’s fairly minimal example using the multiple viewports VTK example (https://examples.vtk.org/site/Python/Visualization/MultipleViewports/) and a simple app layout with Trame. Running in a Jupyter kernel (VS Code or split on # %%
as individual cells in a Jupyter notebook):
# %%
# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkFiltersSources import (
vtkConeSource,
vtkCubeSource,
vtkCylinderSource,
vtkSphereSource,
)
from vtk import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderer,
vtkRenderWindow,
vtkRenderWindowInteractor,
)
from trame.app import get_server
from trame.ui.vuetify3 import VAppLayout
from trame.widgets import vtklocal, vtk as trame_vtk, vuetify3
def main(local: bool = True):
# One render window, multiple viewports.
rw = vtkRenderWindow()
iren = vtkRenderWindowInteractor()
iren.SetInteractorStyle(vtkInteractorStyleTrackballCamera())
iren.SetRenderWindow(rw)
# Define viewport ranges.
xmins = [0, 0.5, 0, 0.5]
xmaxs = [0.5, 1, 0.5, 1]
ymins = [0, 0, 0.5, 0.5]
ymaxs = [0.5, 0.5, 1, 1]
sources = get_sources()
for i in range(4):
ren = vtkRenderer()
rw.AddRenderer(ren)
ren.SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i])
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(sources[i].GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)
ren.AddActor(actor)
ren.ResetCamera()
layout = setup_trame(rw, local)
return layout
def get_sources():
sources = list()
# Create a sphere
sphere = vtkSphereSource()
sphere.SetCenter(0.0, 0.0, 0.0)
sphere.Update()
sources.append(sphere)
# Create a cone
cone = vtkConeSource()
cone.SetCenter(0.0, 0.0, 0.0)
cone.SetDirection(0, 1, 0)
cone.Update()
sources.append(cone)
# Create a cube
cube = vtkCubeSource()
cube.SetCenter(0.0, 0.0, 0.0)
cube.Update()
sources.append(cube)
# Create a cylinder
cylinder = vtkCylinderSource()
cylinder.SetCenter(0.0, 0.0, 0.0)
cylinder.Update()
sources.append(cylinder)
return sources
def setup_trame(rw: vtkRenderWindow, local: bool) -> VAppLayout:
server = get_server(client_type="vue3")
ctrl = server.controller
with VAppLayout(server) as layout:
with vuetify3.VContainer(
fluid=True, classes="pa-0 fill-height", trame_server=server
):
with vuetify3.VContainer(fluid=True, classes="pa-0 fill-height"):
if local:
setup_local_view(rw, ctrl)
else:
setup_remove_view(rw, ctrl)
return layout
def setup_local_view(rw: vtkRenderWindow, controller) -> None:
view = vtklocal.LocalView(rw)
controller.view_update = view.update_throttle
controller.view_reset_camera = view.reset_camera
def setup_remove_view(rw: vtkRenderWindow, controller) -> None:
view = trame_vtk.VtkRemoteView(rw)
controller.view_update = view.update
controller.view_reset_camera = view.reset_camera
# %%
layout = main(local=True)
await layout.ready
layout
Result: [Cannot upload a short 7s video as I’m a new user.]