Label

I have the following problem when I use the LabelWidget tag
ERROR in ./static/js/test1.js 10:0-85
Module not found: Error: Can’t resolve ‘vtk.js/Sources/Rendering/Core/InteractorObserver’ in ‘C:\Users\18530\Desktop\flaskProject\static\js’
resolve ‘vtk.js/Sources/Rendering/Core/InteractorObserver’ in ‘C:\Users\18530\Desktop\flaskProject\static\js’

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

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

import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';
import vtkInteractorStyleImage from '@kitware/vtk.js/Interaction/Style/InteractorStyleImage';

import vtkWidgetManager from '@kitware/vtk.js/Widgets/Core/WidgetManager';
import vtkLabelWidget from '@kitware/vtk.js/Widgets/Widgets3D/LabelWidget';

import vtkInteractorObserver from 'vtk.js/Sources/Rendering/Core/InteractorObserver';
import {
  bindSVGRepresentation,
  multiLineTextCalculator,
  VerticalTextAlignment,
  makeListenableSVGNode,
} from 'vtk.js/Examples/Widgets/Utilities/SVGHelpers';

import controlPanel from './controlPanel.html';

const { computeWorldToDisplay } = vtkInteractorObserver;

// ----------------------------------------------------------------------------
// Standard rendering code setup
// ----------------------------------------------------------------------------

const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance();
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();
const iStyle = vtkInteractorStyleImage.newInstance();
renderWindow.getInteractor().setInteractorStyle(iStyle);

const widgetManager = vtkWidgetManager.newInstance();
widgetManager.setRenderer(renderer);

renderer.resetCamera();
widgetManager.enablePicking();

// ----------------------------------------------------------------------------
// SVG
// ----------------------------------------------------------------------------

const handleTextProps = new Map();

function setupSVG(viewWidget) {
  bindSVGRepresentation(renderer, viewWidget.getWidgetState(), {
    mapState(widgetState, { size }) {
      const textState = widgetState.getText();
      const text = textState.getText();
      const origin = textState.getOrigin();
      if (origin && textState.getVisible()) {
        const coords = computeWorldToDisplay(renderer, ...origin);
        const position = [coords[0], size[1] - coords[1]];
        return {
          text,
          position,
          active: textState.getActive(),
        };
      }
      return null;
    },
    render(data, h) {
      if (data) {
        const nodes = [];
        const { text, position, active } = data;
        const { fontColor, fontSize } = handleTextProps.get(viewWidget);

        if (text.trim().length === 0) {
          nodes.push(
            h('circle', {
              key: 'circle',
              attrs: {
                r: 5,
                stroke: 'red',
                fill: 'red',
                cx: position[0],
                cy: position[1],
              },
            })
          );
        }

        const lines = text.split('\n');
        const dys = multiLineTextCalculator(
          lines.length,
          fontSize,
          VerticalTextAlignment.MIDDLE
        );
        nodes.push(
          ...lines.map((line, index) =>
            makeListenableSVGNode(
              h(
                'text',
                {
                  key: index,
                  attrs: {
                    x: position[0],
                    y: position[1],
                    dx: 12,
                    dy: dys[index],
                    fill: fontColor,
                    'font-size': fontSize,
                    'text-anchor': 'middle',
                    'font-weight': active ? 'bold' : 'normal',
                  },
                  style: {
                    cursor: 'pointer',
                  },
                  on: {
                    pointerenter() {
                      widgetManager.disablePicking();
                      viewWidget.activateHandle({
                        selectedState: viewWidget.getWidgetState().getText(),
                      });
                    },
                    pointerleave: () => {
                      viewWidget.deactivateAllHandles();
                      widgetManager.enablePicking();
                    },
                  },
                },
                line
              )
            )
          )
        );

        return nodes;
      }
      return [];
    },
  });
}

// -----------------------------------------------------------
// UI control handling
// -----------------------------------------------------------

fullScreenRenderer.addController(controlPanel);

let currentHandle = null;
const svgCleanupCallbacks = new Map();

// Add a new label
document.querySelector('#addLabel').addEventListener('click', () => {
  const widget = vtkLabelWidget.newInstance();
  const handle = widgetManager.addWidget(widget);
  widgetManager.grabFocus(widget);

  const textProps = {
    fontSize: 32,
    fontColor: 'white',
  };
  handleTextProps.set(handle, textProps);
  svgCleanupCallbacks.set(handle, setupSVG(handle));

  // Update control panel when a label is selected
  handle.onStartInteractionEvent(() => {
    currentHandle = handle;
    document.getElementById('txtIpt').value = currentHandle.getText() || '';
    document.getElementById('fontSize').value = textProps.fontSize;
    document.getElementById('color').value = textProps.fontColor;
  });
});

// Delete a label
document.querySelector('#deleteLabel').addEventListener('click', () => {
  if (currentHandle) {
    currentHandle.reset();
    widgetManager.removeWidget(currentHandle);
    svgCleanupCallbacks.get(currentHandle)();
    svgCleanupCallbacks.delete(currentHandle);
    handleTextProps.delete(currentHandle);
    currentHandle = null;
  }
});

// Update text
function updateText() {
  const input = document.getElementById('txtIpt').value;
  if (currentHandle) {
    currentHandle.setText(input);
    renderWindow.render();
  }
}
document.querySelector('#txtIpt').addEventListener('keyup', updateText);

// Update font size
function updateFontSize() {
  const input = document.getElementById('fontSize').value;
  if (currentHandle) {
    handleTextProps.set(currentHandle, {
      ...handleTextProps.get(currentHandle),
      fontSize: input,
    });
    currentHandle.getWidgetState().modified(); // render svg
  }
}
document.querySelector('#fontSize').addEventListener('input', updateFontSize);

// Update color
function updateColor() {
  const input = document.getElementById('color').value;
  if (currentHandle) {
    handleTextProps.set(currentHandle, {
      ...handleTextProps.get(currentHandle),
      fontColor: input,
    });
    currentHandle.getWidgetState().modified(); // render svg
  }
}
document.querySelector('#color').addEventListener('input', updateColor);

All import instances of vtk.js/Sources/... should be rewritten to @kitware/vtk.js/.... In addition, vtk.js/Examples is not published, so you should copy that SVGHelpers to your project and install snabbdom. See: Widgets | vtk.js

  1. npm install snabbdom

  2. Download SVGHelpers from this link

  3. import SVGHelpers into your project

  4. import {bindSVGRepresentation} from './SVGHelpers';
    console.log(bindSVGRepresentation);