Compare commits
No commits in common. "7ce58ff48ee42dd3116aa65d70cb340d49a65f29" and "6041378e4454db845270039a5157b18fcb6a1edf" have entirely different histories.
7ce58ff48e
...
6041378e44
2 changed files with 23 additions and 131 deletions
|
@ -90,10 +90,7 @@ fetch("layers.json")
|
||||||
document.title = data["name"]
|
document.title = data["name"]
|
||||||
const layers = data["layers"]
|
const layers = data["layers"]
|
||||||
for (let key in layers) {
|
for (let key in layers) {
|
||||||
let layer = layers[key]
|
l.push({ dirname: key , name: layers[key]["humanname"], color: layers[key]["color"] });
|
||||||
layer.name = layer['humanname']
|
|
||||||
layer.dirname = key
|
|
||||||
l.push(layer)
|
|
||||||
rules.push({
|
rules.push({
|
||||||
dataLayer: key,
|
dataLayer: key,
|
||||||
symbolizer: new protomapsL.LineSymbolizer(layers[key])
|
symbolizer: new protomapsL.LineSymbolizer(layers[key])
|
||||||
|
@ -141,13 +138,6 @@ let geojsons = [];
|
||||||
let geojson;
|
let geojson;
|
||||||
let editlayer;
|
let editlayer;
|
||||||
|
|
||||||
async function purgeLayer(l) {
|
|
||||||
while (l.length > 0) {
|
|
||||||
map.removeLayer(l.pop());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function addGeoJsonToMap(dat) {
|
function addGeoJsonToMap(dat) {
|
||||||
if (editlayer != undefined) {
|
if (editlayer != undefined) {
|
||||||
const style = {
|
const style = {
|
||||||
|
@ -170,13 +160,16 @@ function scalarProduct(a,b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function recompute_anglemarkers(g) {
|
async function recompute_anglemarkers(g) {
|
||||||
purgeLayer(anglemarkers)
|
for (k=0; k < anglemarkers.length ; k++) {
|
||||||
|
map.removeLayer(anglemarkers[k])
|
||||||
|
}
|
||||||
|
anglemarkers = [];
|
||||||
const limit = document.getElementById("angle").value
|
const limit = document.getElementById("angle").value
|
||||||
let distance = 0
|
|
||||||
for (j=0; j< g.length; j++) {
|
for (j=0; j< g.length; j++) {
|
||||||
const coords = g[j].geometry.coordinates;
|
const coords = g[j].geometry.coordinates;
|
||||||
|
console.log(coords);
|
||||||
for (let i=1; i < coords.length - 1; i++) {
|
for (let i=1; i < coords.length - 1; i++) {
|
||||||
distance += L.latLng(coords[i][1],coords[i][0]).distanceTo(L.latLng(coords[i-1][1],coords[i-1][0]))
|
|
||||||
const a = computeVector(coords,i);
|
const a = computeVector(coords,i);
|
||||||
const b = computeVector(coords,i+1);
|
const b = computeVector(coords,i+1);
|
||||||
let angle = Math.acos(scalarProduct(a,b)/Math.sqrt(scalarProduct(a,a)*scalarProduct(b,b)))
|
let angle = Math.acos(scalarProduct(a,b)/Math.sqrt(scalarProduct(a,a)*scalarProduct(b,b)))
|
||||||
|
@ -186,16 +179,9 @@ async function recompute_anglemarkers(g) {
|
||||||
mark.addTo(map);
|
mark.addTo(map);
|
||||||
mark._icon.classList.add("warn");
|
mark._icon.classList.add("warn");
|
||||||
}
|
}
|
||||||
|
console.log(angle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.querySelector("#distance").innerHTML = `${(distance / 1000).toFixed(2)} km`
|
|
||||||
const markSpan = document.querySelector("#anglemarkers")
|
|
||||||
markSpan.innerHTML = `${anglemarkers.length} warning${anglemarkers.length != 1 ? "s" : ""}`
|
|
||||||
if (anglemarkers.length > 0) {
|
|
||||||
markSpan.classList.add("warning")
|
|
||||||
} else {
|
|
||||||
markSpan.classList.remove("warning")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateBrouter () {
|
async function updateBrouter () {
|
||||||
|
@ -206,8 +192,6 @@ async function updateBrouter () {
|
||||||
}
|
}
|
||||||
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");
|
||||||
} else {
|
|
||||||
resetEditing()
|
|
||||||
}
|
}
|
||||||
geojsons = [];
|
geojsons = [];
|
||||||
recompute_anglemarkers(geojsons);
|
recompute_anglemarkers(geojsons);
|
||||||
|
@ -215,14 +199,12 @@ async function updateBrouter () {
|
||||||
map.removeLayer(geojson);
|
map.removeLayer(geojson);
|
||||||
}
|
}
|
||||||
if (markers.length < 2) {
|
if (markers.length < 2) {
|
||||||
document.querySelector("#save").disabled = true
|
|
||||||
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 profile = document.querySelector("#brouter-profile").value;
|
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=${profile}&alternativeidx=0&format=geojson`;
|
|
||||||
fetch(url).then((response) => {
|
fetch(url).then((response) => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("HTTP error " + response.status);
|
throw new Error("HTTP error " + response.status);
|
||||||
|
@ -233,8 +215,9 @@ async function updateBrouter () {
|
||||||
if (geojson != undefined) {
|
if (geojson != undefined) {
|
||||||
map.removeLayer(geojson);
|
map.removeLayer(geojson);
|
||||||
}
|
}
|
||||||
document.querySelector("#save").disabled = false
|
|
||||||
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);
|
recompute_anglemarkers(geojsons);
|
||||||
const dat = {type: "FeatureCollection", features: geojsons};
|
const dat = {type: "FeatureCollection", features: geojsons};
|
||||||
|
@ -248,12 +231,11 @@ async function updateBrouter () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addBrouterMarker(pos) {
|
map.on('click', function(e) {
|
||||||
if (!editing) {
|
if (!editMode) {
|
||||||
editFilename = undefined
|
return;
|
||||||
}
|
}
|
||||||
purgeLayer(endmarkers)
|
marker = new L.marker(e.latlng, {draggable: true}) ;
|
||||||
const marker = new L.marker(pos, {draggable: true}) ;
|
|
||||||
markers.push(marker);
|
markers.push(marker);
|
||||||
marker.on("click", function(e) {
|
marker.on("click", function(e) {
|
||||||
map.removeLayer(this);
|
map.removeLayer(this);
|
||||||
|
@ -265,69 +247,17 @@ async function addBrouterMarker(pos) {
|
||||||
});
|
});
|
||||||
marker.addTo(map);
|
marker.addTo(map);
|
||||||
updateBrouter();
|
updateBrouter();
|
||||||
}
|
|
||||||
|
|
||||||
map.on('click', function(e) {
|
|
||||||
if (!editMode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
addBrouterMarker(e.latlng)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
async function quitEdit(e) {
|
async function quitEdit(e) {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
L.DomEvent.preventDefault(e);
|
L.DomEvent.preventDefault(e);
|
||||||
purgeLayer(endmarkers)
|
|
||||||
purgeLayer(markers)
|
|
||||||
purgeLayer(mapFeatures)
|
|
||||||
markers = []
|
|
||||||
updateBrouter()
|
|
||||||
recompute_anglemarkers([]);
|
|
||||||
|
|
||||||
editMode = false;
|
editMode = false;
|
||||||
document.querySelector(".edit-ui").style.display = "none";
|
document.querySelector(".edit-ui").style.display = "none";
|
||||||
document.getElementById("edit-mode").style.display = "block";
|
document.getElementById("edit-mode").style.display = "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
const endmarkers = []
|
|
||||||
const mapFeatures = []
|
|
||||||
const mapJSONs = {}
|
|
||||||
let editFilename
|
|
||||||
let editing
|
|
||||||
|
|
||||||
async function resetEditing() {
|
|
||||||
editFilename = undefined;
|
|
||||||
document.querySelector('#featurename').value = ""
|
|
||||||
editing = false
|
|
||||||
document.querySelector('#featurename').innerHTML = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startEdit(e) {
|
|
||||||
editing = true
|
|
||||||
purgeLayer(endmarkers)
|
|
||||||
addBrouterMarker(this._latlng)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function whenClicked(e, feature, filename) {
|
|
||||||
if (markers.length > 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
L.DomEvent.stopPropagation(e)
|
|
||||||
purgeLayer(endmarkers)
|
|
||||||
const coords = feature.geometry.coordinates
|
|
||||||
const start = new L.marker(L.latLng(coords[0][1],coords[0][0])).addTo(map)
|
|
||||||
const end = new L.marker(L.latLng(coords[coords.length-1][1],coords[coords.length-1][0])).addTo(map)
|
|
||||||
for (let mark of [start, end]) {
|
|
||||||
endmarkers.push(mark)
|
|
||||||
mark.on('click', startEdit)
|
|
||||||
}
|
|
||||||
editFilename = filename
|
|
||||||
document.querySelector('#featurename').value = editFilename
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function pickDirectory(e){
|
async function pickDirectory(e){
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
L.DomEvent.preventDefault(e);
|
L.DomEvent.preventDefault(e);
|
||||||
|
@ -338,31 +268,16 @@ async function pickDirectory(e){
|
||||||
}
|
}
|
||||||
const layerspan = document.querySelector("#layername")
|
const layerspan = document.querySelector("#layername")
|
||||||
layerspan.innerHTML = ""
|
layerspan.innerHTML = ""
|
||||||
document.querySelector("#brouter-profile").value = "rail";
|
|
||||||
for (i = 0; i < l.length ; i++ ) {
|
for (i = 0; i < l.length ; i++ ) {
|
||||||
|
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];
|
||||||
const profile = editlayer["brouter-profile"] ?? "rail" ;
|
|
||||||
document.querySelector("#brouter-profile").value = profile;
|
|
||||||
layerspan.innerHTML = "Editing layer " + layer_legend(l[i]) + "<br>"
|
layerspan.innerHTML = "Editing layer " + layer_legend(l[i]) + "<br>"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for await (const [name, handle] of dirHandle.entries()) {
|
|
||||||
if (handle.kind === 'file' && name.endsWith("json")) {
|
|
||||||
const fileData = await handle.getFile();
|
|
||||||
const feature = JSON.parse(await fileData.text());
|
|
||||||
const mapFeature = L.geoJson(feature, {
|
|
||||||
style : { "color": "#000", "width": 5 },
|
|
||||||
onEachFeature: function (feature, layer) {
|
|
||||||
layer.on('click', (event) => whenClicked(event, feature, name))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
mapJSONs[name] = feature
|
|
||||||
mapFeature.addTo(map)
|
|
||||||
mapFeatures.push(mapFeature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
editMode = true;
|
editMode = true;
|
||||||
document.getElementById("edit-mode").style.display = "none";
|
document.getElementById("edit-mode").style.display = "none";
|
||||||
document.querySelector(".edit-ui").style.display = "block";
|
document.querySelector(".edit-ui").style.display = "block";
|
||||||
|
@ -371,44 +286,30 @@ async function pickDirectory(e){
|
||||||
alert("There is no path to save!");
|
alert("There is no path to save!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filename = document.querySelector('#featurename').value
|
const filename = window.prompt("Enter filename:", "test");
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let dat = {type: "FeatureCollection", features: geojsons};
|
const dat = {type: "FeatureCollection", features: geojsons};
|
||||||
if (editFilename != undefined && mapJSONs[editFilename]) {
|
|
||||||
dat = mapJSONs[editFilename]
|
|
||||||
dat.features = dat.features.concat(geojsons)
|
|
||||||
}
|
|
||||||
let file;
|
let file;
|
||||||
let deffilename
|
|
||||||
if (filename.match(/\.json$|\.geojson$/)) {
|
|
||||||
deffilename = filename
|
|
||||||
} else {
|
|
||||||
deffilename = `${filename}.geojson`
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
file = await dirHandle.getFileHandle(deffilename, {
|
file = await dirHandle.getFileHandle(`${filename}.geojson`, {
|
||||||
create: true
|
create: true
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(`Could not open file: ${error.message}`);
|
alert(`Could not open file: ${error.message}`);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (editFilename != undefined && filename != editFilename) {
|
|
||||||
await dirHandle.removeEntry(editFilename)
|
|
||||||
}
|
|
||||||
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);
|
||||||
await writableStream.close();
|
await writableStream.close();
|
||||||
addGeoJsonToMap({type: "FeatureCollection", features: geojsons});
|
addGeoJsonToMap(dat);
|
||||||
for (i=0; i<markers.length; i++) {
|
for (i=0; i<markers.length; i++) {
|
||||||
map.removeLayer(markers[i]);
|
map.removeLayer(markers[i]);
|
||||||
}
|
}
|
||||||
markers = [];
|
markers = [];
|
||||||
updateBrouter();
|
updateBrouter();
|
||||||
resetEditing();
|
|
||||||
alert("Saved file!");
|
alert("Saved file!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,13 +326,9 @@ if (edit) {
|
||||||
buttonDiv.innerHTML = `<button id="edit-mode" onClick="pickDirectory(event)" >Edit</button>
|
buttonDiv.innerHTML = `<button id="edit-mode" onClick="pickDirectory(event)" >Edit</button>
|
||||||
<div class="edit-ui">
|
<div class="edit-ui">
|
||||||
<div id="layername" ></div>
|
<div id="layername" ></div>
|
||||||
<span id="distance">0.0 km</span> - <span id="anglemarkers" >0 warnings</span><br>
|
|
||||||
<label for="featurename">Filename</label><br><input type="text" id="featurename"><br>
|
|
||||||
<label for="brouter-profile">Brouter Profile</label><br>
|
|
||||||
<input type="text" id="brouter-profile" onchange="updateBrouter()" ><br>
|
|
||||||
<label for="angle">Turn restriction sensitivity</label><br>
|
<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>
|
<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)" disabled>Save</button><button id="quit" onclick="quitEdit(event)" >Quit</button>
|
<button id="save" onClick="pickDirectory(event)" >Save</button><button id="quit" onclick="quitEdit(event)" >Quit</button>
|
||||||
</div>`
|
</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.";
|
||||||
|
|
|
@ -27,8 +27,3 @@ img.warn { filter: hue-rotate(160deg); }
|
||||||
div.edit-ui {
|
div.edit-ui {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.warning {
|
|
||||||
color: red;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue