JavaScript: Visualization Toolkit 16 kann Multikomponenten von Bildern rendern
Das neue Major Release der freien Bibliothek zur Datenvisualisierung beherrscht weitere Arten der Bildmanipulation und unterstĂĽtzt Webpack 5.
- Silke Hahn
Die JavaScript-Implementierung des Visualization Toolkit (VSK.js) liegt in der 16. Hauptversion vor. Die letzte Blogmeldung der Entwickler der quelloffenen Bibliothek fĂĽr wissenschaftliches Visualisieren liegt schon etwas zurĂĽck: Zuletzt hatten sie 2019 Version 9 per Blogbeitrag angekĂĽndigt, die insgesamt sieben dazwischenliegenden Versionen dĂĽrften trotz semantischer Versionierung nur kleinere Updates erhalten haben.
VSK.js 16 unterstützt Webpack 5 und ist für das Testen zur Continuous Integration/Continuous Delivery (CI/CD)-Plattform GitHub Actions umgezogen. Ab der aktuellen Version sollen die Abhängigkeiten der Bibliothek raschere Aktualisierungen erfahren. Die Abhängigkeit von der kw-web-suite
entfällt laut Blogmeldung, und ein neuer Release-Kanal ist hinzugekommen: Mit vtk.js@beta
wollen die Entwickler Breaking Changes kĂĽnftig vor dem Release testen.
Zeitreihen erstellen
Im Bereich der Visualisierung bietet die neue Version das Multikomponenten-Rendern von Bildern nach Schnitten und Umfang. Neu ist auch ein zweidimensionaler Convolution Filter für den Grafikprozessor. Ein externer Entwickler steuerte dem Release das Volume Clipping als Neuerung bei. Ein Highlight sind die Zeitreihen, die sich aus VTP-Dateien erstellen lassen – hierzu bietet das Kitware-Repository eine Live-Demo samt Quellcode:
import 'vtk.js/Sources/favicon';
import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData';
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkXMLPolyDataReader from 'vtk.js/Sources/IO/XML/XMLPolyDataReader';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import vtkHttpDataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper';
import controlPanel from './controller.html';
const { fetchBinary } = vtkHttpDataAccessHelper;
// ----------------------------------------------------------------------------
// Standard rendering code setup
// ----------------------------------------------------------------------------
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
background: [0, 0, 0],
});
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();
const mapper = vtkMapper.newInstance();
mapper.setInputData(vtkPolyData.newInstance());
const actor = vtkActor.newInstance();
actor.setMapper(mapper);
renderer.addActor(actor);
renderer.resetCamera();
renderWindow.render();
// ----------------------------------------------------------------------------
// Example code
// ----------------------------------------------------------------------------
// Download a series of VTP files in a time series, sort them by time, and
// then display them in a playback series.
// ----------------------------------------------------------------------------
const BASE_URL = 'https://kitware.github.io/vtk-js-datasets/data/vtp/can/';
function downloadTimeSeries() {
const files = [
'can_0.vtp',
'can_5.vtp',
'can_10.vtp',
'can_15.vtp',
'can_20.vtp',
'can_25.vtp',
'can_30.vtp',
'can_35.vtp',
'can_40.vtp',
];
return Promise.all(
files.map((filename) =>
fetchBinary(`${BASE_URL}/${filename}`).then((binary) => {
const reader = vtkXMLPolyDataReader.newInstance();
reader.parseAsArrayBuffer(binary);
return reader.getOutputData(0);
})
)
);
}
function getDataTimeStep(vtkObj) {
const arr = vtkObj.getFieldData().getArrayByName('TimeValue');
if (arr) {
return arr.getData()[0];
}
return null;
}
function setVisibleDataset(ds) {
mapper.setInputData(ds);
renderer.resetCamera();
renderWindow.render();
}
// -----------------------------------------------------------
// UI control handling
// -----------------------------------------------------------
function uiUpdateSlider(max) {
const timeslider = document.querySelector('#timeslider');
timeslider.min = 0;
timeslider.max = max - 1;
timeslider.step = 1;
}
fullScreenRenderer.addController(controlPanel);
// -----------------------------------------------------------
// example code logic
// -----------------------------------------------------------
let timeSeriesData = [];
const timeslider = document.querySelector('#timeslider');
const timevalue = document.querySelector('#timevalue');
timeslider.addEventListener('input', (e) => {
const activeDataset = timeSeriesData[Number(e.target.value)];
if (activeDataset) {
setVisibleDataset(activeDataset);
timevalue.innerText = getDataTimeStep(activeDataset);
}
});
downloadTimeSeries().then((downloadedData) => {
timeSeriesData = downloadedData.filter((ds) => getDataTimeStep(ds) !== null);
timeSeriesData.sort((a, b) => getDataTimeStep(a) - getDataTimeStep(b));
uiUpdateSlider(timeSeriesData.length);
timeslider.value = 0;
// set up camera
renderer.getActiveCamera().setPosition(0, 55, -22);
renderer.getActiveCamera().setViewUp(0, 0, -1);
setVisibleDataset(timeSeriesData[0]);
timevalue.innerText = getDataTimeStep(timeSeriesData[0]);
});
// -----------------------------------------------------------
// Make some variables global so that you can inspect and
// modify objects in your browser's developer console:
// -----------------------------------------------------------
global.mapper = mapper;
global.actor = actor;
global.renderer = renderer;
global.renderWindow = renderWindow;
Kameramanipulation und Szenen mit ParaView
Einige weitere Neuerungen betreffen die Kameramanipulation, so verfügt das Toolkit nun über eine Kameraansicht aus der Ich-Perspektive und eine Rotationsmöglichkeit der Kamera-Achse mittels Mausbewegungen (MouseCameraAxisRotateManipulator). Im Bereich Input/Output (I/O) ist ein STLWriter hinzugekommen, mit dem sich die Größe geometrischer Formen über das Mausrad skalieren lässt – auf GitHub lässt sich eine Live-Demo einsehen.
Das Exportieren von Szenen mit ParaView soll besser unterstützt werden als bislang, geht aus einem separaten Blogeintrag hervor. VTK.js 16 umfasst neue Reader wie Draco und PLY, verbesserte ITK-Intergration und es unterstützt Felddaten aus dem XML-Poly-Datenleser. Neben der Zufallstopologie unterstützen die Widgets nun SVG-Layer und das Skalieren der Pixel der Widget-Steuerungselemente (das Kitware-Repository hält ein Beispiel zur Veranschaulichung bereit).
Ausblick auf kommende Features
Einige Funktionalitäten befinden sich noch in der Planungs- und Entwicklungsphase, ihr Einzug in die Visualisierungsbibliothek ist seitens VTK-Team geplant: Künftig sollen Modul-Builds der JavaScript-ES6-Klassenbibliothek zur Verfügung stehen. Statt Nutzern abzuverlangen, dass sie Libraries zum Verarbeiten von Assets in den Bundler ihrer Wahl wie Webpack einbinden, soll der ESM-Build von VTK.js Anwendern das Preprocessing von Assets abnehmen. Im Beta-Kanal vtk.js@beta
ist diese Funktionalität laut Herausgebern schon verfügbar und sie soll bald auch im Standard-Releasekanal landen.
Die VTK.js-Entwickler haben auch eine React-Library in der Pipeline (react-vtk-js
), mit der Nutzer Visualisierungsszenen deklarativ erstellen können. Die Bibliothek soll über das dash-vtk
von Plotly erhältlich sein. Damit soll sich laut Blogeintrag das auf dem VTK.js basierende Visualisieren von einem Python-Server aus über die von Plotly entwickelte Infrastruktur rationalisieren lassen.
Mehr Informationen zum neuen Release lassen sich der Blogankündigung bei Kitware entnehmen. Im GitHub-Repository der VTK-Entwickler finden Interessierte den dazugehörigen Quellcode und Beispielvideos. Als Beispiel einer mit VTK.js gebauten App lässt sich ParaView Glance besichtigen.
(sih)