diff --git a/config.env.example b/config.env.example
index 89108b5e..f5731974 100644
--- a/config.env.example
+++ b/config.env.example
@@ -24,10 +24,6 @@
# Get an API key on https://www.mapbox.com/signup/
#MAPBOX_TOKEN=
-# MapZen is used for getting elevation information
-# Get an API key on https://mapzen.com/developers/sign_up
-#MAPZEN_TOKEN=
-
# Maxmind configuration. If specified, the maxmind GeoLite2 database will be downloaded
# for Geo IP lookup (to show the initial map state) and kept in memory.
# Sign up here: https://www.maxmind.com/en/geolite2/signup
diff --git a/docs/src/developers/server/config.md b/docs/src/developers/server/config.md
index 0b21b746..60329cc3 100644
--- a/docs/src/developers/server/config.md
+++ b/docs/src/developers/server/config.md
@@ -18,17 +18,17 @@ The config of the FacilMap server can be set either by using environment variabl
| `DB_PASSWORD` | | `facilmap` | The password to connect to the database with. |
| `ORS_TOKEN` | * | | [OpenRouteService API key](https://openrouteservice.org/). |
| `MAPBOX_TOKEN` | * | | [Mapbox API key](https://www.mapbox.com/signup/). |
-| `MAPZEN_TOKEN` | | | [Mapzen API key](https://mapzen.com/developers/sign_up). |
| `MAXMIND_USER_ID` | | | [MaxMind user ID](https://www.maxmind.com/en/geolite2/signup). |
| `MAXMIND_LICENSE_KEY` | | | MaxMind license key. |
| `LIMA_LABS_TOKEN` | | | [Lima Labs](https://maps.lima-labs.com/) API key |
| `HIDE_COMMERCIAL_MAP_LINKS` | | | Set to `1` to hide the links to Google/Bing Maps in the “Map style” menu. |
-| `CUSTOM_CSS_FILE` | | | The path of a CSS file that should be included ([see more details below](#custom-css-file)).
+| `CUSTOM_CSS_FILE` | | | The path of a CSS file that should be included ([see more details below](#custom-css-file)). |
+| `NOMINATIM_URL` | | `https://nominatim.openstreetmap.org` | The URL to the Nominatim server (used to search for places). |
+| `OPEN_ELEVATION_URL` | | `https://api.open-elevation.com` | The URL to the Open Elevation server (used to look up the elevation for markers). |
FacilMap makes use of several third-party services that require you to register (for free) and generate an API key:
* Mapbox and OpenRouteService are used for calculating routes. Mapbox is used for basic routes, OpenRouteService is used when custom route mode settings are made. If these API keys are not defined, calculating routes will fail.
* Maxmind provides a free database that maps IP addresses to approximate locations. FacilMap downloads this database to decide the initial map view for users (IP addresses are looked up in FacilMap’s copy of the database, on IP addresses are sent to Maxmind). This API key is optional, if it is not set, the default view will be the whole world.
-* Mapzen is used to look up the elevation info for search results. The API key is optional, if it is not set, no elevation info will be available for search results.
* Lima Labs is used for nicer and higher resolution map tiles than Mapnik. The API key is optional, if it is not set, Mapnik will be the default map style instead.
## Custom CSS file
diff --git a/docs/src/developers/server/docker.md b/docs/src/developers/server/docker.md
index 5ce6f79a..12868ca6 100644
--- a/docs/src/developers/server/docker.md
+++ b/docs/src/developers/server/docker.md
@@ -34,7 +34,6 @@ services:
DB_PASSWORD: password
ORS_TOKEN: # Get an API key on https://go.openrouteservice.org/ (needed for routing)
MAPBOX_TOKEN: # Get an API key on https://www.mapbox.com/signup/ (needed for routing)
- MAPZEN_TOKEN: # Get an API key on https://mapzen.com/developers/sign_up (needed for elevation info)
MAXMIND_USER_ID: # Sign up here https://www.maxmind.com/en/geolite2/signup (needed for geoip lookup to show initial map state)
MAXMIND_LICENSE_KEY:
LIMA_LABS_TOKEN: # Get an API key on https://maps.lima-labs.com/ (optional, needed for double-resolution tiles)
@@ -76,7 +75,6 @@ services:
DB_PASSWORD: password
ORS_TOKEN: # Get an API key on https://go.openrouteservice.org/ (needed for routing)
MAPBOX_TOKEN: # Get an API key on https://www.mapbox.com/signup/ (needed for routing)
- MAPZEN_TOKEN: # Get an API key on https://mapzen.com/developers/sign_up (needed for elevation info)
MAXMIND_USER_ID: # Sign up here https://www.maxmind.com/en/geolite2/signup (needed for geoip lookup to show initial map state)
MAXMIND_LICENSE_KEY:
LIMA_LABS_TOKEN: # Get an API key on https://maps.lima-labs.com/ (optional, needed for double-resolution tiles)
@@ -100,5 +98,5 @@ To manually create the necessary docker containers, use these commands:
```bash
docker create --name=facilmap_db -e MYSQL_DATABASE=facilmap -e MYSQL_USER=facilmap -e MYSQL_PASSWORD=password -e MYSQL_RANDOM_ROOT_PASSWORD=true --restart=unless-stopped mariadb --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
-docker create --link=facilmap_db -p 8080 --name=facilmap -e "USER_AGENT=My FacilMap (https://facilmap.example.org/, facilmap@example.org)" -e TRUST_PROXY=true -e DB_TYPE=mysql -e DB_HOST=facilmap_db -e DB_NAME=facilmap -e DB_USER=facilmap -e DB_PASSWORD=facilmap -e ORS_TOKEN= -e MAPBOX_TOKEN= -e MAPZEN_TOKEN= -e MAXMIND_USER_ID= -e MAXMIND_LICENSE_KEY= -e LIMA_LABS_TOKEN= --restart=unless-stopped facilmap/facilmap
+docker create --link=facilmap_db -p 8080 --name=facilmap -e "USER_AGENT=My FacilMap (https://facilmap.example.org/, facilmap@example.org)" -e TRUST_PROXY=true -e DB_TYPE=mysql -e DB_HOST=facilmap_db -e DB_NAME=facilmap -e DB_USER=facilmap -e DB_PASSWORD=facilmap -e ORS_TOKEN= -e MAPBOX_TOKEN= -e MAXMIND_USER_ID= -e MAXMIND_LICENSE_KEY= -e LIMA_LABS_TOKEN= --restart=unless-stopped facilmap/facilmap
```
\ No newline at end of file
diff --git a/frontend/src/lib/components/marker-info/marker-info.vue b/frontend/src/lib/components/marker-info/marker-info.vue
index 69264fd7..1d4248e6 100644
--- a/frontend/src/lib/components/marker-info/marker-info.vue
+++ b/frontend/src/lib/components/marker-info/marker-info.vue
@@ -93,7 +93,7 @@
Elevation
- {{marker.ele}}^m
+ {{marker.ele}} m
diff --git a/server/src/config.ts b/server/src/config.ts
index 43d68db7..f06ad89d 100644
--- a/server/src/config.ts
+++ b/server/src/config.ts
@@ -20,13 +20,14 @@ export interface Config {
db: DbConfig;
orsToken?: string;
mapboxToken?: string;
- mapzenToken?: string;
maxmindUserId?: string;
maxmindLicenseKey?: string;
limaLabsToken?: string;
/** Hide the "Open this on Google/Bing Maps" links in the map style menu */
hideCommercialMapLinks?: boolean;
customCssFile?: string;
+ nominatimUrl: string;
+ openElevationApiUrl: string;
}
const config: Config = {
@@ -51,7 +52,6 @@ const config: Config = {
},
orsToken: process.env.ORS_TOKEN || "", // Get a token on https://go.openrouteservice.org/
mapboxToken: process.env.MAPBOX_TOKEN || "", // Get an API key on https://www.mapbox.com/signup/
- mapzenToken: process.env.MAPZEN_TOKEN || "", // Get an API key on https://mapzen.com/developers/sign_up
// Maxmind configuration. If specified, the maxmind GeoLite2 database will be downloaded for Geo IP lookup (to show the initial map state) and kept it in memory
// Sign up here: https://www.maxmind.com/en/geolite2/signup
@@ -63,6 +63,9 @@ const config: Config = {
hideCommercialMapLinks: process.env.HIDE_COMMERCIAL_MAP_LINKS === "1",
customCssFile: process.env.CUSTOM_CSS_FILE || undefined,
+
+ nominatimUrl: process.env.NOMINATIM_URL || "https://nominatim.openstreetmap.org",
+ openElevationApiUrl: process.env.OPEN_ELEVATION_URL || "https://api.open-elevation.com",
};
export default config;
diff --git a/server/src/database/line.ts b/server/src/database/line.ts
index b3c61ec5..cdd91ca5 100644
--- a/server/src/database/line.ts
+++ b/server/src/database/line.ts
@@ -274,7 +274,6 @@ export default class DatabaseLines {
}
async _setLinePoints(padId: PadId, lineId: ID, trackPoints: Point[], _noEvent?: boolean): Promise {
- // First get elevation, so that if that fails, we don't update anything
await this.LinePointModel.destroy({ where: { lineId: lineId } });
const create = [ ];
diff --git a/server/src/database/meta.ts b/server/src/database/meta.ts
index 82671213..f02cea4d 100644
--- a/server/src/database/meta.ts
+++ b/server/src/database/meta.ts
@@ -9,7 +9,7 @@ interface MetaModel extends Model, InferCreationAttri
export interface MetaProperties {
dropdownKeysMigrated: "1";
- hasElevation: "1";
+ hasElevation: "1" | "2";
hasLegendOption: "1";
hasBboxes: "1";
untitledMigrationCompleted: "1";
diff --git a/server/src/elevation.ts b/server/src/elevation.ts
index 03014abc..60c11c5a 100644
--- a/server/src/elevation.ts
+++ b/server/src/elevation.ts
@@ -1,48 +1,44 @@
import type { Point } from "facilmap-types";
+import config from "./config";
-// const API_URL = "https://elevation.mapzen.com/height";
-// const LIMIT = 500;
-// const MIN_TIME_BETWEEN_REQUESTS = 600;
-
-// const throttle = highland<() => void>();
-// throttle.ratelimit(1, MIN_TIME_BETWEEN_REQUESTS).each((func) => {
-// func();
-// });
-
-export async function _getThrottledSlot(): Promise {
- // return new Promise((resolve) => {
- // throttle.write(resolve);
- // });
-}
-
-export async function getElevationForPoint(point: Point): Promise {
- const points = await getElevationForPoints([point]);
+export async function getElevationForPoint(point: Point, failOnError = false): Promise {
+ const points = await getElevationForPoints([point], failOnError);
return points[0];
}
-export async function getElevationForPoints(points: Array<{ lat: string | number; lon: string | number }>): Promise> {
- return points.map(() => undefined);
-
- /*if(points.length == 0)
- return Promise.resolve([ ]);
-
- let ret = Promise.resolve([ ]);
- for(let i=0; i {
- return elevation._getThrottledSlot().then(() => (heights));
- }).then((heights) => {
- let json = {
- encoded_polyline: polyline.encode(points.slice(i, i+LIMIT).map((point) => ([point.lat, point.lon])), 6),
- range: false
- };
-
- return request.get({
- url: `${API_URL}?json=${encodeURI(JSON.stringify(json))}&api_key=${config.mapzenToken}`,
- json: true
- }).then((res) => (heights.concat(res.height)));
- });
+export async function getElevationForPoints(points: Point[], failOnError = false): Promise> {
+ if(points.length == 0) {
+ return [];
+ }
+
+ try {
+ const res = await fetch(`${config.openElevationApiUrl}/api/v1/lookup`, {
+ method: "post",
+ headers: {
+ "Content-type": "application/json"
+ },
+ body: JSON.stringify({
+ locations: points.map((point) => ({ latitude: point.lat, longitude: point.lon }))
+ })
+ });
+ if (!res.ok) {
+ throw new Error(`Looking up elevations failed with status ${res.status}.`);
+ }
+ const json: { results: Array<{ latitude: number; longitude: number; elevation: number }> } = await res.json();
+
+ return json.results.map((result: any) => {
+ if (result.elevation !== 0) {
+ return result.elevation;
+ }
+ });
+ } catch (err: any) {
+ if (failOnError) {
+ throw err;
+ } else {
+ console.warn("Error lookup up elevation", err);
+ return points.map(() => undefined);
+ }
}
- return ret;*/
}
interface AscentDescent {
diff --git a/server/src/search.ts b/server/src/search.ts
index d8059b16..3782a2b1 100644
--- a/server/src/search.ts
+++ b/server/src/search.ts
@@ -37,7 +37,6 @@ interface NominatimError {
error: { code?: number; message: string } | string;
}
-const nameFinderUrl = "https://nominatim.openstreetmap.org";
const limit = 25;
const stateAbbr: Record> = {
"us" : {
@@ -115,7 +114,7 @@ export async function find(query: string, loadUrls = false, loadElevation = fals
async function _findQuery(query: string, loadElevation = false): Promise> {
const body: Array | NominatimError = await throttledFetch(
- nameFinderUrl + "/search?format=jsonv2&polygon_geojson=1&addressdetails=1&namedetails=1&limit=" + encodeURIComponent(limit) + "&extratags=1&q=" + encodeURIComponent(query),
+ config.nominatimUrl + "/search?format=jsonv2&polygon_geojson=1&addressdetails=1&namedetails=1&limit=" + encodeURIComponent(limit) + "&extratags=1&q=" + encodeURIComponent(query),
{
headers: {
"User-Agent": config.userAgent
@@ -131,7 +130,7 @@ async function _findQuery(query: string, loadElevation = false): Promise (res.lon && res.lat));
if(loadElevation && points.length > 0) {
- const elevations = await getElevationForPoints(points);
+ const elevations = await getElevationForPoints(points.map((point) => ({ lat: Number(point.lat), lon: Number(point.lon) })));
elevations.forEach((elevation, i) => {
points[i].elevation = elevation;
});
@@ -142,7 +141,7 @@ async function _findQuery(query: string, loadElevation = false): Promise> {
const body: Array | NominatimError = await throttledFetch(
- `${nameFinderUrl}/lookup?format=jsonv2&addressdetails=1&polygon_geojson=1&extratags=1&namedetails=1&osm_ids=${encodeURI(type.toUpperCase())}${encodeURI(id)}`,
+ `${config.nominatimUrl}/lookup?format=jsonv2&addressdetails=1&polygon_geojson=1&extratags=1&namedetails=1&osm_ids=${encodeURI(type.toUpperCase())}${encodeURI(id)}`,
{
headers: {
"User-Agent": config.userAgent
@@ -158,7 +157,7 @@ async function _findOsmObject(type: string, id: string, loadElevation = false):
const points = body.filter((res) => (res.lon && res.lat));
if(loadElevation && points.length > 0) {
- const elevations = await getElevationForPoints(points);
+ const elevations = await getElevationForPoints(points.map((point) => ({ lat: Number(point.lat), lon: Number(point.lon) })));
elevations.forEach((elevation, i) => {
points[i].elevation = elevation;
});
@@ -170,7 +169,7 @@ async function _findOsmObject(type: string, id: string, loadElevation = false):
async function _findLonLat(lonlatWithZoom: PointWithZoom, loadElevation = false): Promise> {
const [body, elevation] = await Promise.all([
throttledFetch(
- `${nameFinderUrl}/reverse?format=jsonv2&addressdetails=1&polygon_geojson=0&extratags=1&namedetails=1&lat=${encodeURIComponent(lonlatWithZoom.lat)}&lon=${encodeURIComponent(lonlatWithZoom.lon)}&zoom=${encodeURIComponent(lonlatWithZoom.zoom != null ? (lonlatWithZoom.zoom >= 12 ? lonlatWithZoom.zoom+2 : lonlatWithZoom.zoom) : 17)}`,
+ `${config.nominatimUrl}/reverse?format=jsonv2&addressdetails=1&polygon_geojson=0&extratags=1&namedetails=1&lat=${encodeURIComponent(lonlatWithZoom.lat)}&lon=${encodeURIComponent(lonlatWithZoom.lon)}&zoom=${encodeURIComponent(lonlatWithZoom.zoom != null ? (lonlatWithZoom.zoom >= 12 ? lonlatWithZoom.zoom+2 : lonlatWithZoom.zoom) : 17)}`,
{
headers: {
"User-Agent": config.userAgent
diff --git a/types/src/marker.ts b/types/src/marker.ts
index 0d532ef8..6d445c58 100644
--- a/types/src/marker.ts
+++ b/types/src/marker.ts
@@ -13,6 +13,6 @@ export const markerValidator = cruValidator({
colour: optionalCreate(colourValidator), // defaults to type.defaultColour
size: optionalCreate(sizeValidator), // defaults to type.defaultSize
data: optionalCreate(z.record(z.string())),
- ele: optionalCreate(z.number().or(z.null()), null)
+ ele: optionalCreate(z.number().or(z.null()))
});
export type Marker = CRUType;