StandaloneSceneLoader

Live example

## Standalone scene loader

The Standalone Scene Loader is more than a simple example, it is also an
application viewer by itself. No server needed. Just save the following HTML
file to your desktop. This enables you to look at saved scenes exported from
ParaView using this macro.

An example scene can be downloaded from here Dragon.

More dataset can be downloaded here

And viewed with the links below:

Other CAD models

Source

/* eslint-disable import/prefer-default-export */
/* eslint-disable import/no-extraneous-dependencies */

import '@kitware/vtk.js/favicon';

// Load the rendering pieces we want to use (for both WebGL and WebGPU)
import '@kitware/vtk.js/Rendering/Profiles/All';

import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';

import vtkHttpSceneLoader from '@kitware/vtk.js/IO/Core/HttpSceneLoader';
import DataAccessHelper from '@kitware/vtk.js/IO/Core/DataAccessHelper';
import vtkURLExtract from '@kitware/vtk.js/Common/Core/URLExtract';
import vtkOBJReader from '@kitware/vtk.js/IO/Misc/OBJReader';
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';

import controlWidget from './SceneControllerWidget';
import style from './SceneLoader.module.css';

const iOS = /iPad|iPhone|iPod/.test(window.navigator.platform);
let autoInit = true;
let widgetCreated = false;

// Add class to body if iOS device --------------------------------------------

if (iOS) {
document.querySelector('body').classList.add('is-ios-device');
}

function emptyContainer(container) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
}

function downloadZipFile(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = (e) => {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 0) {
resolve(xhr.response);
} else {
reject(xhr, e);
}
}
};

// Make request
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.send();
});
}

export function load(container, options) {
autoInit = false;
emptyContainer(container);

const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance();
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();

function onReady(sceneImporter) {
sceneImporter.onReady(() => {
renderWindow.render();

// Add UI to dynamically change rendering settings
if (!widgetCreated) {
widgetCreated = true;
controlWidget(
document.querySelector('body'),
sceneImporter.getScene(),
renderWindow.render
);
}
});

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

if (options.url) {
const sceneImporter = vtkHttpSceneLoader.newInstance({ renderer });
sceneImporter.setUrl(options.url);
onReady(sceneImporter);
} else if (options.fileURL) {
downloadZipFile(options.fileURL).then((zipContent) => {
const dataAccessHelper = DataAccessHelper.get('zip', {
zipContent,
callback: (zip) => {
const sceneImporter = vtkHttpSceneLoader.newInstance({
renderer,
dataAccessHelper,
});
sceneImporter.setUrl('index.json');
onReady(sceneImporter);
},
});
});
} else if (options.file) {
if (options.ext === 'obj') {
const scene = [];
const reader = new FileReader();
reader.onload = function onLoad(e) {
const objReader = vtkOBJReader.newInstance();
objReader.parse(reader.result);
const nbOutputs = objReader.getNumberOfOutputPorts();
for (let idx = 0; idx < nbOutputs; idx++) {
const source = objReader.getOutputData(idx);
const mapper = vtkMapper.newInstance();
const actor = vtkActor.newInstance();
actor.setMapper(mapper);
mapper.setInputData(source);
renderer.addActor(actor);
scene.push({
name: source.get('name').name,
source,
mapper,
actor,
});
}
onReady({
getScene() {
return scene;
},
resetScene() {
renderer.resetCamera();
},
onReady(fn) {
renderer.resetCamera();
renderWindow.render();
fn();
},
});
};
reader.readAsText(options.file);
} else {
const dataAccessHelper = DataAccessHelper.get('zip', {
zipContent: options.file,
callback: (zip) => {
const sceneImporter = vtkHttpSceneLoader.newInstance({
renderer,
dataAccessHelper,
});
sceneImporter.setUrl('index.json');
onReady(sceneImporter);
},
});
}
}
}

export function initLocalFileLoader(container) {
autoInit = false;
const exampleContainer = document.querySelector('.content');
const rootBody = document.querySelector('body');
const myContainer = container || exampleContainer || rootBody;

const fileSelector = document.createElement('input');
fileSelector.setAttribute('type', 'file');
fileSelector.setAttribute('class', style.bigFileDrop);
myContainer.appendChild(fileSelector);
myContainer.setAttribute('class', style.fullScreen);

function handleFile(e) {
const files = this.files;
if (files.length === 1) {
myContainer.removeChild(fileSelector);
const ext = files[0].name.split('.').slice(-1)[0];
load(myContainer, { file: files[0], ext });
}
}

fileSelector.onchange = handleFile;
}

// Look at URL an see if we should load a file
// ?fileURL=https://data.kitware.com/api/v1/item/587003d08d777f05f44a5c98/download?contentDisposition=inline
const userParams = vtkURLExtract.extractURLParameters();

if (userParams.url || userParams.fileURL) {
const exampleContainer = document.querySelector('.content');
const rootBody = document.querySelector('body');
const myContainer = exampleContainer || rootBody;
load(myContainer, userParams);
}

// Auto setup if no method get called within 100ms
setTimeout(() => {
if (autoInit) {
initLocalFileLoader();
}
}, 100);