safe-cycling-map/src/map.tsx

154 wiersze
4.4 KiB
TypeScript
Czysty Zwykły widok Historia

2023-01-11 10:30:59 +00:00
import React, { useEffect, useState } from "react";
import mapboxgl from "mapbox-gl";
2023-01-05 02:09:44 +00:00
import "./App.css";
2023-01-05 06:06:46 +00:00
import { mapOnLoad } from "./layers";
2023-01-17 02:21:47 +00:00
// @ts-ignore
2023-01-17 02:21:47 +00:00
import MapboxDirections from "@mapbox/mapbox-gl-directions/dist/mapbox-gl-directions";
import "@mapbox/mapbox-gl-directions/dist/mapbox-gl-directions.css";
2023-01-05 02:09:44 +00:00
2023-01-17 02:26:46 +00:00
import MapboxGeocoder from "@mapbox/mapbox-gl-geocoder";
import "@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css";
import { debouncedFetchAndDrawMarkers } from "./api";
import { LoadingStatusType } from "./interfaces";
2023-01-17 02:26:46 +00:00
const MAPBOX_TOKEN =
"pk.eyJ1IjoiamFrZWMiLCJhIjoiY2tkaHplNGhjMDAyMDJybW4ybmRqbTBmMyJ9.AR_fnEuka8-cFb4Snp3upw";
2023-01-28 02:48:20 +00:00
const min_overpass_turbo_zoom = 15;
/** Also the min zoom of the vector tileserver */
// const max_overpass_turbo_zoom = 15;
mapboxgl.accessToken = MAPBOX_TOKEN;
2023-01-05 02:09:44 +00:00
export function Map() {
const mapContainer = React.useRef<HTMLDivElement>(null);
const mapRef = React.useRef<mapboxgl.Map | null>(null);
const markers = React.useRef<mapboxgl.Marker[]>([]);
const [loadingStatus, setLoadingStatus] =
2023-01-28 02:48:20 +00:00
useState<LoadingStatusType>("ready_to_load");
2023-01-05 06:06:46 +00:00
2023-01-15 11:32:49 +00:00
const [lng, setLng] = useState(151.2160755932166);
const [lat, setLat] = useState(-33.88056647217827);
const [zoom, setZoom] = useState(17.504322191852786);
2023-01-05 02:09:44 +00:00
useEffect(() => {
// This is called on every pan
if (mapContainer.current === null) {
return;
}
if (mapRef.current !== null) {
return;
}
mapRef.current = new mapboxgl.Map({
2023-01-05 02:09:44 +00:00
container: mapContainer.current,
center: [lng, lat],
zoom: zoom,
hash: true,
2023-01-28 02:48:20 +00:00
style: "mapbox://styles/mapbox/dark-v11",
2023-01-05 02:09:44 +00:00
});
2023-01-05 06:06:46 +00:00
const map = mapRef.current;
map.on("load", mapOnLoad(map));
2023-01-05 02:09:44 +00:00
map.addControl(new mapboxgl.NavigationControl());
map.addControl(new mapboxgl.FullscreenControl());
2023-01-17 02:26:46 +00:00
map.addControl(
new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl,
}),
"top-left"
);
2023-01-28 03:10:37 +00:00
// map.addControl(
// new MapboxDirections({
// accessToken: mapboxgl.accessToken,
// }),
// "top-left"
// );
2023-01-05 02:09:44 +00:00
map.addControl(
new mapboxgl.GeolocateControl({
2023-01-05 02:09:44 +00:00
positionOptions: {
enableHighAccuracy: true,
},
trackUserLocation: true,
})
);
map.on("move", () => {
if (!map) {
return; // wait for map to initialize
}
2023-01-05 06:06:46 +00:00
const { lng, lat } = map.getCenter();
const zoom = map.getZoom();
2023-01-28 02:48:20 +00:00
if (zoom < min_overpass_turbo_zoom) {
setLoadingStatus("too_zoomed_out");
} else {
2023-01-28 03:10:37 +00:00
setLoadingStatus("ready_to_load");
2023-01-28 02:48:20 +00:00
}
2023-01-05 06:06:46 +00:00
console.log(lng, lat, zoom);
2023-01-05 02:09:44 +00:00
setLng(map.getCenter().lng);
setLat(map.getCenter().lat);
setZoom(map.getZoom());
});
2023-01-28 03:18:07 +00:00
if (map.getZoom() < min_overpass_turbo_zoom) {
2023-01-28 02:48:20 +00:00
setLoadingStatus("too_zoomed_out");
} else {
2023-01-28 03:18:07 +00:00
console.log(`zoom is ${map.getZoom()}`);
2023-01-28 02:48:20 +00:00
debouncedFetchAndDrawMarkers(map, markers, setLoadingStatus);
}
map.on("moveend", async () => {
if (map === null) {
return;
}
2023-01-28 02:48:20 +00:00
const zoom = map.getZoom();
if (zoom > min_overpass_turbo_zoom) {
2023-01-28 03:37:33 +00:00
console.log(`zoom is ${zoom}`);
2023-01-28 02:48:20 +00:00
debouncedFetchAndDrawMarkers(map, markers, setLoadingStatus);
}
});
2023-01-05 02:09:44 +00:00
});
const statusMessages = {
loading: "Loading safety ratings...",
success: "Done loading safety ratings",
ready_to_load: "About to load ratings...",
too_zoomed_out: "Zoom in to see street safety ratings",
2023-01-28 02:48:20 +00:00
unknownerror: "Error loading. Please wait a bit",
"429error": "Too many requests, please try in a bit",
};
const statusText = statusMessages[loadingStatus];
2023-01-05 02:09:44 +00:00
return (
<div>
<div className="sidebar">
<label>
2023-01-28 03:37:33 +00:00
<span color="red">Warning:</span> Data is open source and not guaranteed to be
accurate.
2023-01-28 03:10:37 +00:00
<br></br>
<a
target="_blank"
rel="noopener noreferrer"
2023-01-28 03:39:09 +00:00
href="https://github.com/jakecoppinger/safe-cycling-map/blob/main/docs/key.md"
2023-01-28 03:10:37 +00:00
>
View map key and how safety is calculated
</a>
2023-01-28 03:37:33 +00:00
<br></br>
2023-01-05 02:09:44 +00:00
<a
target="_blank"
rel="noopener noreferrer"
href="https://github.com/jakecoppinger/safe-cycling-map"
>
2023-01-28 03:37:33 +00:00
About this map
2023-01-05 02:09:44 +00:00
</a>
2023-01-28 03:37:33 +00:00
<br></br>
{statusText}
2023-01-05 02:09:44 +00:00
</label>
</div>
<div ref={mapContainer} className="map-container" />
</div>
);
}