<!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: '&copy; <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: '&copy; 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>