Skip to main content

Event System (EventTarget API)

NiiVue implements the browser-native EventTarget API. This supports multiple listeners per event, standard options (once, signal), and coexists with legacy callback properties.

Usage

Adding and removing listeners

const nv = new Niivue();
nv.attachToCanvas(document.getElementById('gl'));

// Add a listener
const handler = (event) => {
console.log('Location:', event.detail);
};
nv.addEventListener('locationChange', handler);

// Remove it
nv.removeEventListener('locationChange', handler);

One-time listeners

nv.addEventListener('imageLoaded', (event) => {
console.log('First image loaded:', event.detail.name);
}, { once: true });

AbortController

Use an AbortController to remove multiple listeners at once:

const controller = new AbortController();

nv.addEventListener('locationChange', handler1, { signal: controller.signal });
nv.addEventListener('intensityChange', handler2, { signal: controller.signal });

// Remove all listeners registered with this signal
controller.abort();

Available Events

User Interaction

EventDetail TypeDescription
dragReleaseDragReleaseParamsDrag operation released
mouseUpPartial<UIData>Mouse button released
locationChangeunknownCrosshair location changed
intensityChangeNVImageIntensity values changed
clickToSegment{ mm3: number; mL: number }Click-to-segment completed
measurementCompletedCompletedMeasurementDistance measurement line completed
angleCompletedCompletedAngleAngle measurement completed
frameChange{ volume: NVImage; index: number }4D frame changed

Loading

EventDetail TypeDescription
imageLoadedNVImageImage/volume loaded
meshLoadedNVMeshMesh loaded
volumeAddedFromUrl{ imageOptions, volume }Volume added from URL
volumeWithUrlRemoved{ url: string }URL-loaded volume removed
volumeRemoved{ volume: NVImage; index: number }Any volume removed from scene
volumeUpdatedvoidVolume updated
meshAddedFromUrl{ meshOptions, mesh }Mesh added from URL
meshWithUrlRemoved{ url: string }URL-loaded mesh removed
meshRemoved{ mesh: NVMesh }Any mesh removed from scene
documentLoadedNVDocumentDocument loaded
dicomLoaderFinished{ files: (NVImage|NVMesh)[] }DICOM loader finished

View Control

EventDetail TypeDescription
azimuthElevationChange{ azimuth: number; elevation: number }3D view rotation changed
clipPlaneChange{ clipPlane: number[] }Clip plane changed
sliceTypeChange{ sliceType: SLICE_TYPE }View layout changed (axial, coronal, etc.)

Shaders

EventDetail TypeDescription
customMeshShaderAdded{ fragmentShaderText, name }Custom shader added
meshShaderChanged{ meshIndex, shaderIndex }Mesh shader changed
meshPropertyChanged{ meshIndex, key, value }Mesh property changed

Rendering

EventDetail TypeDescription
volumeOrderChanged{ volumes: NVImage[] }Volume stacking order changed

Drawing

EventDetail TypeDescription
penValueChanged{ penValue: number; isFilledPen: boolean }Drawing pen value changed
drawingToolChanged{ tool: string; penValue: number; isFilledPen: boolean }Active drawing tool changed (high-level interpretation)
drawingChanged{ action: string }Drawing bitmap materially changed ('draw', 'undo', 'load', 'close')
drawingEnabled{ enabled: boolean }Drawing mode toggled on or off

Configuration

EventDetail TypeDescription
optsChange{ propertyName, newValue, oldValue }Options changed

TypeScript

Events are fully typed. The detail type is inferred from the event name:

nv.addEventListener('azimuthElevationChange', (event) => {
const { azimuth, elevation } = event.detail;
});

nv.addEventListener('imageLoaded', (event) => {
console.log(event.detail.name, event.detail.dims);
});

Backward Compatibility

Legacy callback properties continue to work. When both are registered, events fire before callbacks:

nv.onLocationChange = (location) => { /* callback */ };
nv.addEventListener('locationChange', (event) => { /* event */ });
// Both fire; event first, then callback

See Also