Kitware / vtk-js

Visualization Toolkit for the Web
https://kitware.github.io/vtk-js/
BSD 3-Clause "New" or "Revised" License
1.24k stars 373 forks source link

Multiple Instances of RemoteView #1568

Closed knopkem closed 3 years ago

knopkem commented 4 years ago

I'm trying to setup 2 vtkRemoteViews, each using a different 'app' (server side render code). This works with paravieweb but not with vtk.js. I tried setting a different viewNr to each vtkRemoteView but that doesn't seem to work either. With paraview, both views render correctly and interaction works too (minus some minor quirks) With vtk.js, both canvas render the same view, and interaction is only possible in one of them, changing both views.

Working Example paraviewweb:

import SmartConnect from 'wslink/src/SmartConnect';
import RemoteRenderer from 'paraviewweb/src/NativeUI/Canvas/RemoteRenderer';
import SizeHelper from 'paraviewweb/src/Common/Misc/SizeHelper';
import ParaViewWebClient from 'paraviewweb/src/IO/WebSocket/ParaViewWebClient';

document.body.style.padding = '0';
document.body.style.margin = '0';

function render(url) {
    const divRenderer = document.createElement('div');
    document.body.appendChild(divRenderer);

    divRenderer.style.position = 'relative';
    divRenderer.style.width = '50vw';
    divRenderer.style.height = '50vh';
    divRenderer.style.overflow = 'hidden';

    const config = { sessionURL: url };
    const smartConnect = SmartConnect.newInstance({ config });
    smartConnect.onConnectionReady((connection) => {
      console.log('connection ready');
      const pvwClient = ParaViewWebClient.createClient(connection, [
        'MouseHandler',
        'ViewPort',
        'ViewPortImageDelivery',
      ]);
      const renderer = new RemoteRenderer(pvwClient);
      renderer.setContainer(divRenderer);
      renderer.onImageReady(() => {
        console.log('We are good');
      });
      window.renderer = renderer;
      SizeHelper.onSizeChange(() => {
        renderer.resize();
      });
      SizeHelper.startListening();
    });
    smartConnect.connect();
}

render('ws://localhost:9999/ws');
render('ws://localhost:9998/ws');

Non working example with vtk.js:

import vtkWSLinkClient from "vtk.js/Sources/IO/Core/WSLinkClient";
import vtkRemoteView from 'vtk.js/Sources/Rendering/Misc/RemoteView';
import SmartConnect from 'wslink/src/SmartConnect';
import { connectImageStream } from "vtk.js/Sources/Rendering/Misc/RemoteView";

document.body.style.padding = '0';
document.body.style.margin = '0';

function render(url, id)
{
    const remoteView = vtkRemoteView.newInstance();

    const divRenderer = document.createElement('div');

    divRenderer.style.position = 'relative';
    divRenderer.style.width = '50vw';
    divRenderer.style.height = '50vh';
    divRenderer.style.overflow = 'hidden';

    document.querySelector('body').appendChild(divRenderer);
    remoteView.setContainer(divRenderer);

    const config = { sessionURL: url };
    vtkWSLinkClient.setSmartConnectClass(SmartConnect);
    const clientToConnect = vtkWSLinkClient.newInstance();
    clientToConnect.onConnectionReady((validClient) => {
        console.log('connection ready');
        const session = validClient.getConnection().getSession();
        connectImageStream(session);
        remoteView.setSession(session);
        remoteView.setViewId(id);
        remoteView.render();
    });

    clientToConnect.onConnectionError(console.error);
    clientToConnect.onConnectionClose(console.error);
    clientToConnect.connect(config);
}
render('ws://localhost:9999/ws', -1);
render('ws://localhost:9998/ws', -1);

I'm a bit lost here, any help would be highly appreciated. Thanks

jourdain commented 4 years ago

Indeed, that is because the RemoteView assume a single ImageStream. But you can provide it from the WsClient.

function render(url, id)
{
    const divRenderer = document.createElement('div');

    divRenderer.style.position = 'relative';
    divRenderer.style.width = '50vw';
    divRenderer.style.height = '50vh';
    divRenderer.style.overflow = 'hidden';
    document.querySelector('body').appendChild(divRenderer);

    const config = { sessionURL: url };
    vtkWSLinkClient.setSmartConnectClass(SmartConnect);
    const clientToConnect = vtkWSLinkClient.newInstance();
    clientToConnect.onConnectionReady((validClient) => {
        console.log('connection ready');
        const session = validClient.getConnection().getSession();

        const viewStream = validClient.getImageStream().createViewStream(id);
        const remoteView = vtkRemoteView.newInstance({ session, viewStream });
        remoteView.setContainer(divRenderer);
        remoteView.render();
    });

    clientToConnect.onConnectionError(console.error);
    clientToConnect.onConnectionClose(console.error);
    clientToConnect.connect(config);
}
knopkem commented 4 years ago

Thanks for the quick answer, unfortunately when updating with your code it now doesn't render anything. Mouse interaction on the blank canvas throws exceptions. I tried both with -1 for id and dedicated view Ids (1 and 2), still nothing.

I created an example here: https://github.com/knopkem/paraview-app

jourdain commented 3 years ago

Fixed in v17.2.4