diff --git a/README.md b/README.md index c0fee8b..75c1651 100755 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ The plugin supports many different data providers: - [ArcGIS](https://developers.arcgis.com/features/geocoding/) - [Azure Maps Geocoding](https://www.microsoft.com/en-us/maps/azure/location-services/geocoding) +Multiple data providers can be combined by using the AggregatingGeocoder. + The plugin can easily be extended to support other providers. Current extensions: - [DAWA Geocoder](https://github.com/kjoller/leaflet-control-geocoder-dawa/tree/new) - support for Danish Address Web API by [Niels Kjøller Hansen](https://github.com/kjoller) diff --git a/spec/aggregating-geocoder.spec.ts b/spec/aggregating-geocoder.spec.ts new file mode 100644 index 0000000..faf777f --- /dev/null +++ b/spec/aggregating-geocoder.spec.ts @@ -0,0 +1,39 @@ +import { describe, expect, it, vi } from 'vitest'; +import { AggregatingGeocoder, AgregatorOptions } from '../src/geocoders/aggregating-geocoder'; +import { LatLngLiteral } from 'leaflet'; + +describe('L.Control.Geocoder.AggregatingGeocoder', () => { + it('geocde returns empty when no geocoders', async () => { + const options: AgregatorOptions = { + geocoders: [] + } + const geocoder = new AggregatingGeocoder(options); + + const results = await geocoder.geocode('foo'); + expect(results).toEqual([]); + }); + + it('suggest returns empty when no geocoders', async () => { + const options: AgregatorOptions = { + geocoders: [] + } + const geocoder = new AggregatingGeocoder(options); + + const results = await geocoder.suggest('foo'); + expect(results).toEqual([]); + }); + + it('reverse returns emtpy when no geocoders', async () => { + const options: AgregatorOptions = { + geocoders: [] + } + const geocoder = new AggregatingGeocoder(options); + + const loc: LatLngLiteral = { + lat: 0, + lng: 0 + }; + const results = await geocoder.reverse(loc, 1); + expect(results).toEqual([]); + }); +}); diff --git a/src/geocoders/aggregating-geocoder.ts b/src/geocoders/aggregating-geocoder.ts new file mode 100644 index 0000000..e18477d --- /dev/null +++ b/src/geocoders/aggregating-geocoder.ts @@ -0,0 +1,65 @@ +import * as L from 'leaflet'; +import { LatLngLiteral } from 'leaflet'; +import { IGeocoder, GeocodingContext, GeocodingResult } from './api'; + +export interface AgregatorOptions { + geocoders: IGeocoder[]; +} + +/** + * Implementation of a geocoder that takes other geocoders and aggregates their results together. + **/ +export class AggregatingGeocoder implements IGeocoder { + options: AgregatorOptions = { + geocoders: [] + } + + constructor(options?: Partial) { + L.Util.setOptions(this, options) + } + + private async combineResults(queries: Array>): Promise { + const queryResults: Array = await Promise.all(queries); + const results: Array = []; + for(const r of queryResults) { + results.push(...r); + } + return results; + } + + geocode(query: string, context?: GeocodingContext): Promise { + const queries: Promise[] = []; + for(const geocoder of this.options.geocoders) { + queries.push(geocoder.geocode(query, context)); + } + return this.combineResults(queries); + } + + suggest?(query: string, context?: GeocodingContext): Promise { + const queries: Promise[] = []; + for(const geocoder of this.options.geocoders) { + if (geocoder.suggest) { + queries.push(geocoder.suggest(query, context)); + } + } + return this.combineResults(queries); + } + + reverse?(location: LatLngLiteral, scale: number): Promise { + const queries: Promise[] = []; + for(const geocoder of this.options.geocoders) { + if (geocoder.reverse) { + queries.push(geocoder.reverse(location, scale)); + } + } + return this.combineResults(queries); + } +} + +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link AggregatingGeocoder} + * @param options the services to aggregate together. + */ +export function aggregatingGeocoder(options: Partial) { + return new AggregatingGeocoder(options); +} diff --git a/src/geocoders/index.ts b/src/geocoders/index.ts index d9bc545..86c3ce6 100644 --- a/src/geocoders/index.ts +++ b/src/geocoders/index.ts @@ -14,3 +14,4 @@ export * from './opencage'; export * from './pelias'; export * from './photon'; export * from './what3words'; +export * from './aggregating-geocoder';