kopia lustrzana https://github.com/jakecoppinger/safe-cycling-map
Improve layering, update screenshot
rodzic
5769ebfb2a
commit
012c211654
|
@ -1,10 +1,10 @@
|
|||
Safe Cycling Map
|
||||
================
|
||||
|
||||
Work in progress! PRs and forks very welcome :)
|
||||
Work in progress! PRs and forks very welcome :)
|
||||
|
||||
|
||||
![Screenshot of map](img/safe-cycling-map-2022-01-05.jpg)
|
||||
![Screenshot of map](img/safe-cycling-map-2022-01-05-v2.jpg)
|
||||
|
||||
A map of bike infrastructure using [osm2streets](https://github.com/a-b-street/osm2streets) output.
|
||||
|
||||
|
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 348 KiB |
|
@ -63,7 +63,7 @@ h1 {
|
|||
z-index: 10;
|
||||
bottom: 0px;
|
||||
left: 10px;
|
||||
color: #19ff15bf;
|
||||
color: #039f00bf;
|
||||
font-size: calc(2vw + 2vh + 10px);
|
||||
line-height: 0.8;
|
||||
}
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
import mapboxgl from "mapbox-gl";
|
||||
import * as http from "https";
|
||||
|
||||
// southern-most latitude, western-most longitude, northern-most latitude, eastern-most longitude.
|
||||
export async function getOSMData(bounds: number[]): Promise<any> {
|
||||
const options = {
|
||||
hostname: "overpass-api.de",
|
||||
port: 443,
|
||||
path: "/api/interpreter",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
console.log("Started POST request...");
|
||||
const boundsStr = bounds.join(",");
|
||||
const request_str = `
|
||||
[out:json][timeout:25];
|
||||
(
|
||||
// query part for: “bicycle_parking=*”
|
||||
node["bicycle_parking"](${boundsStr});
|
||||
way["bicycle_parking"](${boundsStr});
|
||||
relation["bicycle_parking"](${boundsStr});
|
||||
// query part for: “amenity=bicycle_parking”
|
||||
node["amenity"="bicycle_parking"](${boundsStr});
|
||||
way["amenity"="bicycle_parking"](${boundsStr});
|
||||
relation["amenity"="bicycle_parking"](${boundsStr});
|
||||
);
|
||||
out body;
|
||||
>;
|
||||
out skel qt;
|
||||
`;
|
||||
console.log("request:", request_str);
|
||||
|
||||
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);
|
||||
const bars = jsonResponse.elements;
|
||||
resolve(bars);
|
||||
});
|
||||
});
|
||||
req.on("error", function (e) {
|
||||
reject(e.message);
|
||||
});
|
||||
req.write(request_str);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
export function drawmap(map: mapboxgl.Map): void {
|
||||
map.addControl(new mapboxgl.NavigationControl());
|
||||
map.addControl(new mapboxgl.FullscreenControl());
|
||||
// Add geolocate control to the map.
|
||||
map.addControl(
|
||||
new mapboxgl.GeolocateControl({
|
||||
positionOptions: {
|
||||
enableHighAccuracy: true,
|
||||
},
|
||||
trackUserLocation: true,
|
||||
})
|
||||
);
|
||||
|
||||
map.on("moveend", function (originalEvent) {
|
||||
const { lat, lng } = map.getCenter();
|
||||
console.log("A moveend event occurred.");
|
||||
console.log({ lat, lng });
|
||||
|
||||
// eg https://localhost:3000
|
||||
const location = window.location.origin;
|
||||
console.log({ location });
|
||||
});
|
||||
}
|
||||
export function removeMarkers(markers: mapboxgl.Marker[]): void {
|
||||
markers.map((marker) => marker.remove());
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
function addLayer(
|
||||
map: mapboxgl.Map,
|
||||
type:
|
||||
| "Driving"
|
||||
| "Parking"
|
||||
| "Sidewalk"
|
||||
| "Shoulder"
|
||||
| "Biking"
|
||||
| "Bus"
|
||||
| "SharedLeftTurn"
|
||||
| "Construction"
|
||||
| "LightRail"
|
||||
| "Footway"
|
||||
| "SharedUse",
|
||||
paint: mapboxgl.FillPaint | undefined
|
||||
): void {
|
||||
map.addLayer({
|
||||
id: type,
|
||||
type: "fill",
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "lanePolygons",
|
||||
paint,
|
||||
filter: ["==", "type", type],
|
||||
// filter: ["==", "$type", "Polygon"],
|
||||
}, 'road-label');
|
||||
}
|
||||
|
||||
const colours = {
|
||||
laneMarking: "white",
|
||||
intersection: "#666666",
|
||||
|
||||
// Derived from
|
||||
// https://github.com/a-b-street/osm2streets/blob/5b40c7af877d4314ca7e45c5ac35ec472845c6ca/street-explorer/www/js/layers.js#L55
|
||||
Driving: "grey",
|
||||
// Driving: "black",
|
||||
Parking: "#333333",
|
||||
Sidewalk: "#CCCCCC",
|
||||
Shoulder: "#CCCCCC",
|
||||
Biking: "#0F7D4B",
|
||||
Bus: "#BE4A4C",
|
||||
SharedLeftTurn: "black",
|
||||
Construction: "#FF6D00",
|
||||
LightRail: "#844204",
|
||||
"Buffer(Planters)": "#555555",
|
||||
|
||||
Footway: "#DDDDE8",
|
||||
SharedUse: "#E5E1BB",
|
||||
};
|
||||
|
||||
export const mapOnLoad = (map: mapboxgl.Map) => () => {
|
||||
const layers = map.getStyle().layers;
|
||||
// Find the index of the first symbol layer in the map style.
|
||||
let firstSymbolId;
|
||||
for (const layer of layers) {
|
||||
if (layer.type === "symbol") {
|
||||
firstSymbolId = layer.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
console.log({ firstSymbolId });
|
||||
|
||||
console.log(
|
||||
"Adding sources. If you don't seen anything check vector server logs."
|
||||
);
|
||||
|
||||
// https://docs.mapbox.com/mapbox-gl-js/example/multiple-geometries/
|
||||
// Add a new vector tile source with ID 'mapillary'.
|
||||
map.addSource("osm2streets-vector-tileserver", {
|
||||
type: "vector",
|
||||
tiles: ["http://localhost:3000/tile/{z}/{x}/{y}"],
|
||||
minzoom: 15,
|
||||
maxzoom: 20,
|
||||
});
|
||||
|
||||
// addLayer(map, "LightRail", {
|
||||
// "fill-color": "yellow",
|
||||
// "fill-opacity": 0.2,
|
||||
// });
|
||||
|
||||
// map.addLayer({
|
||||
// id: "geometry",
|
||||
// type: "fill",
|
||||
|
||||
// source: "osm2streets-vector-tileserver",
|
||||
// "source-layer": "geometry",
|
||||
// paint: {
|
||||
// // To improve!
|
||||
// "fill-color": colours.Driving,
|
||||
// "fill-opacity": 0.4,
|
||||
// },
|
||||
// filter: ["==", "$type", "Polygon"],
|
||||
// });
|
||||
|
||||
// map.addLayer({
|
||||
// id: "lanePolygons",
|
||||
// type: "fill",
|
||||
|
||||
// source: "osm2streets-vector-tileserver",
|
||||
// "source-layer": "lanePolygons",
|
||||
// paint: {
|
||||
// "fill-color": colours.Driving,
|
||||
// "fill-opacity": 1,
|
||||
// },
|
||||
// filter: ["==", "$type", "Polygon"],
|
||||
// });
|
||||
|
||||
// addLayer(map, "Biking", {
|
||||
// "fill-color": colours.Biking,
|
||||
// "fill-opacity": 1,
|
||||
// });
|
||||
|
||||
|
||||
addLayer(map, "SharedUse", {
|
||||
"fill-color": "blue",
|
||||
"fill-opacity": 0.3,
|
||||
});
|
||||
addLayer(map, "Shoulder", {
|
||||
"fill-color": colours.Shoulder,
|
||||
"fill-opacity": 0.5,
|
||||
});
|
||||
addLayer(map, "Sidewalk", {
|
||||
"fill-color": colours.Sidewalk,
|
||||
"fill-opacity": 0.9,
|
||||
});
|
||||
// Currently on the wrong side of ways??
|
||||
addLayer(map, "Footway", {
|
||||
"fill-color": colours.Footway,
|
||||
"fill-opacity": 0.9,
|
||||
});
|
||||
addLayer(map, "Driving", {
|
||||
"fill-color": colours.Driving,
|
||||
"fill-opacity": 0.9,
|
||||
});
|
||||
|
||||
addLayer(map, "Bus", {
|
||||
"fill-color": colours.Bus,
|
||||
"fill-opacity": 0.9,
|
||||
});
|
||||
addLayer(map, "Construction", {
|
||||
"fill-color": colours.Construction,
|
||||
"fill-opacity": 0.5,
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: "intersection",
|
||||
type: "fill",
|
||||
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "geometry",
|
||||
paint: {
|
||||
"fill-color": colours.intersection,
|
||||
"fill-opacity": 1,
|
||||
},
|
||||
/*
|
||||
along with `type`, other attributes we could use here are:
|
||||
- control": "Signed" | "Signalled" | "Uncontrolled"
|
||||
*/
|
||||
filter: ["==", "type", "intersection"],
|
||||
}, 'road-label');
|
||||
|
||||
// // Currently on the wrong side of ways??
|
||||
// addLayer(map, "Parking", {
|
||||
// "fill-color": 'yellow',
|
||||
// "fill-opacity": 0.9,
|
||||
// });
|
||||
|
||||
map.addLayer({
|
||||
id: "Biking",
|
||||
type: "fill",
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "lanePolygons",
|
||||
paint: {
|
||||
"fill-color": colours.Biking,
|
||||
"fill-opacity": 1,
|
||||
},
|
||||
filter: ["==", "type", "Biking"],
|
||||
// filter: ["==", "type", "Biking"],
|
||||
}, 'road-label');
|
||||
|
||||
map.addLayer({
|
||||
id: "intersectionMarkings",
|
||||
type: "fill",
|
||||
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "intersectionMarkings",
|
||||
paint: {
|
||||
"fill-color": colours.Driving,
|
||||
"fill-opacity": 0.8,
|
||||
},
|
||||
filter: ["==", "$type", "Polygon"],
|
||||
}, 'road-label');
|
||||
|
||||
map.addLayer({
|
||||
id: "laneMarkings",
|
||||
type: "fill",
|
||||
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "laneMarkings",
|
||||
paint: {
|
||||
"fill-color": colours.laneMarking,
|
||||
"fill-opacity": 1,
|
||||
},
|
||||
filter: ["==", "$type", "Polygon"],
|
||||
}, 'road-label');
|
||||
};
|
108
src/map.tsx
108
src/map.tsx
|
@ -4,26 +4,20 @@ import React, { useRef, useEffect, useState } from "react";
|
|||
// import mapboxgl from "!mapbox-gl";
|
||||
import mapboxgl from "mapbox-gl";
|
||||
import "./App.css";
|
||||
import { mapOnLoad } from "./layers";
|
||||
|
||||
const MAPBOX_TOKEN =
|
||||
"pk.eyJ1IjoiamFrZWMiLCJhIjoiY2tkaHplNGhjMDAyMDJybW4ybmRqbTBmMyJ9.AR_fnEuka8-cFb4Snp3upw";
|
||||
|
||||
mapboxgl.accessToken = MAPBOX_TOKEN;
|
||||
|
||||
const colours = {
|
||||
road: "grey",
|
||||
cycleway: "green",
|
||||
laneMarking: "white",
|
||||
};
|
||||
|
||||
type LoadingStatusType = "loading" | "success" | "429error" | "unknownerror";
|
||||
export function Map() {
|
||||
const mapContainer = React.useRef<HTMLDivElement>(null);
|
||||
const mapRef = React.useRef<mapboxgl.Map | null>(null);
|
||||
const markers = useRef<mapboxgl.Marker[]>([]);
|
||||
const [lng, setLng] = useState(151.20671);
|
||||
const [lat, setLat] = useState(-33.8683861);
|
||||
const [zoom, setZoom] = useState(16);
|
||||
|
||||
const [lng, setLng] = useState(151.21084276742022);
|
||||
const [lat, setLat] = useState(-33.8720286260115);
|
||||
const [zoom, setZoom] = useState(17);
|
||||
|
||||
useEffect(() => {
|
||||
// This is called on every pan
|
||||
|
@ -36,90 +30,14 @@ export function Map() {
|
|||
|
||||
mapRef.current = new mapboxgl.Map({
|
||||
container: mapContainer.current,
|
||||
style: "mapbox://styles/mapbox/dark-v10",
|
||||
style: "mapbox://styles/mapbox/streets-v12",
|
||||
// style: "mapbox://styles/mapbox/dark-v10",
|
||||
center: [lng, lat],
|
||||
zoom: zoom,
|
||||
});
|
||||
|
||||
const map = mapRef.current;
|
||||
map.on("load", function () {
|
||||
console.log(
|
||||
"Adding sources. If you don't seen anything check vector server logs."
|
||||
);
|
||||
|
||||
// https://docs.mapbox.com/mapbox-gl-js/example/multiple-geometries/
|
||||
// Add a new vector tile source with ID 'mapillary'.
|
||||
map.addSource("osm2streets-vector-tileserver", {
|
||||
type: "vector",
|
||||
tiles: ["http://localhost:3000/tile/{z}/{x}/{y}"],
|
||||
minzoom: 15,
|
||||
maxzoom: 22,
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: "geometry",
|
||||
type: "fill",
|
||||
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "geometry",
|
||||
paint: {
|
||||
// To improve!
|
||||
"fill-color": colours.road,
|
||||
"fill-opacity": 0.4,
|
||||
},
|
||||
filter: ["==", "$type", "Polygon"],
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: "lanePolygons",
|
||||
type: "fill",
|
||||
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "lanePolygons",
|
||||
paint: {
|
||||
"fill-color": colours.road,
|
||||
"fill-opacity": 1,
|
||||
},
|
||||
filter: ["==", "$type", "Polygon"],
|
||||
});
|
||||
map.addLayer({
|
||||
id: "bikePath",
|
||||
type: "fill",
|
||||
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "lanePolygons",
|
||||
paint: {
|
||||
"fill-color": colours.cycleway,
|
||||
"fill-opacity": 1,
|
||||
},
|
||||
filter: ["==", "type", "Biking"],
|
||||
// filter: ["==", "$type", "Polygon"],
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: "laneMarkings",
|
||||
type: "fill",
|
||||
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "laneMarkings",
|
||||
paint: {
|
||||
"fill-color": colours.laneMarking,
|
||||
"fill-opacity": 1,
|
||||
},
|
||||
filter: ["==", "$type", "Polygon"],
|
||||
});
|
||||
map.addLayer({
|
||||
id: "intersectionMarkings",
|
||||
type: "fill",
|
||||
|
||||
source: "osm2streets-vector-tileserver",
|
||||
"source-layer": "intersectionMarkings",
|
||||
paint: {
|
||||
"fill-color": colours.road,
|
||||
"fill-opacity": 0.8,
|
||||
},
|
||||
filter: ["==", "$type", "Polygon"],
|
||||
});
|
||||
});
|
||||
map.on("load", mapOnLoad(map));
|
||||
|
||||
map.addControl(new mapboxgl.NavigationControl());
|
||||
map.addControl(new mapboxgl.FullscreenControl());
|
||||
|
@ -136,6 +54,9 @@ export function Map() {
|
|||
if (!map) {
|
||||
return; // wait for map to initialize
|
||||
}
|
||||
const { lng, lat } = map.getCenter();
|
||||
const zoom = map.getZoom();
|
||||
console.log(lng, lat, zoom);
|
||||
|
||||
setLng(map.getCenter().lng);
|
||||
setLat(map.getCenter().lat);
|
||||
|
@ -143,12 +64,11 @@ export function Map() {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="sidebar">
|
||||
<label>
|
||||
A side-project by{" "}
|
||||
A work in progrss side project by{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
@ -156,7 +76,7 @@ export function Map() {
|
|||
>
|
||||
Jake Coppinger
|
||||
</a>{" "}
|
||||
| Open source (GPLv3) on{" "}
|
||||
| Open source on{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
|
Ładowanie…
Reference in New Issue