Hi @martink , @jourdain ,
thank you for your suggestions and sorry for not coming back to the topic earlier - I needed a while to learn at least some basics of javascript, npm, webpack, etc. to get things running
Slightly inspired by SceneExplorerWidget.js
, I put together the following LabelWidget.js
:
import vtkPixelSpaceCallbackMapper from '@kitware/vtk.js/Rendering/Core/PixelSpaceCallbackMapper';
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
export default function addWidget(renderer, container, sceneItems, render) {
let dims = null;
const textCanvas = document.createElement('canvas');
textCanvas.classList.add('labelCanvas');
textCanvas.style.position = 'absolute';
textCanvas.style.top = '0px';
textCanvas.style.left = '0px';
textCanvas.style.width = '100%';
textCanvas.style.height = '100%';
textCanvas.style.overflow = 'hidden';
renderer.getContainer().appendChild(textCanvas);
const textCtx = textCanvas.getContext('2d');
window.addEventListener('resize', () => {
dims = container.getBoundingClientRect();
textCanvas.setAttribute('width', dims.width);
textCanvas.setAttribute('height', dims.height);
render();
});
window.dispatchEvent(new Event("resize"));
function getArrayNames(sceneItem) {
return `<option value="0">---</option>`
+ sceneItem.source.getArrays()
// introduced "+1" in array index, so that "0" means "no labels"
.map((array, idx) => `<option value="${idx+1}">${array.name}</option>`)
.join('');
}
const listStr = sceneItems
.map(
(item, idx) =>
`<li><select name="${idx}">${getArrayNames(item)}</select> ${item.name}</li>`
)
.join('');
const listContainer = document.createElement('ul');
listContainer.innerHTML = listStr;
listContainer.style.position = 'absolute';
listContainer.style.left = '25px';
listContainer.style.top = '100px';
listContainer.style.backgroundColor = 'white';
listContainer.style.borderRadius = '5px';
listContainer.style.listStyle = 'none';
listContainer.style.padding = '5px 10px';
listContainer.style.margin = '0';
listContainer.style.display = 'block';
listContainer.style.border = 'solid 1px black';
container.appendChild(listContainer);
document.querySelector('body').addEventListener('keypress', (e) => {
if (String.fromCharCode(e.charCode) === 'l') {
if (listContainer.style.display === 'none') {
listContainer.style.display = 'block';
} else {
listContainer.style.display = 'none';
}
}
});
const selectList = listContainer.querySelectorAll('select');
for (let i = 0; i < selectList.length; i++) {
const selectElem = selectList[i];
selectElem.addEventListener('change', handleChange);
}
function handleChange(e) {
const itemIdx = Number(e.target.name);
const value = Number(e.target.value);
// ugly hack: we just append an attribute to the sceneItem
sceneItems[itemIdx].labelArray = value;
if (render) {
render();
}
}
for (const sceneItem of sceneItems) {
console.log(`Adding labels to ${sceneItem.name}`)
const psMapper = vtkPixelSpaceCallbackMapper.newInstance();
psMapper.setInputConnection(sceneItem.source.getOutputPort());
psMapper.setCallback((coordsList) => {
if (textCtx && dims) {
textCtx.clearRect(0, 0, dims.width, dims.height);
const labelArray = sceneItem.labelArray;
if (labelArray) {
coordsList.forEach((xy, idx) => {
textCtx.font = '12px serif';
textCtx.textAlign = 'center';
textCtx.textBaseline = 'middle';
textCtx.fillText(
// "-1" to compensate for offset introduced in getArrays()
`${sceneItem.source.getArrays()[labelArray-1].array.values[idx]}`,
// pixel ratio scaling from https://github.com/Kitware/vtk-js/issues/1179#issuecomment-544709725
xy[0] / window.devicePixelRatio,
dims.height - xy[1] / window.devicePixelRatio);
}); }
}
});
const textActor = vtkActor.newInstance();
textActor.setMapper(psMapper);
renderer.getRenderer().addActor(textActor);
}
}
which can be instantiated in the onReady()
function of the SceneExplorer via
import labelWidget from './LabelWidget';
...
// Add UI to enable labels for different scene items
labelWidget(
fullScreenRenderer,
document.querySelector('body'),
sceneImporter.getScene(),
renderWindow.render
);
Now, I can conveniently select, for which sceneItems I want to see labels at the respective vtkPoints
and which data array entries are to be printed (very messy here, this is not the original data):
Missing point is now, to also export the non-numeric point data arrays from Paraview into the *.vtkjs
file.
Do you possibly have suggestions where I could start with this?