Skip to main content

PanelExtensionContext

type PanelExtensionContext = object;

PanelExtensionContext exposes properties and methods used for writing custom panels. The context provides methods for subscribing to messages, receiving updates, configuring panel settings, and rendering the panel to the UI.

The initPanel function used in registerPanel accepts a PanelExtensionContext parameter. This parameter contains properties and methods for accessing panel data and rendering UI updates. The initPanel function can also return an optional cleanup function that runs when the extension's panelElement unmounts.

For detailed information, see the Creating Custom Panels Guide.

Properties

panelElement

readonly panelElement: HTMLDivElement;

The root element of the panel. Add panel elements as children to this element.


initialState

readonly initialState: unknown;

The initial panel state.


layout

readonly layout: LayoutActions;

Actions that the panel can perform related to the user's current layout. See LayoutActions for details.


dataSourceProfile?

readonly optional dataSourceProfile: string;

Identifies the semantics of the data being played, such as which topics or parameters are semantically meaningful, or which normalization conventions are used. This typically maps to a shorthand identifier for a robotics framework like "ros1", "ros2", or "ulog". See MCAP profiles concept for details.


onRender()?

optional onRender: (renderState, done) => void;

Set this property to a function during panel initialization.

The visualization will run context.onRender when it needs to re-render the panel during playback. The function accepts renderState and done callback as parameters. Render events occur frequently (60hz, 30hz, etc.).

Note: Your onRender function must call done after rendering to indicate the panel is ready to render the next set of data. The exact placement of the done call will vary by framework and the logic of different extensions.

context.onRender = (renderState, done) => {
// Render UI updates using fields from RenderState

// Call done when you have rendered all UI for this renderState.
// If your UI framework delays rendering, call done after the rendering has actually occurred.
done();
};

Parameters

ParameterType
renderStateImmutable<RenderState>
done() => void

Returns

void


subscribeMessageRange()?

optional subscribeMessageRange: (args) => () => void;

Subscribe to receive messages for the entire time range of the given topic in the current data source.

See SubscribeMessageRangeArgs for details on behavior.

Note: This does not read messages from live sources like foxglove_bridge, rosbridge, or ROS 1 native connections. For those messages, you still need to use context.subscribe() and watch("currentFrame").

Parameters

ParameterType
argsSubscribeMessageRangeArgs

Returns

Function

A function that will unsubscribe from the topic, cancel the active async iterator, and prevent onNewRangeIterator from being called again.

Returns

void


UNSTABLE_subscribeMessageRange()?

optional UNSTABLE_subscribeMessageRange: (args) => () => void;

Parameters

ParameterType
argsSubscribeMessageRangeArgs

Returns

Function

Returns

void

Deprecated

Renamed to subscribeMessageRange. Please use that method instead.

Methods

watch()

Call Signature

watch(field): void

Subscribe to updates for this field in the render state. It will only be called when this field changes.

Use context.watch to indicate which fields in the RenderState (such as currentFrame, currentTime, previewTime, parameters, topics) should trigger panel re-rendering when their values change.

context.watch('topics');
context.watch('currentFrame');
context.watch('parameters');
context.watch('currentTime');
Parameters
ParameterType
fieldkeyof RenderState
Returns

void

Call Signature

watch(field): void

Subscribe to updates for this field in the render state. It will only be called when this field changes.

Parameters
ParameterType
field"allFrames"
Returns

void

Deprecated

Calling watch with allFrames is deprecated. Please use PanelExtensionContext.subscribeMessageRange instead.


saveState()

saveState(state): void

Use context.saveState to persist any object as panel settings (also called panel settings) in the current layout.

context.initialState = undefined; // The initial state of the panel

context.saveState({ myNum: 2, myBool: false, myStr: 'abc' });
Parameters
ParameterTypeDescription
statePartial<unknown>The state to save. This value should be JSON serializable.
Returns

void


setParameter()

setParameter(name, value): void

