leaflet-geosearch
Version:
Adds support for address lookup (a.k.a. geocoding / geosearching) to Leaflet.
93 lines (79 loc) • 2.38 kB
text/typescript
import AbstractProvider, {
EndpointArgument,
ParseArgument,
ProviderOptions,
SearchArgument,
SearchResult,
} from './provider';
import { Loader, LoaderOptions } from '@googlemaps/js-api-loader';
export interface RequestResult {
results: google.maps.GeocoderResult[];
status?: google.maps.GeocoderStatus;
}
export interface GeocodeError {
code: Exclude<google.maps.GeocoderStatus, google.maps.GeocoderStatus.OK>;
endpoint: 'GEOCODER_GEOCODE';
message: string;
name: 'MapsRequestError';
stack: string;
}
export type GoogleProviderOptions = LoaderOptions & ProviderOptions;
export default class GoogleProvider extends AbstractProvider<
RequestResult,
google.maps.GeocoderResult
> {
loader: Promise<google.maps.Geocoder> | null = null;
geocoder: google.maps.Geocoder | null = null;
constructor(options: GoogleProviderOptions) {
super(options);
if (typeof window !== 'undefined') {
this.loader = new Loader(options).load().then((google) => {
const geocoder = new google.maps.Geocoder();
this.geocoder = geocoder;
return geocoder;
});
}
}
endpoint({ query }: EndpointArgument): never {
throw new Error('Method not implemented.');
}
parse(
response: ParseArgument<RequestResult>,
): SearchResult<google.maps.GeocoderResult>[] {
return response.data.results.map((r) => {
const { lat, lng } = r.geometry.location.toJSON();
const { east, north, south, west } = r.geometry.viewport.toJSON();
return {
x: lng,
y: lat,
label: r.formatted_address,
bounds: [
[south, west],
[north, east],
],
raw: r,
};
});
}
async search(
options: SearchArgument,
): Promise<SearchResult<google.maps.GeocoderResult>[]> {
const geocoder = this.geocoder || (await this.loader);
if (!geocoder) {
throw new Error(
'GoogleMaps GeoCoder is not loaded. Are you trying to run this server side?',
);
}
const response = await geocoder
.geocode({ address: options.query }, (response) => ({
results: response,
}))
.catch((e: GeocodeError) => {
if (e.code !== 'ZERO_RESULTS') {
console.error(`${e.code}: ${e.message}`);
}
return { results: [] };
});
return this.parse({ data: response });
}
}