Compare commits
6 commits
67784097ae
...
d91e0bd8ad
Author | SHA1 | Date | |
---|---|---|---|
d91e0bd8ad | |||
198175fde2 | |||
4c9b1b555f | |||
634df5ebf4 | |||
13900c8092 | |||
13a7414798 |
3 changed files with 117 additions and 18 deletions
|
@ -15,6 +15,8 @@ legend.onAdd = function (map) {
|
||||||
|
|
||||||
|
|
||||||
const map = L.map("map", { center: [52,13], zoom: 3, minZoom: 0 });
|
const map = L.map("map", { center: [52,13], zoom: 3, minZoom: 0 });
|
||||||
|
map.attributionControl.setPrefix('Made with <a href="https://github.com/homologic/streckenkarte" > Streckenkarte</a>' );
|
||||||
|
|
||||||
|
|
||||||
function update_hash() {
|
function update_hash() {
|
||||||
const {lat, lng} = this.getCenter();
|
const {lat, lng} = this.getCenter();
|
||||||
|
@ -43,7 +45,7 @@ let pointPaintRules = [
|
||||||
stroke: 'white',
|
stroke: 'white',
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
}),
|
}),
|
||||||
filter: (z,f) => { return f.props.zoom < z }
|
filter: (z,f) => { return f.props.zoom > 0 && f.props.zoom < z }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -68,7 +70,7 @@ let pointRules = [
|
||||||
return `400 ${size}px sans-serif`;
|
return `400 ${size}px sans-serif`;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
filter: (z,f) => { return f.props.zoom < z },
|
filter: (z,f) => { return f.props.zoom > 0 && f.props.zoom < z },
|
||||||
sort: (a,b) => { return a.zoom - b.zoom }
|
sort: (a,b) => { return a.zoom - b.zoom }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -94,6 +96,7 @@ fetch("layers.json")
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const strecken = protomapsL.leafletLayer({
|
const strecken = protomapsL.leafletLayer({
|
||||||
|
attribution: "",
|
||||||
url: data["pmtiles_url"] ?? "strecken.pmtiles",
|
url: data["pmtiles_url"] ?? "strecken.pmtiles",
|
||||||
maxDataZoom: data["maxZoom"] ?? 10,
|
maxDataZoom: data["maxZoom"] ?? 10,
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
|
@ -104,6 +107,7 @@ fetch("layers.json")
|
||||||
strecken.addTo(map);
|
strecken.addTo(map);
|
||||||
if ("points_url" in data) {
|
if ("points_url" in data) {
|
||||||
const points = protomapsL.leafletLayer({
|
const points = protomapsL.leafletLayer({
|
||||||
|
attribution: "",
|
||||||
url: data["points_url"],
|
url: data["points_url"],
|
||||||
maxDataZoom: data["maxZoom"] ?? 10,
|
maxDataZoom: data["maxZoom"] ?? 10,
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
|
@ -120,6 +124,7 @@ fetch("layers.json")
|
||||||
let dirHandle;
|
let dirHandle;
|
||||||
let editMode = false;
|
let editMode = false;
|
||||||
let markers = [];
|
let markers = [];
|
||||||
|
let anglemarkers = [];
|
||||||
let geojsons = [];
|
let geojsons = [];
|
||||||
let geojson;
|
let geojson;
|
||||||
let editlayer;
|
let editlayer;
|
||||||
|
@ -137,35 +142,83 @@ function addGeoJsonToMap(dat) {
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function computeVector(coords, i) {
|
||||||
|
return [coords[i][0] - coords[i-1][0], coords[i][1] - coords[i-1][1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
function scalarProduct(a,b) {
|
||||||
|
return a[0] * b[0] + a[1] * b[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function recompute_anglemarkers(g) {
|
||||||
|
for (k=0; k < anglemarkers.length ; k++) {
|
||||||
|
map.removeLayer(anglemarkers[k])
|
||||||
|
}
|
||||||
|
anglemarkers = [];
|
||||||
|
const limit = document.getElementById("angle").value
|
||||||
|
|
||||||
|
for (j=0; j< g.length; j++) {
|
||||||
|
const coords = g[j].geometry.coordinates;
|
||||||
|
console.log(coords);
|
||||||
|
for (let i=1; i < coords.length - 1; i++) {
|
||||||
|
const a = computeVector(coords,i);
|
||||||
|
const b = computeVector(coords,i+1);
|
||||||
|
let angle = Math.acos(scalarProduct(a,b)/Math.sqrt(scalarProduct(a,a)*scalarProduct(b,b)))
|
||||||
|
if (angle > limit ) {
|
||||||
|
let mark = new L.marker(L.latLng(coords[i][1],coords[i][0]))
|
||||||
|
anglemarkers.push(mark);
|
||||||
|
mark.addTo(map);
|
||||||
|
mark._icon.classList.add("warn");
|
||||||
|
}
|
||||||
|
console.log(angle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function updateBrouter () {
|
async function updateBrouter () {
|
||||||
if (markers.length > 0) {
|
if (markers.length > 0) {
|
||||||
for (i=1; i< markers.length-1; i++) {
|
for (i=0; i< markers.length; i++) {
|
||||||
markers[i]._icon.classList.remove("red");
|
markers[i]._icon.classList.remove("red");
|
||||||
|
markers[i]._icon.classList.remove("darkred");
|
||||||
}
|
}
|
||||||
markers[markers.length-1]._icon.classList.add("red");
|
markers[markers.length-1]._icon.classList.add("red");
|
||||||
markers[0]._icon.classList.add("green");
|
markers[0]._icon.classList.add("green");
|
||||||
}
|
}
|
||||||
geojsons = [];
|
geojsons = [];
|
||||||
if (markers.length < 2) {
|
recompute_anglemarkers(geojsons);
|
||||||
if (geojson != undefined) {
|
if (geojson != undefined) {
|
||||||
map.removeLayer(geojson);
|
map.removeLayer(geojson);
|
||||||
}
|
}
|
||||||
|
if (markers.length < 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < markers.length - 1 ; i++) {
|
for (let i = 0; i < markers.length - 1 ; i++) {
|
||||||
const marker1 = markers[i].getLatLng();
|
const marker1 = markers[i].getLatLng();
|
||||||
const marker2 = markers[i+1].getLatLng();
|
const marker2 = markers[i+1].getLatLng();
|
||||||
const url = `https://brouter.de/brouter?lonlats=${marker1.lng},${marker1.lat}|${marker2.lng},${marker2.lat}&profile=rail&alternativeidx=0&format=geojson`;
|
const url = `https://brouter.de/brouter?lonlats=${marker1.lng},${marker1.lat}|${marker2.lng},${marker2.lat}&profile=rail&alternativeidx=0&format=geojson`;
|
||||||
fetch(url).then((response) => response.json())
|
fetch(url).then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("HTTP error " + response.status);
|
||||||
|
}
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (geojson != undefined) {
|
if (geojson != undefined) {
|
||||||
map.removeLayer(geojson);
|
map.removeLayer(geojson);
|
||||||
}
|
}
|
||||||
delete data.features[0].properties.messages
|
delete data.features[0].properties.messages;
|
||||||
|
|
||||||
|
console.log(data.features[0].geometry.coordinates)
|
||||||
geojsons.push(data.features[0]);
|
geojsons.push(data.features[0]);
|
||||||
|
recompute_anglemarkers(geojsons);
|
||||||
const dat = {type: "FeatureCollection", features: geojsons};
|
const dat = {type: "FeatureCollection", features: geojsons};
|
||||||
geojson = addGeoJsonToMap(dat);
|
geojson = addGeoJsonToMap(dat);
|
||||||
})
|
})
|
||||||
|
.catch(err => {
|
||||||
|
markers[i]._icon.classList.add("darkred");
|
||||||
|
markers[i+1]._icon.classList.add("darkred");
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +241,14 @@ map.on('click', function(e) {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
async function quitEdit(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
L.DomEvent.preventDefault(e);
|
||||||
|
editMode = false;
|
||||||
|
document.querySelector(".edit-ui").style.display = "none";
|
||||||
|
document.getElementById("edit-mode").style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
async function pickDirectory(e){
|
async function pickDirectory(e){
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
L.DomEvent.preventDefault(e);
|
L.DomEvent.preventDefault(e);
|
||||||
|
@ -196,18 +257,21 @@ async function pickDirectory(e){
|
||||||
if (!dirHandle) {
|
if (!dirHandle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const layerspan = document.querySelector("#layername")
|
||||||
|
layerspan.innerHTML = ""
|
||||||
for (i = 0; i < l.length ; i++ ) {
|
for (i = 0; i < l.length ; i++ ) {
|
||||||
console.log(l[i].dirname);
|
console.log(l[i].dirname);
|
||||||
if (l[i].dirname === dirHandle.name) {
|
if (l[i].dirname === dirHandle.name) {
|
||||||
|
console.log(l[i])
|
||||||
|
console.log(this)
|
||||||
editlayer = l[i];
|
editlayer = l[i];
|
||||||
this.innerHTML = "Editing layer " + layer_legend(l[i]) + "<br>" + this.innerHTML
|
layerspan.innerHTML = "Editing layer " + layer_legend(l[i]) + "<br>"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("edit-mode").style.color = "red";
|
|
||||||
document.getElementById("edit-mode").innerHTML = "save";
|
|
||||||
editMode = true;
|
editMode = true;
|
||||||
|
document.getElementById("edit-mode").style.display = "none";
|
||||||
|
document.querySelector(".edit-ui").style.display = "block";
|
||||||
} else {
|
} else {
|
||||||
if (geojsons.length < 1) {
|
if (geojsons.length < 1) {
|
||||||
alert("There is no path to save!");
|
alert("There is no path to save!");
|
||||||
|
@ -218,9 +282,15 @@ async function pickDirectory(e){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const dat = {type: "FeatureCollection", features: geojsons};
|
const dat = {type: "FeatureCollection", features: geojsons};
|
||||||
const file = await dirHandle.getFileHandle(`${filename}.geojson`, {
|
let file;
|
||||||
|
try {
|
||||||
|
file = await dirHandle.getFileHandle(`${filename}.geojson`, {
|
||||||
create: true
|
create: true
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
alert(`Could not open file: ${error.message}`);
|
||||||
|
return
|
||||||
|
}
|
||||||
const blob = new Blob([JSON.stringify(dat)]);
|
const blob = new Blob([JSON.stringify(dat)]);
|
||||||
const writableStream = await file.createWritable();
|
const writableStream = await file.createWritable();
|
||||||
await writableStream.write(blob);
|
await writableStream.write(blob);
|
||||||
|
@ -243,8 +313,22 @@ if (edit) {
|
||||||
customButton.onAdd = () => {
|
customButton.onAdd = () => {
|
||||||
const buttonDiv = L.DomUtil.create('div', 'legend');
|
const buttonDiv = L.DomUtil.create('div', 'legend');
|
||||||
if ("showDirectoryPicker" in window) {
|
if ("showDirectoryPicker" in window) {
|
||||||
buttonDiv.innerHTML = `<button id="edit-mode" >Edit</button>`;
|
// const button = L.DomUtil.create('button');
|
||||||
buttonDiv.addEventListener('click', pickDirectory, this)
|
// button.id = 'edit-mode';
|
||||||
|
// button.innerHTML = 'Edit';
|
||||||
|
// buttonDiv.appendChild(button)
|
||||||
|
// button.addEventListener('click', pickDirectory, this)
|
||||||
|
L.DomEvent.disableClickPropagation(buttonDiv);
|
||||||
|
buttonDiv.addEventListener('mouseover', L.DomEvent.stopPropagation);
|
||||||
|
buttonDiv.addEventListener('click', L.DomEvent.preventDefault)
|
||||||
|
buttonDiv.addEventListener('click', L.DomEvent.stopPropagation)
|
||||||
|
buttonDiv.innerHTML = `<button id="edit-mode" onClick="pickDirectory(event)" >Edit</button>
|
||||||
|
<div class="edit-ui">
|
||||||
|
<div id="layername" ></div>
|
||||||
|
<label for="angle">Turn restriction sensitivity</label><br>
|
||||||
|
<input type="range" min="0" step="0.05" max="1" value="0.35" class="slider" id="angle" onchange="recompute_anglemarkers(geojsons)" ><br>
|
||||||
|
<button id="save" onClick="pickDirectory(event)" >Save</button><button id="quit" onclick="quitEdit(event)" >Quit</button>
|
||||||
|
</div>`
|
||||||
} else {
|
} else {
|
||||||
buttonDiv.innerHTML = "Your browser does not support editing. <br> As of 2025, editing is supported on Chromium-based browsers only.";
|
buttonDiv.innerHTML = "Your browser does not support editing. <br> As of 2025, editing is supported on Chromium-based browsers only.";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -21,3 +22,8 @@ body {
|
||||||
}
|
}
|
||||||
img.red { filter: hue-rotate(120deg); }
|
img.red { filter: hue-rotate(120deg); }
|
||||||
img.green { filter: hue-rotate(-120deg); }
|
img.green { filter: hue-rotate(-120deg); }
|
||||||
|
img.darkred { filter: hue-rotate(160deg); }
|
||||||
|
img.warn { filter: hue-rotate(160deg); }
|
||||||
|
div.edit-ui {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
@ -15,8 +15,17 @@ do
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tippecanoe -aN -z"$zoom" -o "$temp/strecken.pmtiles" $temp/*.json
|
tippecanoe -aN -z"$zoom" -o "$temp/strecken.pmtiles" $temp/*.json
|
||||||
|
|
||||||
mv $temp/strecken.pmtiles "$2"
|
if [ -f "$1/points.json" ]
|
||||||
|
then
|
||||||
|
ogr2ogr -t_srs WGS84 "$temp/points.json" "$1/points.json"
|
||||||
|
tippecanoe -aN -z12 -r1 -o "$temp/points.pmtiles" "$temp/points.json"
|
||||||
|
jq '.points_url = "points.pmtiles"' "$1/layers.json" > "$2/layers.json"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
mv $temp/*.pmtiles "$2"
|
||||||
|
|
||||||
rm -r $temp
|
rm -r $temp
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue