ThermalRegistry
The ThermalRegistry is a display context within a ThermalManager. It groups related thermal files and controls registry-wide visualization settings, including temperature range, min/max limits, opacity, and the temperature distribution histogram.
All registries within a single ThermalManager share the manager's thermal palette and services, but each registry maintains its own independent display range, opacity, and group hierarchy.
For the reactivity mechanisms used below (addListener and the CallbacksManager events), see CallbacksManager.
Creating and managing registries
A registry is identified by a unique ID string within its parent ThermalManager. To create or obtain an existing registry, use manager.registries.addOrGetRegistry:
import { ThermalManager } from "@labirthermal/core";
// Create the top-level manager
const manager = new ThermalManager();
// Create or retrieve registries
const registryA = manager.registries.addOrGetRegistry( "display-set-a" );
const registryB = manager.registries.addOrGetRegistry( "display-set-b" );
// Calling addOrGetRegistry with an existing ID returns the same instance
const registryASecondRef = manager.registries.addOrGetRegistry( "display-set-a" );
console.log( registryA === registryASecondRef ); // true
// Registries can be configured with optional settings, e.g. histogram resolution
const customRegistry = manager.registries.addOrGetRegistry( "custom-set", {
histogramResolution: 200
} );
// Remove a registry by ID (destroys the registry and all its groups and instances)
manager.registries.removeRegistry( "display-set-a" );The manager's observable registry collection is available through manager.registries.value. Its listeners and hierarchy iterators are described in ThermalManager. Options passed to addOrGetRegistry configure a new registry only; retrieving an existing ID does not change its settings.
Resetting or removing a registry
registry.removeAllChildren()destroys and removes all groups and their file instances, but keeps the registry in its manager.registry.reset()also resets the registry's opacity and min/max limits. It keeps the registry in its manager and does not reset its temperature range or histogram.registry.destroySelfAndBelow()performs the same cleanup asreset(); it does not remove the registry from its manager.registry.destroySelfInTheManager()delegates tomanager.registries.removeRegistry(registry.id), performing cleanup and removing the registry from the collection.
Use manager.registries.reset() to destroy and remove all registries in that manager.
groups
Within a registry, thermal files are organized into groups represented by ThermalGroup. Groups are stored in the observable registry.groups property.
To create a new group or retrieve an existing one by ID:
import { ThermalManager, ThermalGroup } from "@labirthermal/core";
const manager = new ThermalManager();
const registry = manager.registries.addOrGetRegistry( "display-set" );
// Create or retrieve a group with an optional human-readable name and description
const groupA = registry.groups.addOrGetGroup(
"morning-series",
"Morning Series",
"Recordings captured during morning tests"
);
// Alternatively, instantiate ThermalGroup directly and add it
const groupB = new ThermalGroup( registry, "evening-series", "Evening Series" );
registry.groups.addExistingGroup( groupB );
// Access the list of all groups in the registry
const allGroups: ThermalGroup[] = registry.groups.value;
// Iterate through all groups or all instances across all groups
registry.groups.forEveryGroup( group => console.log( group.label ) );
registry.groups.forEveryInstance( instance => console.log( instance.thermalUrl ) );
// Remove a group by its ID (destroys its instances and clears state)
registry.groups.removeGroup( "morning-series" );
// Listen for group collection changes
registry.groups.addListener( "groups-listener", groups => {
console.log( "Current groups count:", groups.length );
} );
// Unsubscribe when the listener is no longer needed
registry.groups.removeListener( "groups-listener" );Treat registry.groups.value as read-only and use the collection's methods to modify it. The registry also exposes forEveryGroup and forEveryInstance for the same hierarchy traversal.
Setter methods
registry.groups.addOrGetGroup( id, name?, description? )– create or retrieve a group.registry.groups.addExistingGroup( group )– add a directly instantiatedThermalGroup.registry.groups.removeGroup( id )– destroy a group and its instances and remove it.registry.groups.removeAllGroups()– destroy and remove every group and its instances.
Events
registry.groups.addListener( id, groups => ... )– listener on the group collection changes.
Example
The example below shows an implementation of GroupsState using the @labirthermal/webcomponents package. Each group-provider placed inside a registry-provider creates or retrieves one group of the registry – see the context providers guide.
minmax
The registry.minmax property represents the absolute minimum and maximum temperature bounds across all images in the entire registry.
How minmax is calculated
- Calculated automatically after all groups and files are loaded: during batch post-processing (
registry.postLoadedProcessing()), every group first recalculates its own min/max limits from its instances (group.minmax.recalculateFromInstances()). - Then, the registry calculates its global min/max by aggregating values across all groups (
registry.minmax.recalculateFromGroups()). - The property is read-only. Its value is either
{ min: number, max: number }in degrees Celsius orundefinedif no files are loaded.
import { ThermalManager } from "@labirthermal/core";
const manager = new ThermalManager();
const registry = manager.registries.addOrGetRegistry( "display-set" );
// Read current minmax values
const minmax = registry.minmax.value;
if ( minmax ) {
console.log( `Registry min: ${minmax.min} °C, max: ${minmax.max} °C` );
console.log( `Temperature span: ${registry.minmax.distanceInCelsius} °C` );
}
// Listen for minmax updates
registry.minmax.addListener( "minmax-listener", value => {
if ( value ) {
console.log( "New minmax bounds:", value.min, value.max );
}
} );Setter methods
The property is read-only in normal use; it recalculates itself during the batch post-processing.
registry.minmax.recalculateFromGroups()– recalculate the bounds from the current groups (called automatically bypostLoadedProcessing()).
Events
registry.minmax.addListener( id, value => ... )– listener on the bounds changes.
Example
The example below shows an implementation of MinmaxRegistryProperty using the @labirthermal/webcomponents package. The registry-ticks-bar and registry-range-display controls visualize the registry's min/max bounds, and registry-range-full-button resets the active range to them – see the thermal range guide.
range
The registry.range property controls the active temperature window ({ from: number, to: number }) used to colorize thermograms in the registry. Pixels at or below from are mapped to the coldest color of the palette, while pixels at or above to are mapped to the hottest color.
How range works
- Manual control via
imposeRange: you can assign an explicit temperature range at any time usingregistry.range.imposeRange({ from, to }). - Automatic initialization: when files finish loading in
postLoadedProcessing(), ifrange.valueisundefined, it is automatically set to the full span{ from: minmax.min, to: minmax.max }. - Clamping: any imposed range is validated and clamped to stay within
[minmax.min, minmax.max]. If new files expand or narrow the registry minmax, the active range is clamped accordingly. - Preset helpers:
registry.range.applyMinmax()sets the active range to the full min/max limits.registry.range.applyAuto()sets an optimal range calculated from the histogram by discarding temperatures with low frequency (bins with relative height < 10%).
import { ThermalManager } from "@labirthermal/core";
const manager = new ThermalManager();
const registry = manager.registries.addOrGetRegistry( "display-set" );
// Manually set a custom temperature range
registry.range.imposeRange({ from: 24.0, to: 36.5 });
// Apply the entire minmax span
registry.range.applyMinmax();
// Apply the automatically calculated histogram-based range
registry.range.applyAuto();
// Access current range
const currentRange = registry.range.currentRange; // or registry.range.value
// Listen for range changes
registry.range.addListener( "range-listener", range => {
if ( range ) {
console.log( `Range updated: from ${range.from} °C to ${range.to} °C` );
}
} );Setter methods
registry.range.imposeRange( { from, to } )– set an explicit range (clamped to the minmax bounds).registry.range.applyMinmax()– set the range to the full min/max limits.registry.range.applyAuto()– set the histogram-based automatic range.
Events
registry.range.addListener( id, range => ... )– listener on the active range changes.registry.range.onAutoValueChanged– CallbacksManager called when the calculated automatic range changes.
Example
The example below shows an implementation of RangeDriver using the @labirthermal/webcomponents package. The registry-range-slider manipulates the registry's range interactively, while registry-range-auto-button and registry-range-full-button call applyAuto() and applyMinmax(). The initial range can be set through the from and to attributes of registry-provider – see the thermal range guide.
histogram
The registry.histogram property contains the statistical distribution of temperatures across all files and all groups in the registry.
How the histogram is calculated
- Calculated after all groups are loaded: during batch post-processing,
histogram.recalculateHistogramBufferInWorker()runs asynchronously in a Web Worker thread. - Aggregated from all registry files: the worker parses thermal data buffers from every instance in every group belonging to this registry, generating a consolidated temperature histogram.
- Performance & caching: histogram calculations are cached via
histogramResultCacheto avoid redundant worker processing when file readers are reused. - The histogram data is used by
registry.range.applyAuto()to determine optimal temperature limits. - The property value is an array of
ThermalStatistics:tstype ThermalStatistics = { from: number; // Interval start in °C to: number; // Interval end in °C percentage: number; // Percentage of pixels in this bin count: number; // Pixel count in this bin height: number; // Normalized height for display (0-100) };
import { ThermalManager } from "@labirthermal/core";
const manager = new ThermalManager();
const registry = manager.registries.addOrGetRegistry( "display-set" );
// Access histogram bins
const bins = registry.histogram.value;
// Listen for histogram updates
registry.histogram.addListener( "hist-listener", data => {
console.log( "Histogram recalculated with", data.length, "bins" );
} );Setter methods
registry.histogram.setResolution( value )– change the number of histogram bins and recalculate.registry.histogram.recalculateHistogramBufferInWorker()– recalculate the histogram in a Web Worker (called automatically bypostLoadedProcessing()).
Events
registry.histogram.addListener( id, bins => ... )– listener on the histogram data changes.registry.histogram.onCalculationStart– CallbacksManager called when a recalculation starts.registry.histogram.onCalculationEnd– CallbacksManager called with a success flag when a recalculation finishes.
Example
The example below shows an implementation of HistogramState using the @labirthermal/webcomponents package. The registry-histogram control renders the registry's histogram bins and lets the user expand them into a detailed view.
opacity
The registry.opacity property controls the opacity of thermal canvas layers for all instances in this registry. This is especially useful for dual-spectrum cameras where an IR thermogram is overlaid onto a visible-spectrum photograph.
The opacity value is constrained between 0 (completely transparent IR image) and 1 (completely opaque IR image).
import { ThermalManager } from "@labirthermal/core";
const manager = new ThermalManager();
const registry = manager.registries.addOrGetRegistry( "display-set" );
// Set opacity and propagate to all instances
registry.opacity.imposeOpacity( 0.6 );
// Access current opacity
const currentOpacity: number = registry.opacity.value;
// Listen for opacity changes
registry.opacity.addListener( "opacity-listener", ( value: number ) => {
console.log( "Opacity changed:", value );
} );Setter methods
registry.opacity.imposeOpacity( value )– set the opacity (0–1) and propagate it to all instances.
Events
registry.opacity.addListener( id, value => ... )– listener on the opacity changes.
Example
The example below shows an implementation of OpacityDrive using the @labirthermal/webcomponents package. The initial opacity is set through the opacity attribute of registry-provider and the user changes it with the registry-opacity-slider control.
batch
Files should be loaded through the registry's batch loader, which groups file requests registered within one tick and automatically executes postLoadedProcessing() when requests finish. The whole loading pipeline – batching, caching and parser determination – is described in FilesService & batches.
import {
ThermalManager,
ThermalFileInstance,
ThermalFileFailure
} from "@labirthermal/core";
const manager = new ThermalManager();
const registry = manager.registries.addOrGetRegistry( "display-set" );
const group = registry.groups.addOrGetGroup( "series" );
// Request files to be loaded into a specific group
registry.batch.request(
"/files/sequence.lrc",
undefined, // Optional visible light image URL
group,
async ( result: ThermalFileInstance | ThermalFileFailure ) => {
if ( result instanceof ThermalFileInstance ) {
const container = document.createElement( "div" );
document.body.appendChild( container );
result.mountToDom( container );
} else {
console.error( "File load failed:", result.message );
}
}
);Instance labels
Assign an optional human-readable label to a loaded instance with result.setLabel("Measurement A") in a successful batch callback. Read it through result.label; it does not change the file name or the source URL.
The deprecated full-load methods, loadFullOneFile and loadFullMultipleFiles, also accept an optional label in each file request and apply it to the created instance. Labels belong to individual instances, so the same source file can have different labels in different groups. For new loading code, prefer the batch loader shown above.
Setter methods
registry.batch.request( thermalUrl, visibleUrl, group, callback, id? )– register a file request in the current (or a new) batch.registry.batch.closeBatch()– close the currently open batch.
Events
registry.batch.onBatchComplete– CallbacksManager called with all results whenever a batch finishes.batch.onResolve– CallbacksManager on theBatchobject returned byrequest(), called with the batch's results.registry.onProcessingStart/registry.onProcessingEnd– CallbacksManagers fired aroundpostLoadedProcessing().
loading
Indicates whether the registry is currently loading files. The value is true from the first batch request until the last batch finishes.
Setter methods
registry.loading.markAsLoading()/registry.loading.markAsLoaded()– managed automatically by the batch loader; call them only when implementing a custom loading flow.
Events
registry.loading.addListener( id, isLoading => ... )– listener on the loading state changes.
Summary of registry controls
| Property | Type | Provider attribute | Control elements |
|---|---|---|---|
| Groups | ThermalGroup[] | – | group-provider |
| Minmax | { min, max } | undefined | – (computed) | registry-range-display, registry-ticks-bar |
| Range | { from, to } | undefined | registry-provider from="20" to="40" | registry-range-slider, registry-range-auto-button, registry-range-full-button, registry-range-form |
| Histogram | ThermalStatistics[] | – (computed) | registry-histogram |
| Opacity | number (0–1) | registry-provider opacity="0.5" | registry-opacity-slider |