Skip to content

Commit

Permalink
feat: add GeoApiFR provider (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
patou authored Aug 12, 2021
1 parent 21e8004 commit 6d8ef6a
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 19 deletions.
41 changes: 22 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Leaflet.GeoSearch

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->

[![All Contributors](https://img.shields.io/badge/all_contributors-42-orange.svg?style=flat-square)](#contributors-)

<!-- ALL-CONTRIBUTORS-BADGE:END -->

**Demo and Docs: [smeijer.github.io/leaflet-geosearch](https://smeijer.github.io/leaflet-geosearch)**
Expand Down Expand Up @@ -55,6 +57,7 @@ The control comes with a number of default providers:
- [OpenCage]
- [OpenStreetMap]
- [Mapbox](https://docs.mapbox.com/help/tutorials/local-search-geocoding-api/)
- [GeoApiFR](https://geo.api.gouv.fr/adresse)

Although this project is still named `leaflet-geosearch`, this library is also
usable without LeafletJS, and does not have any dependencies whatsoever.
Expand Down Expand Up @@ -168,7 +171,6 @@ const map = new L.Map('map');
map.addControl(searchControl);
```


# Using with react-leaflet

Usage with `react-leaflet` is similar to the usage with plain Leaflet. This example
Expand All @@ -178,11 +180,13 @@ leaflet example.

```jsx
import { GeoSearchControl, MapBoxProvider } from 'leaflet-geosearch';
import {useMap} from 'react-leaflet';
const SearchField = ({apiKey}) => {
const provider = new MapBoxProvider({ params: {
access_token: apiKey
}});
import { useMap } from 'react-leaflet';
const SearchField = ({ apiKey }) => {
const provider = new MapBoxProvider({
params: {
access_token: apiKey,
},
});

// @ts-ignore
const searchControl = new GeoSearchControl({
Expand All @@ -193,28 +197,27 @@ const SearchField = ({apiKey}) => {
useEffect(() => {
map.addControl(searchControl);
return () => map.removeControl(searchControl);
}, [])
}, []);

return null;
}
};
```

The `useEffect` hook used in `SearchField` even allows for conditional rendering of the
search field.

```jsx
import {MapContainer} from 'react-leaflet';
import { MapContainer } from 'react-leaflet';
const MyMap = () => {
// ...
return (
<MapContainer>
{showSearch && <SearchField apiKey={apiKey} />}

{/* ... */}
</MapContainer>
);
}

// ...
return (
<MapContainer>
{showSearch && <SearchField apiKey={apiKey} />}

{/* ... */}
</MapContainer>
);
};
```

## GeoSearchControl
Expand Down
3 changes: 3 additions & 0 deletions docs/lib/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
LocationIQProvider,
OpenCageProvider,
OpenStreetMapProvider,
GeoApiFrProvider,
} from 'leaflet-geosearch';

export default {
Expand Down Expand Up @@ -35,4 +36,6 @@ export default {
}),

OpenStreetMap: new OpenStreetMapProvider(),

GeoApiFr: new GeoApiFrProvider(),
};
53 changes: 53 additions & 0 deletions docs/providers/geoapifr.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
name: GeoApiFr
menu: Providers
route: /providers/geoapifr
---

import Playground from '../components/Playground';
import Map from '../components/Map';

# GeoApiFr Provider

For more options and configurations, see the [Geo Api FR][1].

<Playground>
<Map provider="GeoApiFr" />
</Playground>

```js
import { GeoApiFrProvider } from 'leaflet-geosearch';

const provider = new GeoApiFrProvider();

// add to leaflet
import { GeoSearchControl } from 'leaflet-geosearch';

map.addControl(
new GeoSearchControl({
provider,
}),
);
```

## Optional parameters

Geo Api FR supports a number of [optional parameters][2]. As the api requires those parameters to be added to the url, they can be added to the `params` key of the provider.

All options defined next to the `params` key, would have been added to the request body.

```js
const provider = new OpenStreetMapProvider({
searchUrl: 'https://api-adresse.data.gouv.fr/search',
reverseUrl: 'https://api-adresse.data.gouv.fr/reverse',
params: {
type: 'municipality', // limit search results to city
autocomplete: 1, // Use in autocomplete mode (search in prefix mode)
lat: 0, // Latitude in degree
lon: 0, // Longitude in degree
},
});
```

[1]: https://geo.api.gouv.fr/
[2]: https://geo.api.gouv.fr/adresse
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export { default as LocationIQProvider } from './providers/locationIQProvider';
export { default as OpenCageProvider } from './providers/openCageProvider';
export { default as OpenStreetMapProvider } from './providers/openStreetMapProvider';
export { default as MapBoxProvider } from './providers/mapBoxProvider';
export { default as GeoApiFrProvider } from './providers/geoApiFrProvider';

export { default as JsonProvider } from './providers/provider';
84 changes: 84 additions & 0 deletions src/providers/geoApiFrProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import AbstractProvider, {
EndpointArgument,
ParseArgument,
ProviderOptions,
SearchResult,
RequestType,
} from './provider';

export interface RequestResult {
features: RawResult[];
type: string;
version: string;
attribution: string;
licence: string;
query: string;
limit: string;
}

export interface RawResult {
properties: {
label: string;
score: number;
importance: number;
x: number;
y: number;
housenumber: string;
id: string;
type: string;
name: string;
postcode: string;
citycode: string;
city: string;
context: string;
street: string;
};
type: string;
geometry: {
coordinates: number[];
type: string;
};
}

export type GeoApiFrProviderOptions = {
searchUrl?: string;
reverseUrl?: string;
} & ProviderOptions;

export default class GeoApiFrProvider extends AbstractProvider<
RequestResult,
RawResult
> {
searchUrl: string;
reverseUrl: string;

constructor(options: GeoApiFrProviderOptions = {}) {
super(options);

const host = 'https://api-adresse.data.gouv.fr';
this.searchUrl = options.searchUrl || `${host}/search`;
this.reverseUrl = options.reverseUrl || `${host}/reverse`;
}

endpoint({ query, type }: EndpointArgument) {
const params = typeof query === 'string' ? { q: query } : query;

switch (type) {
case RequestType.REVERSE:
return this.getUrl(this.reverseUrl, params);

default:
return this.getUrl(this.searchUrl, params);
}
}

parse(result: ParseArgument<RequestResult>): SearchResult<RawResult>[] {
return result.data.features.map((r) => ({
x: r.geometry.coordinates[0],
y: r.geometry.coordinates[1],
label: r.properties.label,
bounds: null,
raw: r,
}));
}
}
1 change: 1 addition & 0 deletions src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export { default as LocationIQProvider } from './locationIQProvider';
export { default as OpenCageProvider } from './openCageProvider';
export { default as OpenStreetMapProvider } from './openStreetMapProvider';
export { default as MapBoxProvider } from './mapBoxProvider';
export { default as GeoApiFrProvider } from './geoApiFrProvider';

export { default as Provider } from './provider';

0 comments on commit 6d8ef6a

Please sign in to comment.