CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ol

OpenLayers is a high-performance, feature-packed library for creating interactive maps on the web.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

events-system.mddocs/

Events System

Comprehensive event handling system providing map interactions, property changes, and lifecycle events with support for custom event listeners and conditions.

Capabilities

Core Event Classes

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;
}

Event Registration Functions

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);

Map Events

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');
});

Observable Class Methods

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');
});

Property Change Events

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);

Collection Events

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);

Render Events

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');
});

Event Conditions

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
});

Types

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>>;
}

Install with Tessl CLI

npx tessl i tessl/npm-ol

docs

controls-ui.md

coordinate-systems-projections.md

core-map-system.md

data-sources.md

events-system.md

format-support.md

index.md

layer-management.md

styling-system.md

user-interactions.md

vector-features-geometries.md

tile.json