safe-cycling-map/src/api.ts

156 wiersze
4.1 KiB
TypeScript

import debounce from "debounce";
import { OverpassResponse, RawOverpassNode } from "./interfaces";
import * as http from "https";
import { drawMarkersAndCards, removeMarkers } from "./drawing";
import { wayToNode } from "./geo-utils";
import { bicycleParking, safeCycleways } from "./overpass-requests";
import osmtogeojson from 'osmtogeojson';
/**
* Make request to Overpass Turbo.
* @param overpassQuery Overpass turbo query string
* @returns
*/
export async function getOSMData(overpassQuery: string): Promise<OverpassResponse> {
const options = {
hostname: "overpass-api.de",
port: 443,
path: "/api/interpreter",
method: "POST",
headers: {
// "Content-Type": "application/json",
'Content-Type': 'application/x-www-form-urlencoded'
},
};
return new Promise((resolve, reject) => {
var req = http.request(options, function (res) {
var body = "";
res.setEncoding("utf8");
res.on("data", (chunk) => (body += chunk));
res.on("end", function () {
if (res.statusCode !== 200) {
console.log("error code", res.statusCode);
reject(res.statusCode);
}
const jsonResponse = JSON.parse(body);
resolve(jsonResponse);
});
});
req.on("error", function (e) {
reject(e.message);
});
req.write(new URLSearchParams({
'data': overpassQuery,
}).toString());
req.end();
});
}
export const debouncedFetchAndDrawMarkers = debounce(fetchAndDrawMarkers, 2000);
async function fetchAndDrawMarkers(
map: mapboxgl.Map,
markers: React.MutableRefObject<mapboxgl.Marker[]>,
setLoadingStatus: React.Dispatch<React.SetStateAction<LoadingStatusType>>
) {
setLoadingStatus("loading");
const bounds = map.getBounds();
const southernLat = bounds.getSouth();
const westLong = bounds.getWest();
const northLat = bounds.getNorth();
const eastLong = bounds.getEast();
let ads: OverpassResponse;
let safeRoutes: OverpassResponse;
const overpassBounds = [southernLat, westLong, northLat, eastLong];
const boundsStr = overpassBounds.join(",");
const parkingOverpassQuery = bicycleParking(boundsStr);;
const safeRoutesOverpassQuery = safeCycleways(boundsStr);;
console.log("Started POST request...");
try {
ads = (await getOSMData(parkingOverpassQuery));
safeRoutes = await getOSMData(safeRoutesOverpassQuery);
} catch (e) {
console.log("Error:", e);
setLoadingStatus("unknownerror");
return;
}
const geoJson = osmtogeojson(safeRoutes, {})
console.log(geoJson);
console.log("Adding geojson to map...");
// try {
// map.removeSource('greenRoads');
// } catch (e) {
// }
map.addSource('redRoads', {
type: 'geojson',
data: {
features: geoJson.features.filter(feature => feature.properties &&
feature.properties.maxspeed > 40),
type: "FeatureCollection"
}
});
map.addSource('greenRoads', {
type: 'geojson',
data: {
features: geoJson.features.filter(feature => feature.properties &&
(feature.properties.highway === 'cycleway' || feature.properties.highway === 'pedestrian'))
,
type: "FeatureCollection"
}
});
// Add a new layer to visualize the polygon.
map.addLayer({
'id': 'redRoadsId',
'type': 'line',
'source': 'redRoads', // reference the data source
'layout': {},
'paint': {
"line-color": "red",
"line-width": 5
},
});
// Add a new layer to visualize the polygon.
map.addLayer({
'id': 'greenRoadsId',
'type': 'line',
'source': 'greenRoads', // reference the data source
'layout': {},
'paint': {
"line-color": "green",
"line-width": 5
},
});
return;
removeMarkers(markers.current);
const nodesAndWayCenters: RawOverpassNode[] = ads.elements
.map((item) => (item.type === "way" ? wayToNode(item, ads.elements) : item))
.filter((item) => item !== null)
.map((item) => item as RawOverpassNode)
.filter((item) => item.tags !== undefined);
markers.current = await drawMarkersAndCards(map, nodesAndWayCenters);
setLoadingStatus("success");
}
type LoadingStatusType = "loading" | "success" | "429error" | "unknownerror";