UNPKG

@independo/leaflet-independo-maps

Version:

Leaflet plugin for displaying points of interest as pictograms.

511 lines (498 loc) 18.1 kB
import L, { LatLngExpression, Map, LatLngBounds } from 'leaflet'; interface Pictogram { /** * A unique identifier for the pictogram. * This ID is provided by the underlying data source (e.g., Global Symbols API). */ id: string; /** * URL of the pictogram. */ url: string; /** * Text to display below the pictogram. */ displayText: string; /** * ARIA label for the pictogram. */ ariaLabel?: string; /** * Description of the pictogram. */ description?: string; /** * A flexible container for any additional metadata from the data source. */ metadata?: Record<string, any>; } /** * Represents a single point of interest (POI). * * A Point of Interest (POI) is a location that has specific significance, * such as a restaurant, park, store, landmark, or other notable place. * Each POI contains key information such as its name, type, and geographic location. */ interface PointOfInterest { /** * A unique identifier for the point of interest. * This ID is provided by the underlying data source (e.g., Google Places, Overpass API). */ id: string; /** * The human-readable name of the point of interest. * @example "Cafe Mozart", "Schönbrunn Palace" */ name: string; /** * The category or type of the point of interest. * @example "restaurant", "park", "museum" */ type: string; /** * The latitude coordinate of the point of interest. */ latitude: number; /** * The longitude coordinate of the point of interest. */ longitude: number; /** * An optional address or description of the point of interest. * @example "Albertinaplatz 2, 1010 Wien, Austria" */ address?: string; /** * A flexible container for any additional metadata from the data source. * E.g. operational hours, tags, or other details. */ metadata?: Record<string, any>; } interface PictogramMarkerOptions { /** * Whether to add the pictogram description to the pictogram marker in case a description is available. * * @default false */ addDescription?: boolean; /** * Whether to bring the pictogram marker to the front when clicked. * * @default true */ bringToFrontOnClick?: boolean; /** * Whether to bring the pictogram marker to the front when hovered. * * @default true */ bringToFrontOnHover?: boolean; /** * Whether to bring the pictogram marker to the front when focused. * * @default true */ bringToFrontOnFocus?: boolean; /** * A callback function that is called when the pictogram marker is clicked. * * @default undefined */ onClick?: (pictogram: Pictogram, pointOfInterest?: PointOfInterest) => void; } /** * A custom Leaflet layer that displays a pictogram marker at a specified geographical location. * * This marker supports accessibility features, customizable interactions, and flexible styling. * It is designed to be used with the Leaflet library and integrates easily into any Leaflet map. */ declare class PictogramMarker extends L.Layer { private readonly addDescription; private readonly bringToFrontOnClick; private readonly bringToFrontOnHover; private readonly bringToFrontOnFocus; private readonly onClick; private readonly _latlng; private readonly _pictogram; private readonly _pointOfInterest; private container?; private box?; private map; getLatLng(): L.LatLng; /** * Constructs a new instance of the `PictogramMarker` class. * * @param latlng - The geographical coordinates where the marker should be placed. * @param pictogram - The pictogram object containing the display data (e.g., URL, label, description). * @param pointOfInterest - (Optional) The associated point of interest for this marker. * @param options - (Optional) Configuration options for the marker's behavior and interactivity. * * @example * ```typescript * const latlng = L.latLng(48.20849, 16.37208); * const pictogram = { * id: '1', * url: 'https://example.com/pictogram.png', * displayText: 'Restaurant', * description: 'A fine dining restaurant serving local cuisine.' * }; * * const options = { * addDescription: true, * bringToFrontOnClick: true, * onClick: (pictogram) => { * console.log('Pictogram clicked:', pictogram); * } * }; * * const marker = new PictogramMarker(latlng, pictogram, undefined, options); * marker.addTo(map); * ``` */ constructor(latlng: LatLngExpression, pictogram: Pictogram, pointOfInterest?: PointOfInterest, options?: PictogramMarkerOptions); onAdd(map: Map): this; onRemove(map: Map): this; private updatePosition; private setupInteractions; private toggleInFront; } /** * Options for querying points of interest within a specified geographic area. * * Implementations should adhere to the following behaviors: * - If the `types` array is not provided, the query should include all available types. * - If the `types` array is provided but is empty, the query should exclude all results (no types match). * - The `limit` specifies the maximum number of results and should be respected when provided. * - The `metadata` field allows for additional, implementation-specific query parameters. */ interface PointOfInterestQueryOptions { /** * A list of types or categories to filter the results. * - If this field is omitted, the query should include all available types. * - If this field is provided as an empty array, the query should return no results. * Examples: ["restaurant", "park", "museum"]. */ types?: string[]; /** * The maximum number of results to return. * If omitted, the implementation should return all results or the default maximum limit. * Example: 50. */ limit?: number; /** * A flexible container for any additional options specific to the implementation. * This can include fields such as `openNow` (only return currently open places), `radius`, or API-specific flags. */ metadata?: Record<string, any>; } /** * Abstract interface for a service that fetches points of interest (POIs) * within a specified geographic area. * * Implementations of this interface should: * - Query a data source (e.g., Google Places API, Overpass API, or Apple Maps Server API). * - Adhere to the filtering and behavior rules defined in `PointOfInterestQueryOptions`. * - Return a list of POIs with standardized fields as defined in `PointOfInterest`. */ interface PointOfInterestService { /** * Fetches a list of points of interest within the given bounds. * * @param bounds - The geographic bounds for the query. Specifies the area to search for POIs. * @param options - Optional filters and query settings. * - If `types` is omitted, all available POI types should be included in the query. * - If `types` is an empty array, no POIs should be returned. * - If `limit` is specified, the implementation should respect this value. * @returns A promise resolving to an array of POIs. */ getPointsOfInterest(bounds: LatLngBounds, options?: PointOfInterestQueryOptions): Promise<PointOfInterest[]>; } /** * Options for configuring the OverpassPOIService. */ interface OverpassPOIServiceOptions { /** * The base URL of the Overpass API endpoint. * * @default "https://overpass-api.de/api/interpreter". * @see https://wiki.openstreetmap.org/wiki/Overpass_API#Public_Overpass_API_instances Public Overpass API instances */ apiUrl?: string; /** * Default types of points of interest to query if none are provided in the {@link PointOfInterestQueryOptions} * object in the {@link getPointsOfInterest} method. * * @default ["shop", "leisure"] * @see https://wiki.openstreetmap.org/wiki/Key:shop * @see https://wiki.openstreetmap.org/wiki/Key:leisure */ defaultTypes?: string[]; /** * OpenStreetMap types to query. * Possible values: "node", "way", "relation". * * @default ["node"] * @see https://wiki.openstreetmap.org/wiki/Elements */ osmTypes?: string[]; /** * Default number of points of interest to query if no limit is provided in the {@link PointOfInterestQueryOptions} * object in the {@link getPointsOfInterest} method. * * @default 25 */ defaultLimit?: number; /** * Maximum number of retries for requests in case of rate limiting or server errors. * * @default 3 */ maxRetries?: number; /** * Timeout between retries in milliseconds. * * @default 1000 */ retryDelay?: number; /** * Timeout for a single request in seconds. * * @default 25 */ timeout?: number; /** * Whether to try to derive names for POIs with no name from their type. * * Some POIs may not have a name, but they have a type (e.g., "restaurant"). If this option is enabled, * the service will try to derive a generic name for the {@link PointOfInterest} from the type (e.g., "Restaurant"). * * @default true */ deriveNames?: boolean; /** * Whether to filter out POIs with no name. * * If this option is enabled, POIs with no name will be filtered out from the results. * Otherwise, POIs with no name will be included in the results and will have the name "Unknown". * * @default true */ filterOutNoName?: boolean; } /** * Abstract interface for a service that provides a {@link Pictogram} for a given {@link PointOfInterest}. */ interface PictogramService { /** * @description Fetches a pictogram for the given point of interest. * * @param poi The {@link PointOfInterest} to fetch a pictogram for. * @returns A promise resolving to a {@link Pictogram} object or `undefined` if no pictogram is found. */ getPictogram(poi: PointOfInterest): Promise<Pictogram | undefined>; } /** * @description Options for configuring the GlobalSymbolsPictogramService. * @see https://globalsymbols.com/api/docs Global Symbols API documentation */ interface GlobalSymbolsPictogramServiceOptions { /** * @description The base URL of the Global Symbols API endpoint. * @default "https://globalsymbols.com/api/v1/concepts/suggest". */ apiUrl?: string; /** * @description The symbol set the pictogram should be fetched from. * @default "arasaac" * @remarks Examples: `"arasaac"`, `"sclera"`, `"blissymbols"`, etc. * @see https://globalsymbols.com/api/docs Global Symbols API documentation * @see https://globalsymbols.com/api/v1/symbolsets GET all available symbol sets */ symbolSet?: string; /** * @description Include the type of the point of interest in the display text of the pictogram. * @default false */ includeTypeInDisplayText?: boolean; /** * @description Include the type of the point of interest in the aria label of the pictogram. * @default true */ includeTypeInAriaLabel?: boolean; /** * @description Cache strategy: "in-memory" (in-memory caching) or "local-storage" (persistent caching). * @default "local-storage" */ cacheStrategy?: "in-memory" | "local-storage"; /** * @description Cache expiration time in milliseconds. * @default 604800000 (1 week) */ cacheExpiration?: number; /** * @description Cache prefix for the local storage cache. * @default "global-symbols-pictogram-service" * @remarks This is used to avoid conflicts with other local storage items. */ cachePrefix?: string; } /** * Abstract interface for a service that sorts markers on a map. * * The sorting order does not affect the visual position of the markers on the map, but rather the order in which they * are added to the DOM. This is relevant for screen readers and keyboard navigation. */ interface MarkerSortingService { /** * Sorts the given markers but DOES NOT add them to the map. * * @param markers The markers to sort. * @param map The map is provided for context, e.g. to determine the current map bounds, mapping the coordinates * to layer points, etc. * * @returns A promise resolving to the sorted markers. */ sortMarkers(markers: PictogramMarker[], map: L.Map): Promise<PictogramMarker[]>; } interface GridSortingServiceOptions { /** * The layout direction for the x-axis: "lr" (left-to-right) or "rl" (right-to-left). * * @default "lr" */ lr: "lr" | "rl"; /** * The layout direction for the y-axis: "tb" (top-to-bottom) or "bt" (bottom-to-top). * * @default "tb" */ tb: "tb" | "bt"; /** * The threshold in pixels to determine row separation. * * @default 64 */ rowThreshold: number; } /** * Options for configuring the Independo Maps plugin. */ interface IndependoMapsOptions { /** * Options for the {@link PictogramMarker}s created by the plugin. */ pictogramMarkerOptions?: PictogramMarkerOptions; /** * Options for configuring the default {@link OverpassPOIService}. * * These options are used if no custom `poiService` is provided. * Allows customization of the Overpass API endpoint, default types, and other service-specific behaviors. * * @example * ```typescript * overpassServiceOptions: { * apiUrl: "https://custom-overpass-api.com", * defaultLimit: 50, * defaultTypes: ["amenity", "shop", "tourism"] * }; * ``` */ overpassServiceOptions?: OverpassPOIServiceOptions; /** * Options for configuring the default {@link GlobalSymbolsPictogramService}. * * These options are used if no custom `pictogramService` is provided. * Allows customization of behavior such as including types in display text and symbol set selection. * * @example * ```typescript * globalSymbolsServiceOptions: { * includeTypeInDisplayText: true, * symbolSet: "your-custom-symbolset" * }; * ``` */ globalSymbolsServiceOptions?: GlobalSymbolsPictogramServiceOptions; /** * Options for configuring the default {@link GridSortingService}. * * @remarks This option is used to define the layout direction of the pictograms when adding them to the DOM. * This is relevant for screen readers and keyboard navigation. On the * @example {lr: "lr", tb: "tb"} */ gridSortServiceOptions?: GridSortingServiceOptions; /** * Custom implementation of the {@link PointOfInterestService}. * * Use this field to provide your own service for fetching points of interest (POIs). * If not provided, the plugin will default to an instance of {@link OverpassPOIService}. * * @example * ```typescript * poiService: new CustomPOIService(); * ``` */ poiService?: PointOfInterestService; /** * Custom implementation of the {@link PictogramService}. * * Use this field to provide your own service for fetching pictograms for POIs. * If not provided, the plugin will default to an instance of {@link GlobalSymbolsPictogramService}. * * @example * ```typescript * pictogramService: new CustomPictogramService(); * ``` */ pictogramService?: PictogramService; /** * Custom implementation of the {@link MarkerSortingService}. * * Use this field to provide your own service for sorting markers on the map. * If not provided, the plugin will default to an instance of {@link GridSortingService}. * * @remarks The sorting order does not affect the visual position of the markers on the map, but rather the order in * which they are added to the DOM. This is relevant for screen readers and keyboard navigation. One can imagine * use cases where the markers should be sorted in a specific order, e.g. by distance to the user's location. */ markerSortingService?: MarkerSortingService; /** * Debounce interval in milliseconds for updating the map after a move or zoom event. * * @remarks This interval prevents the map from updating too frequently and causing performance issues. * @default 300 */ debounceInterval?: number; /** * The default pictogram to use when no pictogram is found for a POI. * * @remarks This pictogram will be used when the pictogram service returns `undefined` for a POI. If no pictogram * can be found for a POI and the default pictogram is not provided, the POI will not be displayed on the map. * @default undefined */ defaultPictogram?: Pictogram; } declare class IndependoMaps { private readonly debounceInterval; private readonly defaultPictogram?; private readonly map; private readonly poiLayerGroup; private readonly poiService; private readonly pictogramService; private readonly markerSortingService; private readonly pictogramMarkerOptions?; constructor(map: L.Map, options?: IndependoMapsOptions); /** * Updates the map by fetching POIs and adding corresponding markers. */ private updateMap; } /** * Initializes the Independo Maps plugin on a {@link L.Map} and returns an instance of the plugin. * * @param map The {@link L.Map} to initialize the plugin on. * @param options Optional {@link IndependoMapsOptions} to configure the plugin. * @returns An instance of {@link IndependoMaps}. */ declare function initIndependoMaps(map: L.Map, options?: IndependoMapsOptions): IndependoMaps; export { PictogramMarker, initIndependoMaps };