<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Model Flying Fields in Austria</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
margin: 0;
}
html, body, #map {
width: 100%;
height: 100%;
}
</style>
<link rel="stylesheet" href="/.cdn/leaflet/1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin="" />
<script src="/.cdn/leaflet/1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
</head>
<body>
<div id="map"
ondrop="dropHandler(event);"
ondragover="dragOverHandler(event);">
</div>
<script>
const osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
});
const google_sat = L.tileLayer('https://{s}.google.com/vt?lyrs=s&x={x}&y={y}&z={z}', {
maxZoom: 19,
attribution: '© Google',
subdomains: ['mt0','mt1','mt2','mt3']
});
const icon_red = L.icon({
iconUrl: '/.cdn/leaflet-color-markers/0.1.0/img/marker-icon-red.png',
shadowUrl: '/.cdn/leaflet/1.9.4/dist/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
const icon_orange = L.icon({
iconUrl: '/.cdn/leaflet-color-markers/0.1.0/img/marker-icon-orange.png',
shadowUrl: '/.cdn/leaflet/1.9.4/dist/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
const icon_green = L.icon({
iconUrl: '/.cdn/leaflet-color-markers/0.1.0/img/marker-icon-green.png',
shadowUrl: '/.cdn/leaflet/1.9.4/dist/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
function pointToLayer(feature, latlng) {
if (feature.properties && feature.properties.radius) {
return L.circle(latlng, feature.properties.radius);
} else {
return L.marker(latlng);
}
}
function onEachFeature(feature, layer, addtext=null) {
let content = "";
if (feature.properties) {
if (feature.properties.name) {
content += "<strong>"+feature.properties.name+"</strong>";
}
}
if (addtext) {
content += "<br />";
content += addtext;
}
if (feature.geometry) {
if (feature.geometry.type === "Point") {
content += "<br />";
content += feature.geometry.coordinates[1]+", "+feature.geometry.coordinates[0];
}
}
if (content) {
layer.bindPopup(content);
}
}
const geojson_fields = L.geoJSON([], {
pointToLayer: pointToLayer,
onEachFeature: onEachFeature
});
const geojson_austrocontrol = L.geoJSON([], {
pointToLayer: pointToLayer,
style: function (feature) {
if (feature.properties.name.startsWith("Safety Zone")) {
return {color: '#ff0000'};
} else {
return {color: '#ffcc00'};
}
},
onEachFeature: function (feature, layer) {
const addtext = feature.properties.message;
onEachFeature(feature, layer, addtext);
}
});
const geojson_dji = L.geoJSON([], {
pointToLayer: function (feature, latlng) {
let marker;
switch (feature.properties.level) {
case 1: marker = L.marker(latlng, {icon: icon_red}); break;
case 2: marker = L.marker(latlng, {icon: icon_red}); break;
default: marker = L.marker(latlng, {icon: icon_orange}); break;
}
if (feature.properties.num_polygons) {
return marker;
} else {
const circle = L.circle(latlng, feature.properties.radius);
return L.featureGroup([circle, marker]);
}
},
style: function (feature) {
switch (feature.properties.level) {
case 1: return {color: '#ff0000'};
case 2: return {color: '#ff0000'};
default: return {color: '#ffcc00'};
}
},
onEachFeature: function (feature, layer) {
let addtext = "";
switch (feature.properties.level) {
case 0: addtext = "Warning Zone"; break;
case 1: addtext = "Authorization Zone"; break;
case 2: addtext = "Restricted Zone"; break;
case 3: addtext = "Enhanced Warning Zone"; break;
case 7: addtext = "Regulary Restricted Zone"; break;
case 8: addtext = "Approved Zone"; break;
}
onEachFeature(feature, layer, addtext);
},
filter: function (feature, layer) {
if (feature.geometry.type === "GeometryCollection") {
const geometries = feature.geometry.geometries;
feature.properties.num_polygons = geometries.filter(
function (e) { return e.type === "Polygon" }
).length
}
return true;
}
});
const geojson_dropped = L.geoJSON([], {
pointToLayer: pointToLayer,
onEachFeature: onEachFeature
});
const circle_loc = L.circle([0.0, 0.0], 0.0, {color: '#00ff00'});
const marker_loc = L.marker([0.0, 0.0], {icon: icon_green});
const group_loc = L.featureGroup();
const map = L.map('map', {
center: [47.2038, 14.7428],
zoom: 9,
layers: [osm, geojson_fields, geojson_austrocontrol, geojson_dropped, group_loc]
});
map.attributionControl.setPrefix('<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">Leaflet</a>');
const base_layers = {
'OpenStreetMap': osm,
'Google Satellite': google_sat
};
const overlays = {
'Model Flying Fields': geojson_fields,
'Austro Control Zones': geojson_austrocontrol,
'DJI GEO Zones': geojson_dji,
'Dropped GeoJSON': geojson_dropped,
'Current Location': group_loc
};
L.control.layers(base_layers, overlays).addTo(map);
L.control.scale({imperial: false}).addTo(map);
async function populateFields() {
// https://www.austrocontrol.at/jart/prj3/ac/data/uploads/OeAeC_MOD_001-i16a_modellflugplaetze.pdf
// Version: 2021-03-15, downloaded on 2023-02-13
const requestURL = 'OeAeC_MOD_001-i16a_modellflugplaetze.geojson';
const request = new Request(requestURL);
const response = await fetch(request);
const fields = await response.json();
geojson_fields.addData(fields);
}
populateFields();
async function populateAustroControl() {
// https://utm.dronespace.at/avm/
const requestURL = 'austrocontrol_zones.geojson';
const request = new Request(requestURL);
const response = await fetch(request);
const zones = await response.json();
geojson_austrocontrol.addData(zones);
}
populateAustroControl();
async function populateDJI() {
// https://fly-safe.dji.com/nfz/nfz-query
const requestURL = 'dji_geozones_at.geojson';
const request = new Request(requestURL);
const response = await fetch(request);
const geozones = await response.json();
geojson_dji.addData(geozones);
}
populateDJI();
function dragOverHandler(event) {
event.preventDefault();
}
function dropHandler(event) {
event.preventDefault();
const reader = new FileReader();
reader.onload = function () {
const data = JSON.parse(this.result);
geojson_dropped.addData(data);
};
reader.readAsText(event.dataTransfer.files[0]);
}
function onPositionReceived(position) {
const coords = [position.coords.latitude, position.coords.longitude];
const accuracy = position.coords.accuracy;
circle_loc.setLatLng(coords).setRadius(accuracy);
marker_loc.setLatLng(coords).bindPopup(
"<strong>You are here</strong><br />" +
"Accuracy: " + accuracy + "<br />" +
coords.join(", "));;
if (!group_loc.hasLayer(circle_loc)) {
group_loc.addLayer(circle_loc);
}
if (!group_loc.hasLayer(marker_loc)) {
group_loc.addLayer(marker_loc);
}
group_loc.bringToFront();
}
navigator.geolocation.watchPosition(onPositionReceived);
</script>
</body>
</html>