Appearance
Modern JavaScript development
Modern web development rely on package manager to bring project dependencies. This section covers how published releases can be used within a JavaScript project.
Project setup
In the simple example we are going to use Vite with Vanilla JavaScript. The full code is available for reference here.
json
{
"name": "modern-app",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^6.3.5"
},
"dependencies": {
"@kitware/trame-vtklocal": "1.1.1"
}
}
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script
type="module"
src="https://kitware.github.io/vtk-wasm/wasm32/latest/vtkWebAssembly.mjs"
></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Standalone VTK.wasm example</title>
</head>
<body>
<div id="app">
<canvas></canvas>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
js
import "./style.css";
import { createNamespace } from "@kitware/trame-vtklocal/dist/esm/vtk.mjs";
import { buildWASMScene } from "./example";
createNamespace().then((vtk) => {
buildWASMScene(vtk, "#app > canvas");
});
js
export async function buildWASMScene(
vtk,
canvasSelector = "#vtk-wasm-window",
) {
// Make up some data array to generate a mesh (JS-only)
function makeQuadMesh(nx, ny) {
// Create a grid of points on the XY plane from (0, 0) to (nx, ny)
const pointJSArray = [];
for (let i = 0; i < ny + 1; i++) {
for (let j = 0; j < nx + 1; j++) {
const x = (j - 0.5 * nx) / nx;
const y = (i - 0.5 * ny) / ny;
pointJSArray.push(x); // x-coordinate
pointJSArray.push(y); // y-coordinate
pointJSArray.push(
2 * Math.sqrt(x * x + y * y) * Math.sin(x) * Math.cos(y),
); // z-coordinate
}
}
const connectivityJSArray = [];
const offsetsJSArray = [];
for (let i = 0; i < ny; i++) {
for (let j = 0; j < nx; j++) {
offsetsJSArray.push(connectivityJSArray.length);
connectivityJSArray.push(j + i * (nx + 1));
connectivityJSArray.push(j + i * (nx + 1) + 1);
connectivityJSArray.push(j + i * (nx + 1) + nx + 2);
connectivityJSArray.push(j + i * (nx + 1) + nx + 1);
}
}
offsetsJSArray.push(connectivityJSArray.length);
return {
points: pointJSArray,
offsets: offsetsJSArray,
connectivity: connectivityJSArray,
};
}
const meshData = makeQuadMesh(50, 50);
// Working on VTK.wasm
// => vtkObject creation is directly available on the vtk namespace
const points = vtk.vtkPoints();
const polys = vtk.vtkCellArray();
const connectivity = vtk.vtkTypeInt32Array();
const offsets = vtk.vtkTypeInt32Array();
// Ways to bind JS data to VTK.wasm types
// => method call are async and needs to be awaited
// => property can be accessed using the dot notation
await points.data.setArray(new Float32Array(meshData.points));
await connectivity.setArray(new Int32Array(meshData.connectivity));
await offsets.setArray(new Int32Array(meshData.offsets));
// Calling methods with other vtkObject as arguments
await polys.setData(offsets, connectivity);
// Using properties to set values as a batch update
const polyData = vtk.vtkPolyData();
polyData.set({ points, polys });
// Getting values from method call (async) or property (sync)
console.log("NumberOfPoints:", await polyData.getNumberOfPoints());
console.log("NumberOfCells:", await polyData.getNumberOfCells());
console.log("PolyDataBounds:", await polyData.getBounds());
// Create object with properties in constructor
const mapper = vtk.vtkPolyDataMapper();
await mapper.setInputData(polyData);
const actor = vtk.vtkActor({ mapper });
// Setting a property even across vtkObjects
// Same as: await (await actor.getProperty()).setEdgeVisibility(true);
actor.property.edgeVisibility = true;
// Setup rendering part
const renderer = vtk.vtkRenderer();
await renderer.addActor(actor);
await renderer.resetCamera();
// Create a RenderWindow and bind it to a canvas in the DOM
const renderWindow = vtk.vtkRenderWindow({ canvasSelector });
await renderWindow.addRenderer(renderer);
const interactor = vtk.vtkRenderWindowInteractor({
canvasSelector,
renderWindow,
});
// Trigger render and start interactor
await interactor.render();
await interactor.start();
// Observing vtkObject
const tag = renderWindow.observe("StartEvent", () => {
console.log("Camera position", renderer.activeCamera.position);
});
setTimeout(() => {
// Remove observer for one specific tag
renderWindow.unObserve(tag);
// Remove all observers
renderWindow.unObserveAll();
// Print the full state of a vtkObject
console.log("Camera state:", renderer.activeCamera.state);
}, 30000);
}
css
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
margin: 0;
height: 100vh;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
}
bash
npm install
npm run build
Since we are not publishing our WASM bundle to npm yet, we are using the one hosted on our documentation web site under https://kitware.github.io/vtk-wasm/wasm32/9.5.0/vtkWebAssembly.mjs
. But you can also download it from our CI registry and serve it or import it yourself.