Scalar range widget

#1

Hello,

I am building a React app and I need to visualize some vtkjs scenes, and I want to add a scalar range widget like the one you can find on the Calculator example (https://kitware.github.io/vtk-js/examples/Calculator.html)

In my case the scene is loaded with vtkHttpSceneLoader, and I tried attaching a mapper with a lookupTable that I could update like in the example with lookupTable.updateMappingRange, but even though the mapping range is updated there is no effect on my scene, as if the scene just ignores the lookup table. I have tried several ways, including changing the lookupTable of all the mappers of my renderer but no success, the visualization doesn’t change. I have also tried to attach a vtkColorTransferFunction to the mapper as lookup table.

I think I am missing something here, maybe a simple concept I didn’t understand.

Here is my code:

class VtkViewer extends Component {
    constructor(props) {
        super(props);

        this.fullScreenRenderer = null;
        this.container = React.createRef();
        this.updateScalarRange = this.updateScalarRange.bind(this);
    }

    componentDidMount() {
        const { vtk } = window;

        this.fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
            rootContainer: this.container.current,
            containerStyle: {},
        });
        this.renderer = this.fullScreenRenderer.getRenderer();
        this.renderWindow = this.fullScreenRenderer.getRenderWindow();

        // One of the tests: create a lookupTable from vtkColorTransferFunction
        // I also tried with a regular vtkLookupTable instance
        // this.lookupTable = vtkColorTransferFunction.newInstance();
        // const preset = vtkColorMaps.getPresetByName('erdc_rainbow_bright');
        // const dataRange = [0, 255];
        // this.lookupTable.applyColorMap(preset);
        // this.lookupTable.setMappingRange(...dataRange);
        // this.lookupTable.updateRange();

        this.mapper = vtkMapper.newInstance({
            interpolateScalarsBeforeMapping: true,
            useLookupTableScalarRange: false,
            // lookupTable: this.lookupTable,
        });
        this.actor = vtkActor.newInstance();

        // Add scalar range controller
        this.addControlPanel();

        if (_.isEmpty(vtk)) {
            return;
        }

        // Step 1: only display the first vtk
        const dataAccessHelper = DataAccessHelper.get('zip', {
            zipContent: vtk[0],
            callback: () => {
                const sceneImporter = vtkHttpSceneLoader.newInstance({
                    renderer: this.renderer,
                    dataAccessHelper,
                }, {
                    actor: this.actor,
                    mapper: this.mapper,
                    // lookupTable: this.lookupTable,
                });
                sceneImporter.setUrl('index.json');
                this.onReady(sceneImporter);
            },
        });
    }

    onReady(sceneImporter) {
        sceneImporter.onReady(() => {
            this.renderWindow.render();
        });

        window.addEventListener('dblclick', () => {
            sceneImporter.resetScene();
            this.renderWindow.render();
        });
    }

    addControlPanel() {
        const { intl } = this.props;

        this.fullScreenRenderer.addController(`
            <table>
                <tr><td>${intl.formatMessage({ id: 'labels.vtk.scalarRange' })}</td></tr>
                <tr>
                    <td data-children-count="1">
                        <input class="min" type="text" style="width: 100%;" value="0">
                    </td>
                    <td data-children-count="1">
                        <input class="max" type="text" style="width: 100%;" value="1">
                    </td>
                </tr>
            </table>
        `);

        document.querySelector('.min').addEventListener('input', this.updateScalarRange);
        document.querySelector('.max').addEventListener('input', this.updateScalarRange);
    }

    updateScalarRange() {
        const min = Number(document.querySelector('.min').value);
        const max = Number(document.querySelector('.max').value);

        if (!Number.isNaN(min) && !Number.isNaN(max)) {
            // this.lookupTable.setMappingRange(min, max);
            // this.mapper.updateLookupTable();
            this.renderer.getActors().forEach((actor) => {
                actor.getMapper().getLookupTable().setMappingRange(min, max);
                if (actor.getMapper().getLookupTable().updateRange) { // for vtkColorTransferFunction
                    actor.getMapper().getLookupTable().updateRange();
                }
            });
            this.renderer.getActors().forEach((actor) => {
                console.log(actor.getMapper().getLookupTable().getMappingRange());
            });
            this.renderWindow.render();
        }
    }

    render() {
        return <div className={style.container} ref={this.container} />;
    }
}

(Sebastien Jourdain) #2

You are missing that, in your example, you’ve set it to false rather than true.

#3

Thank you for your answer

Actually I also tried to set it to true, and add or not a lookup table manually instanciated, but no changes on the view when I update the min/max values

(Sebastien Jourdain) #4

Oh, I think I know why. How did you get the scene? From the macro? If so, the macro compute the RGB and therefore no more color adjustment. :wink:

I have a better exporter in the work that truly export the array for the scene loader but I didn’t get a chance to finish its integration in ParaView… But it is available in VTK/C++…

#5

Ah yes indeed the scene is exported from the macro! Thank you!

I think we will change the way we get the scene I don’t know yet, but anyway thank you for your help to find the origin of the problem :slight_smile:

(Sebastien Jourdain) #6

Here is the other code that you can use to export the scene. https://github.com/Kitware/VTK/blob/master/Web/Python/vtkmodules/web/vtkjs_helper.py