Use context.setParameter to set the parameter name to any valid value (i.e., basic types, dates, Uint8Array, and arrays or objects containing these values).

context.setParameter('/param1', 'value1');
Parameters
ParameterTypeDescription
namestringThe name of the parameter to set.
valueParameterValueThe new value of the parameter.
Returns

void


setSharedPanelState()

setSharedPanelState(state): void

Set temporary state shared by the same type of panel calling this function. This will not be saved in the layout.

Parameters
ParameterType
stateundefined | Record<string, unknown>
Returns

void


setVariable()

setVariable(name, value): void

Use context.setVariable to set the variable name to any valid variable value.

context.setVariable('myVar', 55);

context.onRender = (renderState: RenderState, done) => {
// Read variable values from renderState
const variableValues = renderState.variables;
const myVarValue = variableValues.myVar;

// Call done when you have rendered all UI for this renderState.
// If your UI framework delays rendering, call done after the rendering has actually occurred.
done();
};
Parameters
ParameterTypeDescription
namestringThe name of the variable to set.
valueVariableValueThe new value of the variable.
Returns

void


setPreviewTime()

setPreviewTime(time): void

Set active preview time. Setting preview time to undefined will clear the preview time.

Parameters
ParameterType
timeundefined | number
Returns

void


seekPlayback()?

optional seekPlayback(time): void

Move playback to the given time. The behavior is like the user clicking the play bar to seek.

Parameters
ParameterType
timenumber
Returns

void


subscribe()

subscribe(topic, options): () => void

Use context.subscribe to subscribe to a topic to receive messages. Returns an unsubscribe function that will be called when messages are no longer needed.

const unsubscribe = context.subscribe('/my_topic', {
preload: true,
});

// Unsubscribe later
unsubscribe();
Parameters
ParameterTypeDescription
topicstringThe name of the topic to subscribe to.
optionsSubscribeOptions | undefinedSubscription options. For more information, see SubscribeOptions.
Returns

Function

A function that will unsubscribe from the topic when called.


unsubscribeAll()

unsubscribeAll(): void

Unsubscribe from all topics.

context.unsubscribeAll();
Returns

void


subscribeAppSettings()

subscribeAppSettings(): () => void

Use context.subscribeAppSettings to subscribe to application settings updates. Returns an unsubscribe function that will be called when settings updates are no longer needed.

const unsubscribe = context.subscribeAppSettings();

// Unsubscribe later
unsubscribe();
Returns

Function

A function that will unsubscribe from application settings updates when called.


optional advertise(topic, datatype, options): void

Use context.advertise to publish messages on a topic. This must be called before using context.publish to publish messages.

context.advertise('/my_topic', 'std_msgs/String');
Parameters
ParameterTypeDescription
topicstringThe name of the topic to publish messages on.
schemaNamestringThe name of the pattern the published messages will follow.
optionsRecord<string, unknown>Options to pass to the current data source for additional configuration.
Returns

void


unadvertise()?

optional unadvertise(topic): void

Indicates that you no longer want to publish on this topic.

context.unadvertise('/my_image_topic');

If the current data source does not support publishing, this property may be undefined.

Parameters
ParameterType
topicstring
Returns

void


publish()?

optional publish(topic, message): void

Use context.publish to publish messages on a topic that has been previously published. (You must first call advertise to publish the topic before you can publish.) If the topic has not been published or is otherwise incorrectly formatted, the function will throw an error.

context.advertise('/my_color_topic', 'std_msgs/ColorRGBA');
context.publish('/my_color_topic', { r: 0, g: 1, b: 0, a: 1 });

If the current data source does not support publishing, this property may be undefined.

Parameters
ParameterTypeDescription
topicstringThe name of the topic to publish messages on.
messageunknownThe message to publish.
Returns

void


callService()?

optional callService(service, request): Promise<unknown>

Use context.callService to send a service call to the specified service with a request payload.

context.callService('my_service', { foo: 'bar' });

