Skip to content

Events

SurfView.js uses an event system for communication between components. Both the viewer and surfaces emit events you can listen to.

Viewer Events

Surface Events

javascript
viewer.on('surface:added', ({ surfaceId, surface }) => {
  console.log(`Surface ${surfaceId} added`);
});

viewer.on('surface:removed', ({ surfaceId }) => {
  console.log(`Surface ${surfaceId} removed`);
});

viewer.on('surface:variant', ({ surfaceId, variant }) => {
  console.log(`Surface ${surfaceId} switched to variant ${variant}`);
});

Layer Events

javascript
viewer.on('layer:added', ({ surfaceId, layerId }) => {
  console.log(`Layer ${layerId} added to ${surfaceId}`);
});

viewer.on('layer:removed', ({ surfaceId, layerId }) => {
  console.log(`Layer ${layerId} removed from ${surfaceId}`);
});

viewer.on('layer:updated', ({ surfaceId, layerId, changes }) => {
  console.log(`Layer ${layerId} updated`, changes);
});

viewer.on('layer:colormap', ({ layerId, colormap }) => {
  console.log(`Colormap changed to ${colormap}`);
});

viewer.on('layer:intensity', ({ layerId, range }) => {
  console.log(`Intensity range changed to`, range);
});

viewer.on('layer:threshold', ({ layerId, threshold }) => {
  console.log(`Threshold changed to`, threshold);
});

viewer.on('layer:opacity', ({ layerId, opacity }) => {
  console.log(`Opacity changed to ${opacity}`);
});

Interaction Events

javascript
viewer.on('surface:click', (hit) => {
  if (hit.surfaceId && hit.vertexIndex !== null) {
    console.log(`Clicked ${hit.surfaceId} at vertex ${hit.vertexIndex}`);
    console.log(`Position:`, hit.point);
    console.log(`Normal:`, hit.normal);
  }
});

Annotation Events

javascript
viewer.on('annotation:added', ({ id, surfaceId, vertexIndex }) => {
  console.log(`Annotation ${id} added`);
});

viewer.on('annotation:moved', ({ id, vertexIndex }) => {
  console.log(`Annotation ${id} moved to vertex ${vertexIndex}`);
});

viewer.on('annotation:removed', ({ id }) => {
  console.log(`Annotation ${id} removed`);
});

viewer.on('annotation:activated', ({ id }) => {
  console.log(`Annotation ${id} activated`);
});

viewer.on('annotation:reset', () => {
  console.log('All annotations cleared');
});

Render Events

javascript
viewer.on('render:before', () => {
  // Called before each render
});

viewer.on('render:after', () => {
  // Called after each render
});

viewer.on('render:needed', () => {
  // Called when a render is requested
});

Viewpoint Events

javascript
viewer.on('viewpoint:changed', ({ viewpoint, position }) => {
  console.log(`Viewpoint changed to ${viewpoint}`);
});

Controls Events

javascript
viewer.on('controls:changed', ({ name, value }) => {
  console.log(`Control ${name} changed to ${value}`);
});

viewer.on('controls:error', ({ error }) => {
  console.error('Controls error:', error);
});

Removing Listeners

javascript
// Store the handler
const handler = (event) => console.log(event);

// Add listener
viewer.on('surface:click', handler);

// Remove listener
viewer.off('surface:click', handler);

One-time Listeners

javascript
viewer.once('surface:added', ({ surfaceId }) => {
  console.log(`First surface added: ${surfaceId}`);
});

Event Flow Example

javascript
// Track all layer changes
viewer.on('layer:updated', ({ surfaceId, layerId, changes }) => {
  // Log to analytics
  analytics.track('layer_updated', { surfaceId, layerId, ...changes });
});

// Sync state with React
viewer.on('layer:opacity', ({ layerId, opacity }) => {
  setLayerOpacity(prev => ({ ...prev, [layerId]: opacity }));
});

// Handle picking
viewer.on('surface:click', (hit) => {
  if (hit.vertexIndex !== null) {
    // Show data at clicked vertex
    const data = getDataAtVertex(hit.surfaceId, hit.vertexIndex);
    showTooltip(hit.point, data);
  }
});

Released under the MIT License.