Audience: GeoView core developers
GeoView uses a lightweight, fully typed delegate event system built on EventHelper static methods. There are no external event libraries — events are simple typed callback arrays managed by each class that owns them.
All delegate types extend this base generic:
export type EventDelegateBase<T, U, Z> = (sender: T, event: U) => Z;
T — Sender class (the object emitting the event)U — Event payload type (undefined for events with no data)Z — Return type (typically void)EventHelper (in packages/geoview-core/src/api/events/event-helper.ts) provides three static methods:
// Register a callback for an event
EventHelper.onEvent(handlersList, callback);
// Unregister a callback
EventHelper.offEvent(handlersList, callback);
// Emit an event to all registered handlers
EventHelper.emitEvent(sender, handlersList, event);
Define typed delegate aliases at the bottom of your file (or in a shared types file):
export type LayerNameChangedDelegate = EventDelegateBase<
AbstractBaseGVLayer,
LayerNameChangedEvent,
void
>;
export type LayerVisibleChangedDelegate = EventDelegateBase<
AbstractBaseGVLayer,
LayerVisibleChangedEvent,
void
>;
export type LayerNameChangedEvent = {
layerPath: string;
layerName: string;
};
export type LayerVisibleChangedEvent = {
layerPath: string;
visible: boolean;
};
export class MyLayer extends AbstractBaseGVLayer {
/** Callback delegates for the layer name changed event. */
#onLayerNameChangedHandlers: LayerNameChangedDelegate[] = [];
/** Callback delegates for the visible changed event. */
#onLayerVisibleChangedHandlers: LayerVisibleChangedDelegate[] = [];
/**
* Emits a layer name changed event to all handlers.
*/
#emitLayerNameChanged(event: LayerNameChangedEvent): void {
EventHelper.emitEvent(this, this.#onLayerNameChangedHandlers, event);
}
/**
* Emits a layer visible changed event to all handlers.
*/
#emitLayerVisibleChanged(event: LayerVisibleChangedEvent): void {
EventHelper.emitEvent(this, this.#onLayerVisibleChangedHandlers, event);
}
}
/**
* Registers a callback for the layer name changed event.
*/
onLayerNameChanged(callback: LayerNameChangedDelegate): void {
EventHelper.onEvent(this.#onLayerNameChangedHandlers, callback);
}
/**
* Unregisters a callback from the layer name changed event.
*/
offLayerNameChanged(callback: LayerNameChangedDelegate): void {
EventHelper.offEvent(this.#onLayerNameChangedHandlers, callback);
}
setLayerName(name: string): void {
this.#layerName = name;
this.#emitLayerNameChanged({ layerPath: this.getLayerPath(), layerName: name });
}
MapViewer defines map-level events (packages/geoview-core/src/geo/map/map-viewer.ts):
// Delegate types
export type MapInitDelegate = EventDelegateBase<MapViewer, undefined, void>;
export type MapMoveEndDelegate = EventDelegateBase<MapViewer, MapMoveEndEvent, void>;
export type MapZoomEndDelegate = EventDelegateBase<MapViewer, MapZoomEndEvent, void>;
// Private arrays
#onMapInitHandlers: MapInitDelegate[] = [];
#onMapMoveEndHandlers: MapMoveEndDelegate[] = [];
// Public subscribe/unsubscribe
onMapInit(callback: MapInitDelegate): void {
EventHelper.onEvent(this.#onMapInitHandlers, callback);
}
offMapInit(callback: MapInitDelegate): void {
EventHelper.offEvent(this.#onMapInitHandlers, callback);
}
// Private emit
#emitMapInit(): void {
EventHelper.emitEvent(this, this.#onMapInitHandlers, undefined);
}
Controllers subscribe to events in their onHook() lifecycle method and unsubscribe in onUnhook():
override onHook(): void {
// Subscribe to layer events
this.getMapViewer().onMapMoveEnd(this.#boundedHandleMapMoveEnd);
}
override onUnhook(): void {
// Unsubscribe to prevent memory leaks
this.getMapViewer().offMapMoveEnd(this.#boundedHandleMapMoveEnd);
}
useEffect(() => {
logger.logTraceUseEffect("COMPONENT - subscribe to map move end");
const handleMoveEnd = (sender: MapViewer, event: MapMoveEndEvent): void => {
setCenter(event.center);
};
mapViewer.onMapMoveEnd(handleMoveEnd);
return () => {
mapViewer.offMapMoveEnd(handleMoveEnd);
};
}, [mapViewer]);
#private#onXxxHandlers to prevent external manipulationoffEvent in cleanup (onUnhook(), useEffect return) to prevent memory leaksoffEvent| Element | Pattern | Example |
|---|---|---|
| Delegate type | {EventName}Delegate |
MapMoveEndDelegate |
| Event payload type | {EventName}Event |
MapMoveEndEvent |
| Handler array | #on{EventName}Handlers |
#onMapMoveEndHandlers |
| Subscribe method | on{EventName} |
onMapMoveEnd() |
| Unsubscribe method | off{EventName} |
offMapMoveEnd() |
| Emit method | #emit{EventName} |
#emitMapMoveEnd() |