If the current data source does not support services, this property may be undefined.

Parameters
ParameterTypeDescription
servicestringThe name of the service to call.
requestunknownThe request payload for the service call.
Returns

Promise<unknown>

A Promise that resolves when the result is available or rejects if an error occurs


updatePanelSettingsEditor()

updatePanelSettingsEditor(settings): void

Call the updatePanelSettingsEditor method on the PanelExtensionContext instance to define or update its settings.

const panelSettings: SettingsTree = {
nodes: { ... },
actionHandler: (action: SettingsTreeAction) => { ... }
};

context.updatePanelSettingsEditor(panelSettings);

settings parameter must be a valid SettingsTree and must contain 2 required properties – nodes and actionHandler:

  • nodes - A hierarchy where each node can contain input fields, display fields, or even other nodes
  • actionHandler - A function that will be called when a user interacts with the settings UI; it contains logic to handle interactions and update the panel or settings tree

It can also contain the following optional properties:

  • enableFilter – A boolean to set whether a filter control should be displayed
  • focusedPath – A node to scroll to and highlight in the editor (temporary one-time effect)

The following example tree has a title text input field within the General section, and an actionHandler to respond to updates to the title field.

const panelSettings: SettingsTree = {
nodes: {
general: {
label: 'General',
fields: {
title: {
label: 'Title',
input: 'string',
// `panelTitle` refers to the value in the panel configuration
value: panelTitle,
},
},
},
},
actionHandler: (action: SettingsTreeAction) => {
switch (action.action) {
case 'perform-node-action':
// Handle user actions defined for nodes in the settings tree
break;
case 'update':
if (action.payload.path[0] === 'general' && action.payload.path[1] === 'title') {
// Read action.payload.value for the new panel title value
panelTitle = action.payload.value;

// Update panel state accordingly
}
break;
}
},
};

context.updatePanelSettingsEditor(panelSettings);

SettingsTreeAction

SettingsTreeAction describes how the settings UI should update when a user interacts with a field.

Each SettingsTreeAction has a payload with a path pointing to the field to be updated (e.g., ["general", "title"]).

The update operation corresponds to a user setting a new value for a field (e.g., "My new title").

Special Node Attributes

There are two special SettingsTreeNode attributes, label and visibility. The value you specify for label will control the label displayed in the settings editor. If you set the renamable node attribute to true, users can edit the node label – you will receive an update SettingsTreeAction with a path ending in label.

Also, if you specify a boolean for the node visibility, the settings editor will provide a button to toggle the node's visibility, and you will receive an update operation with a path ending in visibility.

For examples of how to use these special attributes, see the panel settings example extension.

Input Types

In addition to the string input type in the above example, the panel API provides multiple types for extending panel input fields.

Each input type has different properties you can configure:

  • autocomplete
  • boolean
  • rgb
  • rgba
  • gradient
  • messagepath
  • select
  • string
  • toggle
  • vec3
  • vec2

Parameters

ParameterTypeDescription
settings{ actionHandler: (action) => void; enableFilter: boolean; focusedPath: readonly string[]; nodes: {}; }-
settings.actionHandler(action) => voidThe handler for all operations on the settings tree initiated by the UI.
settings.enableFilter?booleanIf the settings editor should display a filter control, then true.
settings.focusedPath?readonly string[]This will have a one-time effect, scrolling the editor to the node at the path and highlighting it. This is a temporary effect, so it does not need to be subsequently un-set.
settings.nodesThe root node of the settings tree. Updates to these will automatically reflect in the editor UI.

Returns

void


setDefaultPanelTitle()

setDefaultPanelTitle(defaultTitle): void

Use context.setDefaultPanelTitle to override the default title of the panel. Users can always override the default title manually. If no override is set or the default title, the panel will only display its type (e.g., "Image").

// Override default panel title
context.setDefaultPanelTitle(`Plot of ${config.topicName}`);
Parameters
ParameterType
defaultTitleundefined | string
Returns

void