Skip to content

Commit

Permalink
Merge pull request #535 from ibi-group/add-otp-geocoder
Browse files Browse the repository at this point in the history
Add OTP Geocoder
  • Loading branch information
miles-grant-ibigroup authored Feb 21, 2023
2 parents 39619ce + 43e8359 commit 6b5fc0f
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 18 deletions.
55 changes: 55 additions & 0 deletions __snapshots__/storybook.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,28 @@ exports[`Storyshots Geocoder Test Autocomplete 1`] = `

exports[`Storyshots Geocoder Test Autocomplete 2`] = `
<div>
<div>
<label
htmlFor="otpHost"
>
OTP Host (ending with

<pre
style={
Object {
"display": "inline",
}
}
>
/router/default
</pre>
)
</label>
<input
id="otpHost"
onChange={[Function]}
/>
</div>
<div>
<label
htmlFor="maxLat"
Expand Down Expand Up @@ -870,6 +892,17 @@ exports[`Storyshots Geocoder Test Autocomplete 2`] = `
type="checkbox"
/>
</label>
<label
htmlFor="otp"
>
OTP:
<input
checked={false}
id="otp"
onChange={[Function]}
type="checkbox"
/>
</label>
</div>
<div>
<label
Expand Down Expand Up @@ -994,6 +1027,17 @@ exports[`Storyshots Geocoder Test Reverse 2`] = `
type="checkbox"
/>
</label>
<label
htmlFor="otp"
>
OTP:
<input
checked={false}
id="otp"
onChange={[Function]}
type="checkbox"
/>
</label>
</div>
<div />
<div>
Expand Down Expand Up @@ -1170,6 +1214,17 @@ exports[`Storyshots Geocoder Test Search 2`] = `
type="checkbox"
/>
</label>
<label
htmlFor="otp"
>
OTP:
<input
checked={false}
id="otp"
onChange={[Function]}
type="checkbox"
/>
</label>
</div>
<div>
<label
Expand Down
51 changes: 51 additions & 0 deletions packages/geocoder/src/apis/otp/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

// eslint-disable-next-line prettier/prettier
import type { AutocompleteQuery } from "../../geocoders/types"

type FetchArgs = {
url: string
query: string
}

type OTPGeocoderResponse = {
results: {
lat: number,
lng: number,
description: string,
id: string
}[]
} | undefined


function run({ query, url }: FetchArgs): Promise<OTPGeocoderResponse> {
// TODO: Support corners/osm nodes?
return fetch(`${url}/geocode?corners=false&query=${query}`)
.then(res => res.text())
.then(res => JSON.parse(`{"results": ${res}}`));
}

/**
* Search for an address using
* OTP Geocoder
*
* @param {Object} $0
* @param {string} $0.url The OTP instance, ending with /default/
* @param {string} $0.text query
* @return {Promise} A Promise that'll get resolved with the autocomplete result
*/
async function autocomplete({
url,
text
}: AutocompleteQuery): Promise<OTPGeocoderResponse> {
return run({
query: text,
url
})
}

function search(): Promise<unknown> { console.warn("Not implemented"); return null }
function reverse(): Promise<unknown> { console.warn("Not implemented"); return null }


export { autocomplete, reverse, search };
export type { OTPGeocoderResponse }
37 changes: 37 additions & 0 deletions packages/geocoder/src/geocoders/otp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Prettier does not support typescript annotation
// eslint-disable-next-line prettier/prettier
import type { AutocompleteQuery, MultiGeocoderResponse } from "./types";

import Geocoder from "./abstract-geocoder";
import { OTPGeocoderResponse } from "../apis/otp";

/**
* Allows fetching results from OTP instance with the geocoder endpoint enabled
*/
export default class OTPGeocoder extends Geocoder {
getAutocompleteQuery(query: AutocompleteQuery): AutocompleteQuery {
const {
baseUrl,
} = this.geocoderConfig;
return {
url: baseUrl,
...query
};
}


rewriteAutocompleteResponse(response: OTPGeocoderResponse): MultiGeocoderResponse {
return {
features: response?.results?.map(stop => ({
geometry: { type: "Point", coordinates: [stop.lng, stop.lat] },
id: stop.id,
// TODO: if non-stops are supported, these need to be detected here and
// this layer property updated accordingly
properties: { layer: "stops", source: "otp", name: stop.description, label: stop.description },
type: "Feature"
})),
type: "FeatureCollection"
};
}

}
33 changes: 32 additions & 1 deletion packages/geocoder/src/index.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const GeocoderTester = ({
const [enableGeocodeEarth, setEnableGeocodeEarth] = useState(true);
const [enableHere, setEnableHere] = useState(true);
const [enablePhoton, setEnablePhoton] = useState(true);
const [enableOtp, setEnableOtp] = useState(false);
const [otpHost, setOtpHost] = useState("");
const [
reverseUseFeatureCollection,
setReverseUseFeatureCollection
Expand Down Expand Up @@ -57,6 +59,12 @@ const GeocoderTester = ({
type: "PHOTON"
});

const otpGeocoder = getGeocoder({
baseUrl: otpHost,
size: 1,
type: "OTP"
});

const searchObj: AnyGeocoderQuery = {
text: searchTerm
};
Expand All @@ -77,15 +85,29 @@ const GeocoderTester = ({
const photonRes = enablePhoton
? await photonGeocoder[endpoint](searchObj)
: null;
const otpRes = enableOtp ? await otpGeocoder[endpoint](searchObj) : null;
onResults({
hereRes,
peliasRes,
photonRes
photonRes,
otpRes
});
};

return (
<div>
{endpoint === "autocomplete" && (
<div>
<label htmlFor="otpHost">
OTP Host (ending with{" "}
<pre style={{ display: "inline" }}>/router/default</pre>)
</label>
<input
id="otpHost"
onChange={e => setOtpHost(e.target.value)}
></input>
</div>
)}
{/* Boundary Input */}
{endpoint !== "reverse" && (
<div>
Expand Down Expand Up @@ -219,6 +241,15 @@ const GeocoderTester = ({
type="checkbox"
/>
</label>
<label htmlFor="otp">
OTP:
<input
checked={enableOtp}
id="otp"
onChange={e => setEnableOtp(e.target.checked)}
type="checkbox"
/>
</label>
</div>
<div>
{endpoint !== "reverse" && (
Expand Down
4 changes: 4 additions & 0 deletions packages/geocoder/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import * as pelias from "isomorphic-mapzen-search";
import memoize from "lodash.memoize";
import * as here from "./apis/here";
import * as photon from "./apis/photon";
import * as otp from "./apis/otp";

import ArcGISGeocoder from "./geocoders/arcgis";
import NoApiGeocoder from "./geocoders/noapi";
import PeliasGeocoder from "./geocoders/pelias";
import HereGeocoder from "./geocoders/here";
import PhotonGeocoder from "./geocoders/photon";
import OTPGeocoder from "./geocoders/otp";

// Prettier does not support typescript annotation
// eslint-disable-next-line prettier/prettier
Expand All @@ -29,6 +31,8 @@ const getGeocoder = memoize((geocoderConfig: GeocoderConfig & { type: string })
return new HereGeocoder(here, geocoderConfig);
case "PHOTON":
return new PhotonGeocoder(photon, geocoderConfig);
case "OTP":
return new OTPGeocoder(otp, geocoderConfig);
default:
console.error(`Unknown geocoder type: "${type}". Using NoApiGeocoder.`);
return new NoApiGeocoder();
Expand Down
17 changes: 0 additions & 17 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2845,23 +2845,6 @@
resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca"
integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==

"@opentripplanner/core-utils@^8.1.1":
version "8.1.1"
resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-8.1.1.tgz#434487a09605fd3c241d36993c63e0c2c965e6da"
integrity sha512-xQhc6uhdcGZR5HKfQclA4d2YDkUtBcCz+LnFGpXRSlkyJtXHkVs+Z+CsTK/GfNlnhmEoUcyrKN6yGA8xG0/1IA==
dependencies:
"@mapbox/polyline" "^1.1.0"
"@opentripplanner/geocoder" "^1.3.4"
"@styled-icons/foundation" "^10.34.0"
"@turf/along" "^6.0.1"
bowser "^2.7.0"
chroma-js "^2.4.2"
date-fns "^2.28.0"
date-fns-tz "^1.2.2"
lodash.clonedeep "^4.5.0"
lodash.isequal "^4.5.0"
qs "^6.9.1"

"@pmmmwh/react-refresh-webpack-plugin@^0.5.1":
version "0.5.4"
resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz#df0d0d855fc527db48aac93c218a0bf4ada41f99"
Expand Down

0 comments on commit 6b5fc0f

Please sign in to comment.