diff --git a/spec/__snapshots__/here.spec.ts.snap b/spec/__snapshots__/here.spec.ts.snap index 838c5adf..a8ac3aef 100644 --- a/spec/__snapshots__/here.spec.ts.snap +++ b/spec/__snapshots__/here.spec.ts.snap @@ -47,3 +47,42 @@ Array [ ], ] `; + +exports[`L.Control.Geocoder.HEREv2 geocodes Innsbruck 1`] = ` +Array [ + Array [ + Array [ + Object { + "bbox": Object { + "_northEast": Object { + "lat": 42.36355, + "lng": -71.05439, + }, + "_southWest": Object { + "lat": 42.36355, + "lng": -71.05439, + }, + }, + "center": Object { + "lat": 42.36355, + "lng": -71.05439, + }, + "name": "Salumeria Italiana, 151 Richmond St, Boston, MA 02109, United States", + "properties": Object { + "city": "Boston", + "countryCode": "USA", + "countryName": "United States", + "county": "Suffolk", + "district": "North End", + "houseNumber": "151", + "label": "Salumeria Italiana, 151 Richmond St, Boston, MA 02109, United States", + "postalCode": "02109", + "state": "Massachusetts", + "stateCode": "MA", + "street": "Richmond St", + }, + }, + ], + ], +] +`; diff --git a/spec/here.spec.ts b/spec/here.spec.ts index 06569b35..953dbec7 100644 --- a/spec/here.spec.ts +++ b/spec/here.spec.ts @@ -1,5 +1,6 @@ import { testXMLHttpRequest } from './mockXMLHttpRequest'; import { HERE } from '../src/geocoders/here'; +import { HEREv2 } from '../src/geocoders/here'; import { GeocodingResult } from '../src/geocoders/api'; describe('L.Control.Geocoder.HERE', () => { @@ -85,3 +86,83 @@ describe('L.Control.Geocoder.HERE', () => { expect(callback.mock.calls).toMatchSnapshot(); }); }); + +describe('L.Control.Geocoder.HEREv2', () => { + it('geocodes Innsbruck', () => { + let geocodingParams = {at:'50.62925,3.057256'}; + const geocoder = new HEREv2({ apiKey: 'xxx', geocodingQueryParams: geocodingParams }); + const callback = jest.fn(); + testXMLHttpRequest( + 'https://geocode.search.hereapi.com/v1/discover?q=Innsbruck&apiKey=xxx&at=50.62925%2C3.057256', + { + "items": [ + { + "title": "Salumeria Italiana", + "id": "here:pds:place:840drt3p-898f6ee434794fe59895e71ccf9381e1", + "ontologyId": "here:cm:ontology:restaurant", + "resultType": "place", + "address": { + "label": "Salumeria Italiana, 151 Richmond St, Boston, MA 02109, United States", + "countryCode": "USA", + "countryName": "United States", + "stateCode": "MA", + "state": "Massachusetts", + "county": "Suffolk", + "city": "Boston", + "district": "North End", + "street": "Richmond St", + "postalCode": "02109", + "houseNumber": "151" + }, + "position": { "lat": 42.36355, "lng": -71.05439 }, + "access": [{ "lat": 42.3635, "lng": -71.05448 }], + "distance": 11, + "categories": [ + { "id": "600-6300-0066", "name": "Grocery", "primary": true }, + { "id": "100-1000-0000", "name": "Restaurant" }, + { "id": "100-1000-0006", "name": "Deli" }, + { "id": "600-6300-0067", "name": "Specialty Food Store" } + ], + "references": [ + { "supplier": { "id": "core" }, "id": "31213861" }, + { "supplier": { "id": "tripadvisor" }, "id": "3172680" }, + { "supplier": { "id": "yelp" }, "id": "JNx0DlfndRurT-8KhSym7g" }, + { "supplier": { "id": "yelp" }, "id": "P44VNcZUUNZfiFy-c4SUJw" } + ], + "foodTypes": [ + { "id": "304-000", "name": "Italian", "primary": true }, + { "id": "800-057", "name": "Pizza" }, + { "id": "800-060", "name": "Sandwich" } + ], + "contacts": [ + { + "phone": [{ "value": "+16175234946" }, { "value": "+16175238743" }, { "value": "+16177204243" }], + "fax": [{ "value": "+16175234946" }], + "www": [ + { "value": "http://www.salumeriaitaliana.com" } + ], + "email": [{ "value": "contact@salumeriaitaliana.com" }] + } + ], + "openingHours": [ + { + "text": ["Mon-Sat: 08:00 - 17:00", "Sun: 10:00 - 16:00"], + "isOpen": false, + "structured": [ + { "start": "T080000", "duration": "PT11H00M", "recurrence": "FREQ:DAILY;BYDAY:MO,TU,WE,TH,FR,SA" }, + { "start": "T100000", "duration": "PT06H00M", "recurrence": "FREQ:DAILY;BYDAY:SU" } + ] + } + ] + } + ] + }, + () => geocoder.geocode('Innsbruck', callback) + ); + + const feature: GeocodingResult = callback.mock.calls[0][0][0]; + expect(feature.name).toBe('Salumeria Italiana, 151 Richmond St, Boston, MA 02109, United States'); + expect(feature.center).toStrictEqual({ "lat": 42.36355, "lng": -71.05439 }); + expect(callback.mock.calls).toMatchSnapshot(); + }); +}); diff --git a/src/geocoders/here.ts b/src/geocoders/here.ts index 4cd8ab49..04ba617f 100755 --- a/src/geocoders/here.ts +++ b/src/geocoders/here.ts @@ -13,6 +13,8 @@ export interface HereOptions extends GeocoderOptions { app_id: string; app_code: string; reverseGeocodeProxRadius: null; + reverseGeocodeUrl: string; + apiKey: string; } /** @@ -23,7 +25,9 @@ export class HERE implements IGeocoder { serviceUrl: 'https://geocoder.api.here.com/6.2/', app_id: '', app_code: '', - reverseGeocodeProxRadius: null + reverseGeocodeProxRadius: null, + apiKey: '', + reverseGeocodeUrl: '' }; constructor(options?: Partial) { @@ -82,10 +86,97 @@ export class HERE implements IGeocoder { } } +export class HEREv2 implements IGeocoder { + + options: HereOptions = { + serviceUrl: 'https://geocode.search.hereapi.com/v1/discover', + reverseGeocodeUrl: 'https://revgeocode.search.hereapi.com/v1/revgeocode', + apiKey: '', + reverseGeocodeProxRadius: null, + app_id: '', + app_code: '' + } + + constructor(options?: Partial) { + L.Util.setOptions(this, options); + } + + geocode(query: string, cb: GeocodingCallback, context?: any): void { + + const params = geocodingParams(this.options, { + q: query, + apiKey: this.options.apiKey + }); + + if (!params.at && !params.in) { + throw Error('at / in parameters not found. Please define coordinates (at=latitude,longitude) or other (in) in your geocodingQueryParams.'); + } + + this.getJSON(this.options.serviceUrl, params, cb, context); + } + + reverse(location: L.LatLngLiteral, scale: number, cb: GeocodingCallback, context?: any): void { + const _proxRadius = this.options.reverseGeocodeProxRadius + ? this.options.reverseGeocodeProxRadius + : null; + const proxRadius = _proxRadius ? ',' + encodeURIComponent(_proxRadius) : ''; + const params = reverseParams(this.options, { + at: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng), + apiKey: this.options.apiKey + }); + + if (proxRadius) { + params.limit = proxRadius; + } + + this.getJSON(this.options.reverseGeocodeUrl, params, cb, context); + } + + getJSON(url: string, params: any, cb: GeocodingCallback, context?: any) { + getJSON(url, params, data => { + const results: GeocodingResult[] = []; + + if (data.items && data.items.length) { + for (let i = 0; i <= data.items.length - 1; i++) { + let item, latLng, latLngBounds; + item = data.items[i]; + latLng = L.latLng(item.position.lat, item.position.lng); + + if (item.mapView) { + latLngBounds = L.latLngBounds( + L.latLng(item.mapView.south, item.mapView.west), + L.latLng(item.mapView.north, item.mapView.east) + ); + } else { + // Using only position when not provided + latLngBounds = L.latLngBounds( + L.latLng(item.position.lat, item.position.lng), + L.latLng(item.position.lat, item.position.lng) + ); + } + results[i] = { + name: item.address.label, + properties: item.address, + bbox: latLngBounds, + center: latLng + }; + } + } + cb.call(context, results); + }); + } +} + + /** * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link HERE} * @param options the options */ export function here(options?: Partial) { - return new HERE(options); + if (options.apiKey) { + return new HEREv2(options); + } else { + console.log('Using the api with app_code and app_id is deprecated. Check the docs to use an apiKey.') + return new HERE(options); + } }