From 0ed69c3648810bc453ef1a7d04be161ca894ae82 Mon Sep 17 00:00:00 2001 From: frees0l0 <69469354+frees0l0@users.noreply.github.com> Date: Wed, 22 Jan 2025 03:25:57 +0800 Subject: [PATCH] feat: add AMap(Gaode) provider (#409) Co-authored-by: Stephan Meijer --- .env.sample | 1 + .github/workflows/ci.yml | 1 + docs/lib/providers.ts | 5 ++ docs/providers/amap.mdx | 40 +++++++++++++++ src/index.ts | 1 + src/providers/__tests__/amapProvider.spec.js | 24 +++++++++ src/providers/__tests__/amapResponse.json | 30 ++++++++++++ src/providers/amapProvider.ts | 51 ++++++++++++++++++++ 8 files changed, 153 insertions(+) create mode 100644 docs/providers/amap.mdx create mode 100644 src/providers/__tests__/amapProvider.spec.js create mode 100644 src/providers/__tests__/amapResponse.json create mode 100644 src/providers/amapProvider.ts diff --git a/.env.sample b/.env.sample index 5fa237c0c..4845f2c99 100644 --- a/.env.sample +++ b/.env.sample @@ -3,4 +3,5 @@ GOOGLE_API_KEY=___YOUR_KEY___ LOCATIONIQ_API_KEY=___YOUR_KEY___ OPENCAGE_API_KEY=___YOUR_KEY___ HERE_API_KEY=___YOUR_KEY___ +AMAP_API_KEY=___YOUR_KEY___ GEOAPIFY_API_KEY=___YOUR_KEY___ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e4e64cff..cbd43d0d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,6 +120,7 @@ jobs: GATSBY_LOCATIONIQ_API_KEY: ${{ secrets.LOCATIONIQ_API_KEY }} GATSBY_OPENCAGE_API_KEY: ${{ secrets.OPENCAGE_API_KEY }} GATSBY_HERE_API_KEY: ${{ secrets.HERE_API_KEY }} + GATSBY_AMAP_API_KEY: ${{ secrets.AMAP_API_KEY }} update-docs: name: Update docs diff --git a/docs/lib/providers.ts b/docs/lib/providers.ts index d13c6ab14..baa9c3d17 100644 --- a/docs/lib/providers.ts +++ b/docs/lib/providers.ts @@ -11,6 +11,7 @@ import { PeliasProvider, GeoApiFrProvider, GeoapifyProvider, + AMapProvider, } from 'leaflet-geosearch'; export default { @@ -51,4 +52,8 @@ export default { Pelias: new PeliasProvider(), GeoApiFr: new GeoApiFrProvider(), + + AMap: new AMapProvider({ + params: { key: process.env.GATSBY_AMAP_API_KEY }, + }), }; diff --git a/docs/providers/amap.mdx b/docs/providers/amap.mdx new file mode 100644 index 000000000..274d8407b --- /dev/null +++ b/docs/providers/amap.mdx @@ -0,0 +1,40 @@ +--- +name: AMap +menu: Providers +route: /providers/amap +--- + +import Playground from '../components/Playground'; +import Map from '../components/Map'; + +# AMap Provider + +**note**: AMap services require an API key. [Obtain here][1]. +For more options and configurations, see the [AMap developer docs][2]. + + + + + +```js +import { AMapProvider } from 'leaflet-geosearch'; + +const provider = new AMapProvider({ + params: { + key: '__YOUR_AMAP_KEY__', + }, +}); + +// add to leaflet +import { GeoSearchControl } from 'leaflet-geosearch'; + +map.addControl( + new GeoSearchControl({ + provider, + style: 'bar', + }), +); +``` + +[1]: https://console.amap.com/dev/key/app +[2]: https://lbs.amap.com/api/webservice/guide/api/georegeo diff --git a/src/index.ts b/src/index.ts index 3ae242ff8..cebed54e3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,5 +16,6 @@ export { default as PeliasProvider } from './providers/peliasProvider'; export { default as MapBoxProvider } from './providers/mapBoxProvider'; export { default as GeoApiFrProvider } from './providers/geoApiFrProvider'; export { default as GeoapifyProvider } from './providers/geoapifyProvider'; +export { default as AMapProvider } from './providers/amapProvider'; export { default as JsonProvider } from './providers/provider'; diff --git a/src/providers/__tests__/amapProvider.spec.js b/src/providers/__tests__/amapProvider.spec.js new file mode 100644 index 000000000..f995af635 --- /dev/null +++ b/src/providers/__tests__/amapProvider.spec.js @@ -0,0 +1,24 @@ +import Provider from '../amapProvider'; +import fixtures from './amapResponse.json'; + +describe('AMapProvider', () => { + beforeAll(() => { + fetch.mockResponse(async () => ({ body: JSON.stringify(fixtures) })); + }); + + test('Can fetch results', async () => { + const provider = new Provider({ + params: { + key: process.env.AMAP_API_KEY, + }, + }); + + const results = await provider.search({ query: '上海市浦东新区外滩' }); + const result = results[0]; + + expect(result.label).toBeTruthy(); + expect(`${result.x},${result.y}`).toEqual(fixtures.geocodes[0].location); + // amap provider doesn't return bounds :( + expect(result.bounds).toBeNull(); + }); +}); diff --git a/src/providers/__tests__/amapResponse.json b/src/providers/__tests__/amapResponse.json new file mode 100644 index 000000000..ed68190b3 --- /dev/null +++ b/src/providers/__tests__/amapResponse.json @@ -0,0 +1,30 @@ +{ + "status": "1", + "info": "OK", + "infocode": "10000", + "count": "1", + "geocodes": [ + { + "formatted_address": "上海市浦东新区外滩", + "country": "中国", + "province": "上海市", + "citycode": "021", + "city": "上海市", + "district": "浦东新区", + "township": [], + "neighborhood": { + "name": [], + "type": [] + }, + "building": { + "name": [], + "type": [] + }, + "adcode": "310115", + "street": [], + "number": [], + "location": "121.497253,31.238235", + "level": "住宅区" + } + ] +} diff --git a/src/providers/amapProvider.ts b/src/providers/amapProvider.ts new file mode 100644 index 000000000..debf74a97 --- /dev/null +++ b/src/providers/amapProvider.ts @@ -0,0 +1,51 @@ +import AbstractProvider, { + EndpointArgument, + ParseArgument, + SearchResult, +} from './provider'; + +export type RequestResult = { + status: number; + count: number; + info: string; + geocodes: RawResult[]; +}; + +export interface RawResult { + formatted_address: string; + country: string; + province: string; + city: string; + citycode: string; + district: string; + number: string; + adcode: string; + location: string; + level: string; +} + +export default class AMapProvider extends AbstractProvider< + RequestResult, + RawResult +> { + searchUrl = 'https://restapi.amap.com/v3/geocode/geo'; + + endpoint({ query }: EndpointArgument): string { + const params = typeof query === 'string' ? { address: query } : query; + params.output = 'JSON'; + + return this.getUrl(this.searchUrl, params); + } + + parse(response: ParseArgument): SearchResult[] { + const records = response.data.geocodes ?? []; + + return records.map((r) => ({ + x: Number(r.location.substring(0, r.location.indexOf(','))), + y: Number(r.location.substring(r.location.indexOf(',') + 1)), + label: r.formatted_address, + bounds: null, + raw: r, + })); + } +}