PanelExtensionContext
type PanelExtensionContext = object;
The PanelExtensionContext exposes properties and methods for writing a custom panel. The
context has methods to subscribe for messages, receive updates, configure your panel's settings,
and render your panel to the UI.
The initPanel function used in
registerPanel accepts a PanelExtensionContext
argument. This argument contains properties and methods for accessing panel data and rendering UI
updates. The initPanel function also returns an optional cleanup function to run when the
extension panelElement unmounts.
See the Creating a custom panel guide for more details.
Properties
panelElement
readonly panelElement: HTMLDivElement;
The root element for the panel. Add your panel elements as children under this element.
initialState
readonly initialState: unknown;
Initial panel state
layout
readonly layout: LayoutActions;
Actions the panel may 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 back, such as which topics or parameters are semantically meaningful or normalization conventions to use. This typically maps to a shorthand identifier for a robotics framework such as "ros1", "ros2", or "ulog". See the MCAP profiles concept at https://mcap.dev/spec/registry#profiles.
onRender()?
optional onRender: (renderState, done) => void;
Set this property to a function during your panel's initialization.
Foxglove will run context.onRender whenever your panel needs to re-render during playback.
The function accepts renderState and a done callback as its arguments. Render events occur
frequently (60hz, 30hz, etc).
Note: Your onRender function must call done after rendering to indicate that the
panel is ready to render the next set of data. The exact placement of this done invocation
will vary between frameworks and different extensions' logic.
context.onRender = (renderState, done) => {
// Render your UI updates with fields from RenderState
// Call done when you've rendered all the UI for this renderState.
// If your UI framework delays rendering, call done when rendering has actually happened.
done();
};
Parameters
| Parameter | Type |
|---|---|
renderState | Immutable<RenderState> |
done | () => void |
Returns
void
subscribeMessageRange()?
optional subscribeMessageRange: (args) => () => void;
Subscribe to receive the entire time range of messages for a given topic for the current data source.
See SubscribeMessageRangeArgs for more information on behavior.
Note: This will not read messages for live sources, like foxglove_bridge, rosbridge, or ROS 1
native connections. For those messages you will still need to use context.subscribe() and
watch("currentFrame").
Parameters
| Parameter | Type |
|---|---|
args | SubscribeMessageRangeArgs |
Returns
A function that will unsubscribe from the topic, cancel the active async iterator, and prevent onNewRangeIterator from being called again.
(): void;
Returns
void
UNSTABLE_subscribeMessageRange()?
optional UNSTABLE_subscribeMessageRange: (args) => () => void;
Parameters
| Parameter | Type |
|---|---|
args | SubscribeMessageRangeArgs |
Returns
(): void;
Returns
void
Deprecated
Renamed to subscribeMessageRange. Please use that method instead.
Methods
watch()
Call Signature
watch(field): void;
Subscribe to updates on this field within the render state. Render will only be invoked when this field changes.
Use context.watch to indicate which fields in RenderState (e.g. currentFrame,
currentTime, previewTime, parameters, topics) should trigger panel re-renders when
their contained values change.
context.watch("topics");
context.watch("currentFrame");
context.watch("parameters");
context.watch("currentTime");
Parameters
| Parameter | Type |
|---|---|
field | keyof RenderState |
Returns
void
Call Signature
watch(field): void;
Subscribe to updates on this field within the render state. Render will only be invoked when this field changes.
Parameters
| Parameter | Type |
|---|---|
field | "allFrames" |
Returns
void
Deprecated
Calling watch with allFrames is deprecated. Use PanelExtensionContext.subscribeMessageRange instead.
saveState()
saveState(state): void;
Use context.saveState to save an arbitrary object as persisted panel state (also known as
panel settings) in the current layout. You can view the current panel state using
Import/export settings.
context.initialState = undefined; // your panel's initial state
context.saveState({ myNum: 2, myBool: false, myStr: "abc" });
Parameters
| Parameter | Type | Description |
|---|---|---|
state | Partial<unknown> | The state to save. This value should be JSON serializable. |
Returns
void
setParameter()
setParameter(name, value): void;
Use context.setParameter to set a parameter name to any valid value (i.e. primitives, dates, Uint8Arrays, and arrays or objects containing these values).
context.setParameter("/param1", "value1");
Parameters
| Parameter | Type | Description |
|---|---|---|
name | string | The name of the parameter to set. |
value | ParameterValue | The new value of the parameter. |
Returns
void
setSharedPanelState()
setSharedPanelState(state): void;
Set the transient state shared by panels of the same type as the caller of this function. This will not be persisted in the layout.
Parameters
| Parameter | Type |
|---|---|
state | | Record<string, unknown> | (prevState) => | { [key: string]: unknown; } | undefined | undefined |
Returns
void
setVariable()
setVariable(name, value): void;
Use context.setVariable to set a
variable name to any valid variable
value.
context.setVariable("myVar", 55);
context.onRender = (renderState: RenderState, done) => {
// Read variable values from the renderState
const variableValues = renderState.variables;
const myVarValue = variableValues.myVar;
// Call done when you've rendered all the UI for this renderState. If your UI framework delays rendering, call done when rendering has actually happened.
done();
};
Parameters
| Parameter | Type | Description |
|---|---|---|
name | string | The name of the variable to set. |
value | VariableValue | The new value of the variable. |
Returns
void
setPreviewTime()
setPreviewTime(time): void;
Set the active preview time. Setting the preview time to undefined clears the preview time.
Parameters
| Parameter | Type |
|---|---|
time | number | undefined |
Returns
void
seekPlayback()?
optional seekPlayback(time): void;
Seek playback to the given time. Behaves as if the user had clicked the playback bar to seek.
Clients can pass a number or alternatively a Time object for greater precision.
This property may be undefined if the current data source does not support seeking.
Parameters
| Parameter | Type |
|---|---|
time | number | Time |
Returns
void
subscribe()
Call Signature
subscribe(subscriptions): void;
Use context.subscribe to indicate the topics your panel wants to receive messages for. The
messages are provided during render in RenderState.currentFrame.
Parameters
| Parameter | Type |
|---|---|
subscriptions | Subscription[] |
Returns
void
Remarks
This method will update the current subscriptions to the new list of Subscriptions and unsubscribe from any previously subscribed topics no longer in the Subscription list. Passing an empty array will unsubscribe from all topics.
context.subscribe([{ topic: "/some/topic" }, { topic: "/another/topic" }]);
context.subscribe([]) will unsubscribe from all topics, and is equivalent to
unsubscribeAll.
Range loading
Most panels display data from the current frame; examples of built-in panels that display the current frame are 3D, Image, and Raw Message, however some panels can display data for multiple messages or even the entire dataset duration (Plot, Map, State Transitions).
Subscriptions will provide only the messages for the current frame. If your panel would like to process all the available messages on a topic, use @PanelExtensionContext.subscribeMessageRange | subscribeMessageRange instead.
NOTE: Message range loading is done on a best-effort basis. If your range-loaded messages exceed available memory limits for the browser or desktop app, then the data may not represent the full dataset range. Range loading results in more data transfer and memory use and is recommended only for panels which require access to the entire dataset.
Message converters
Message converters can convert messages from one schema to another – for example, a user might
convert custom GPS message into
foxglove.LocationFix
messages for visualization in the Map
panel. Users may have one or more
message converters registered.
If your panel expects messages with specific schema names, you can leverage registered message converters to convert from one schema to another.
Specify the convertTo option to enable message conversion on a topic. When conversion is
enabled for a subscription, the MessageEvents will contain message entries with the
converted message rather than the original message on the topic. The original message is
available in the originalMessageEvent field in the message event.
context.subscribe([{ topic: "/some/topic", convertTo: "foxglove.LocationFix" }]);
The convertibleTo field within RenderState.topics will contain the names of schemas you can convert this topic into.
Call Signature
subscribe(topics): void;
Parameters
| Parameter | Type |
|---|---|
topics | string[] |
Returns
void
Deprecated
Use subscribe with an array of Subscription objects instead.
unsubscribeAll()
unsubscribeAll(): void;
Unsubscribe from all topics.
Note: This is analogous to calling subscribe([]) with an empty array of topics.
Returns
void
subscribeAppSettings()
subscribeAppSettings(settings): void;
Subscribe to any changes in application settings for an array of setting keys.
The keys and their corresponding values are not currently documented and are subject to change.