Plugins extend map functionality through a unified lifecycle. They integrate with the InteractionBroker for pick event handling and support exclusive groups for mutual exclusion.
// src/plugins/myfeature/MyPlugin.ts
import type { MapPlugin, PluginContext } from "@core/map/contracts/PluginContract";
import { DisposeBag } from "@core/map/utils/disposeBag";
export class MyPlugin implements MapPlugin {
readonly id = "my-plugin";
readonly priority = 50; // Higher = first to receive events
readonly exclusiveGroup = "none"; // "draw" | "measure" | "none"
private ctx: PluginContext | null = null;
private disposeBag = new DisposeBag();
activate(ctx: PluginContext): void {
this.ctx = ctx;
const viewer = ctx.runtime.getViewer();
// Set up event handlers, primitives, etc.
// Register everything in disposeBag
this.disposeBag.add(() => {
// Cleanup
});
}
deactivate(): void {
// Temporary pause — keep state but stop listening
}
dispose(): void {
this.deactivate();
this.disposeBag.dispose();
this.ctx = null;
}
}import { MyPlugin } from "@plugins/myfeature/MyPlugin";
// In your page component:
const handleReady = (app: MapApp) => {
const myPlugin = new MyPlugin();
app.activatePlugin(myPlugin);
};Plugins with the same exclusiveGroup are mutually exclusive. When one activates, others in the same group are deactivated.
"draw": Drawing tools (point, polyline, polygon)"measure": Measurement tools (distance, area)"none": No exclusion — can coexist with any plugin
To consume pick events, implement PickConsumer:
import type { PickConsumer } from "@core/map/contracts/PluginContract";
getPickConsumer(): PickConsumer {
return {
pluginId: this.id,
priority: this.priority,
onPick: (payload) => {
// Process the pick
// Return true to consume (stop propagation)
// Return false to pass to next consumer
return true;
},
};
}Register with InteractionBroker:
activate(ctx: PluginContext): void {
// Access broker via the MapApp
broker.register(this.getPickConsumer());
}- DisposeBag: Every plugin MUST own a DisposeBag
- Symmetric lifecycle:
activate()↔deactivate(), finaldispose() - No wild listeners: All event handlers go through the broker or DisposeBag
- requestRender(): Call after visual changes
- Use Primitives: Prefer
PolylineCollection,PointPrimitiveCollectionover Entity for performance