OpenLayers is a high-performance, feature-packed library for creating interactive maps on the web.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive event handling system providing map interactions, property changes, and lifecycle events with support for custom event listeners and conditions.
Foundation classes for the OpenLayers event system.
/**
* Base event class
*/
class BaseEvent {
constructor(type: string);
/** Event type string */
type: string;
/** Target object that fired the event */
target: any;
/** Whether default action is prevented */
defaultPrevented: boolean;
/** Prevent default action */
preventDefault(): void;
/** Stop event propagation */
stopPropagation(): void;
}
/**
* Map-specific event
*/
class MapEvent extends BaseEvent {
constructor(type: string, map: Map, frameState?: FrameState);
/** Map that fired the event */
map: Map;
/** Frame state at event time */
frameState?: FrameState;
}
/**
* Map browser event (user interactions)
*/
class MapBrowserEvent extends MapEvent {
constructor(type: string, map: Map, originalEvent: Event, dragging?: boolean, frameState?: FrameState);
/** Original browser event */
originalEvent: Event;
/** Pixel coordinates */
pixel: Pixel;
/** Map coordinates */
coordinate: Coordinate;
/** Whether currently dragging */
dragging: boolean;
}
/**
* Event target implementation
*/
class Target {
constructor();
/** Add event listener */
addEventListener(type: string, listener: (event: Event) => void): void;
/** Remove event listener */
removeEventListener(type: string, listener: (event: Event) => void): void;
/** Dispatch event */
dispatchEvent(event: Event | string): boolean;
}Core functions for managing event listeners.
/**
* Register event listener and return key for removal
* @param target - Event target
* @param type - Event type
* @param listener - Event listener function
* @param thisArg - Context for listener
*/
function listen(target: EventTarget, type: string, listener: ListenerFunction, thisArg?: Object): EventsKey;
/**
* Register one-time event listener
* @param target - Event target
* @param type - Event type
* @param listener - Event listener function
* @param thisArg - Context for listener
*/
function listenOnce(target: EventTarget, type: string, listener: ListenerFunction, thisArg?: Object): EventsKey;
/**
* Unregister event listener using key
* @param key - Event key returned from listen/listenOnce
*/
function unlistenByKey(key: EventsKey | EventsKey[]): void;
/**
* Unregister event listener by function
* @param target - Event target
* @param type - Event type
* @param listener - Event listener function
* @param thisArg - Context for listener
*/
function unlisten(target: EventTarget, type: string, listener: ListenerFunction, thisArg?: Object): void;Usage Examples:
import { listen, listenOnce, unlistenByKey } from 'ol/events';
import Map from 'ol/Map';
// Listen for map clicks
const map = new Map({...});
const clickKey = listen(map, 'click', (event) => {
console.log('Map clicked at:', event.coordinate);
});
// One-time listener
const loadKey = listenOnce(map, 'loadend', () => {
console.log('Map finished loading');
});
// Remove listener
unlistenByKey(clickKey);
// Multiple listeners
const keys = [
listen(map, 'movestart', onMoveStart),
listen(map, 'moveend', onMoveEnd)
];
// Remove all listeners
unlistenByKey(keys);Events specific to map lifecycle and interactions.
/** Map event types */
const MapEventType = {
/** Fired after map rendering */
POSTRENDER: 'postrender',
/** Fired when map starts moving */
MOVESTART: 'movestart',
/** Fired when map stops moving */
MOVEEND: 'moveend',
/** Fired when loading starts */
LOADSTART: 'loadstart',
/** Fired when loading ends */
LOADEND: 'loadend'
} as const;
/** Map browser event types */
const MapBrowserEventType = {
/** Single click event */
SINGLECLICK: 'singleclick',
/** Click event (includes double-clicks) */
CLICK: 'click',
/** Double click event */
DBLCLICK: 'dblclick',
/** Pointer drag event */
POINTERDRAG: 'pointerdrag',
/** Pointer move event */
POINTERMOVE: 'pointermove',
/** Pointer down event */
POINTERDOWN: 'pointerdown',
/** Pointer up event */
POINTERUP: 'pointerup',
/** Pointer over event */
POINTEROVER: 'pointerover',
/** Pointer out event */
POINTEROUT: 'pointerout',
/** Pointer enter event */
POINTERENTER: 'pointerenter',
/** Pointer leave event */
POINTERLEAVE: 'pointerleave',
/** Pointer cancel event */
POINTERCANCEL: 'pointercancel'
} as const;Usage Examples:
import Map from 'ol/Map';
const map = new Map({...});
// Map lifecycle events
map.on('loadstart', () => {
console.log('Map loading started');
});
map.on('loadend', () => {
console.log('Map loading finished');
});
map.on('movestart', (event) => {
console.log('Map started moving');
});
map.on('moveend', (event) => {
console.log('Map stopped moving');
console.log('New center:', map.getView().getCenter());
});
// Browser interaction events
map.on('singleclick', (event) => {
console.log('Single click at:', event.coordinate);
});
map.on('pointermove', (event) => {
// Mouse/touch move
const pixel = event.pixel;
const hit = map.hasFeatureAtPixel(pixel);
map.getTargetElement().style.cursor = hit ? 'pointer' : '';
});
map.on('dblclick', (event) => {
console.log('Double click - zoom in');
});Enhanced event handling for OpenLayers objects.
/**
* Observable class with convenient event methods
*/
class Observable extends Target {
constructor();
/** Add event listener (alias for addEventListener) */
on(type: string | string[], listener: (event: BaseEvent) => void): EventsKey | EventsKey[];
/** Add one-time event listener */
once(type: string | string[], listener: (event: BaseEvent) => void): EventsKey | EventsKey[];
/** Remove event listener */
un(type: string | string[], listener: (event: BaseEvent) => void): void;
/** Fire/dispatch an event */
dispatchEvent(event: BaseEvent | string): boolean;
/** Get revision number (incremented on changes) */
getRevision(): number;
/** Increment revision (trigger change event) */
changed(): void;
}Usage Examples:
import VectorSource from 'ol/source/Vector';
import Feature from 'ol/Feature';
const vectorSource = new VectorSource();
// Listen for feature changes
vectorSource.on('addfeature', (event) => {
console.log('Feature added:', event.feature);
});
vectorSource.on('removefeature', (event) => {
console.log('Feature removed:', event.feature);
});
vectorSource.on('changefeature', (event) => {
console.log('Feature changed:', event.feature);
});
// One-time listener
vectorSource.once('clear', () => {
console.log('Source cleared');
});
// Multiple event types
const keys = vectorSource.on(['addfeature', 'removefeature'], (event) => {
console.log('Feature collection changed');
});Events for object property modifications.
/** Object event types */
const ObjectEventType = {
/** Property change event */
PROPERTYCHANGE: 'propertychange'
} as const;
/**
* Property change event
*/
class ObjectEvent extends BaseEvent {
constructor(type: string, key: string, oldValue: any);
/** Property key that changed */
key: string;
/** Previous property value */
oldValue: any;
}Usage Examples:
import View from 'ol/View';
const view = new View({
center: [0, 0],
zoom: 2
});
// Listen for view property changes
view.on('propertychange', (event) => {
console.log(`Property "${event.key}" changed from`, event.oldValue, 'to', view.get(event.key));
});
// Listen for specific properties
view.on('change:center', () => {
console.log('Center changed to:', view.getCenter());
});
view.on('change:zoom', () => {
console.log('Zoom changed to:', view.getZoom());
});
view.on('change:rotation', () => {
console.log('Rotation changed to:', view.getRotation());
});
// Change properties to trigger events
view.setCenter([100, 100]);
view.setZoom(5);Events for collection modifications (adding/removing items).
/** Collection event types */
const CollectionEventType = {
/** Item added to collection */
ADD: 'add',
/** Item removed from collection */
REMOVE: 'remove'
} as const;
/**
* Collection event
*/
class CollectionEvent extends BaseEvent {
constructor(type: string, element: any, index?: number);
/** Element that was added/removed */
element: any;
/** Index of the element */
index?: number;
}Usage Examples:
import Collection from 'ol/Collection';
import Feature from 'ol/Feature';
const collection = new Collection();
// Listen for collection changes
collection.on('add', (event) => {
console.log('Item added at index', event.index, ':', event.element);
});
collection.on('remove', (event) => {
console.log('Item removed from index', event.index, ':', event.element);
});
// Add items to trigger events
const feature1 = new Feature();
const feature2 = new Feature();
collection.push(feature1);
collection.insertAt(0, feature2);
collection.remove(feature1);Events during the rendering process.
/**
* Render event fired during map rendering
*/
class RenderEvent extends BaseEvent {
constructor(type: string, vectorContext?: VectorContext, frameState?: FrameState, context?: CanvasRenderingContext2D, glContext?: WebGLRenderingContext);
/** Vector context for immediate rendering */
vectorContext?: VectorContext;
/** Current frame state */
frameState?: FrameState;
/** 2D canvas context */
context?: CanvasRenderingContext2D;
/** WebGL context */
glContext?: WebGLRenderingContext;
}Usage Examples:
import VectorLayer from 'ol/layer/Vector';
import { Style, Circle, Fill } from 'ol/style';
const vectorLayer = new VectorLayer({...});
// Listen for layer rendering
vectorLayer.on('prerender', (event) => {
// Before layer renders
console.log('Layer about to render');
});
vectorLayer.on('postrender', (event) => {
// After layer renders - can draw additional content
const vectorContext = event.vectorContext;
const frameState = event.frameState;
// Draw custom overlay graphics
vectorContext.setStyle(new Style({
image: new Circle({
radius: 5,
fill: new Fill({ color: 'red' })
})
}));
vectorContext.drawGeometry(customGeometry);
});
// Map-level render events
map.on('postrender', (event) => {
// After entire map renders
console.log('Map render complete');
});Predefined functions for testing event conditions in interactions.
/** Event condition function type */
type EventCondition = (event: MapBrowserEvent) => boolean;
/** Always return true */
const always: EventCondition;
/** Always return false */
const never: EventCondition;
/** Test for single click */
const singleClick: EventCondition;
/** Test for double click */
const doubleClick: EventCondition;
/** Test for no modifier keys */
const noModifierKeys: EventCondition;
/** Test for platform modifier key only (Cmd/Ctrl) */
const platformModifierKeyOnly: EventCondition;
/** Test for shift key only */
const shiftKeyOnly: EventCondition;
/** Test for alt key only */
const altKeyOnly: EventCondition;
/** Test for pointer move */
const pointerMove: EventCondition;
/** Test for primary action (left button/touch) */
const primaryAction: EventCondition;
/** Test that target element is not editable */
const targetNotEditable: EventCondition;Usage Examples:
import { Select } from 'ol/interaction';
import { click, platformModifierKeyOnly, shiftKeyOnly } from 'ol/events/condition';
// Use conditions in interactions
const selectInteraction = new Select({
condition: click, // Only on click
addCondition: shiftKeyOnly, // Shift+click to add to selection
removeCondition: platformModifierKeyOnly, // Ctrl/Cmd+click to remove
});
// Custom condition function
const customCondition = (event) => {
return event.originalEvent.button === 0 && // Left mouse button
!event.originalEvent.altKey && // No alt key
event.pixel[0] > 100; // X coordinate > 100
};
const customSelect = new Select({
condition: customCondition
});type EventsKey = {
target: EventTarget;
type: string;
listener: ListenerFunction;
};
type ListenerFunction = (event: Event | BaseEvent) => void;
type Pixel = [number, number];
type Coordinate = [number, number] | [number, number, number] | [number, number, number, number];
interface FrameState {
time: number;
viewState: ViewState;
animate: boolean;
coordinateToPixelTransform: Transform;
extent: Extent;
focus?: Coordinate;
index: number;
layerStatesArray: LayerState[];
layerIndex: number;
pixelRatio: number;
pixelToCoordinateTransform: Transform;
postRenderFunctions: PostRenderFunction[];
size: Size;
tileQueue: TileQueue;
usedTiles: Object<string, Object<string, boolean>>;
viewHints: number[];
wantedTiles: Object<string, Object<string, boolean>>;
}