first functional commit
This commit is contained in:
commit
07c9e50a9f
2 changed files with 214 additions and 0 deletions
9
README.md
Normal file
9
README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# logbook2map
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
python3 -m http.server -b "::" 8030
|
||||
```
|
||||
|
||||
Go to https://8030.code.louis.hostux.fr
|
205
index.html
Normal file
205
index.html
Normal file
|
@ -0,0 +1,205 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>logbook2map</title>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css">
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#input_modal {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
display: none;
|
||||
|
||||
textarea {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
font-size: 1.5em;
|
||||
min-width: 20em;
|
||||
min-height: 20em;
|
||||
max-width: 40em;
|
||||
max-height: 40em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
|
||||
<div id="input_modal">
|
||||
<textarea placeholder="ICAO_departure;ICAO_destination Validate with Ctrl+Enter Load new data with Ctrl+O"></textarea>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
|
||||
<script>
|
||||
const osmStyle = {
|
||||
"version": 8,
|
||||
"sources": {
|
||||
"osm": {
|
||||
"type": "raster",
|
||||
"tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"],
|
||||
"tileSize": 256,
|
||||
"attribution": "© OpenStreetMap Contributors",
|
||||
"maxzoom": 19
|
||||
}
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"id": "osm",
|
||||
"type": "raster",
|
||||
"source": "osm" // This must match the source key above
|
||||
}
|
||||
]
|
||||
};
|
||||
var map = new maplibregl.Map({
|
||||
container: 'map', // container id
|
||||
style: osmStyle, // style URL
|
||||
center: [17.97, 57.91], // starting position [lng, lat]
|
||||
zoom: 3.7 // starting zoom
|
||||
});
|
||||
|
||||
function _updateMap(csvData, airportsData) {
|
||||
const lines = csvData.split('\n');
|
||||
const features = lines.map(line => {
|
||||
const [from, to] = line.split(',');
|
||||
|
||||
const fromAirport = airportsData[from];
|
||||
const toAirport = airportsData[to];
|
||||
|
||||
if(!fromAirport) { alert(`Airport ${from} not found`); return; }
|
||||
if(!toAirport) { alert(`Airport ${to} not found`); return; }
|
||||
|
||||
const fromLongitude = parseFloat(fromAirport.longitude);
|
||||
const fromLatitude = parseFloat(fromAirport.latitude);
|
||||
const toLongitude = parseFloat(toAirport.longitude);
|
||||
const toLatitude = parseFloat(toAirport.latitude);
|
||||
|
||||
return {
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
from,
|
||||
to
|
||||
},
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[fromLongitude, fromLatitude],
|
||||
[toLongitude, toLatitude]
|
||||
]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
map.addSource('routes', {
|
||||
type: 'geojson',
|
||||
data: {
|
||||
type: 'FeatureCollection',
|
||||
features
|
||||
}
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: 'routes',
|
||||
type: 'line',
|
||||
source: 'routes',
|
||||
layout: {
|
||||
'line-join': 'round',
|
||||
'line-cap': 'round'
|
||||
},
|
||||
paint: {
|
||||
'line-color': '#bd34eb',
|
||||
'line-width': 4
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateMap(csvData) {
|
||||
// download https://davidmegginson.github.io/ourairports-data/airports.csv if not locally available
|
||||
const request = indexedDB.open('my_database', 1);
|
||||
request.onupgradeneeded = function(event) {
|
||||
const db = event.target.result;
|
||||
const objectStore = db.createObjectStore('airports');
|
||||
};
|
||||
request.onerror = function(event) { alert('Error while opening database:\n' + event.target.error); };
|
||||
request.onsuccess = function(event) {
|
||||
const db = event.target.result;
|
||||
const transaction = db.transaction(['airports'], 'readwrite');
|
||||
const objectStore = transaction.objectStore('airports');
|
||||
|
||||
const getRequest = objectStore.get('airports');
|
||||
getRequest.onerror = function(event) { alert("Error getting data:\n" + event.target.error); };
|
||||
getRequest.onsuccess = function(event) {
|
||||
if (!event.target.result) {
|
||||
// Data not found, fetch and store it
|
||||
fetch('https://davidmegginson.github.io/ourairports-data/airports.csv')
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
console.info('Downloaded airports.csv, parsing the data...');
|
||||
const airports = {};
|
||||
for(const airport of data.split('\n')) {
|
||||
const [_id, ident, _type, name, latitude, longitude] = airport.split(',');
|
||||
if(!ident) continue;
|
||||
airports[ident.replace(/^"|"$/g, '')] = { name, latitude, longitude };
|
||||
}
|
||||
|
||||
const transaction = db.transaction(['airports'], 'readwrite');
|
||||
const objectStore = transaction.objectStore('airports');
|
||||
objectStore.put(airports, 'airports');
|
||||
_updateMap(csvData, airports);
|
||||
})
|
||||
.catch(error => { alert('Error while downloading airports.csv: \n' + error); });
|
||||
} else {
|
||||
console.log('Data found in local storage!');
|
||||
_updateMap(csvData, event.target.result);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function showInputModal() {
|
||||
document.getElementById('input_modal').style.display = 'flex';
|
||||
|
||||
const textarea = document.querySelector('#input_modal textarea');
|
||||
textarea.focus();
|
||||
textarea.addEventListener('keydown', event => {
|
||||
if(event.ctrlKey && event.key === 'Enter') {
|
||||
const csvData = textarea.value;
|
||||
updateMap(csvData);
|
||||
document.getElementById('input_modal').style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showInputModal();
|
||||
|
||||
document.addEventListener('keydown', event => {
|
||||
if(event.ctrlKey && event.key === 'o') {
|
||||
event.preventDefault();
|
||||
showInputModal();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue