Files
geograsim/App/sims/heli/routes.html
T
Adminator eac686ee1a Atlas: Tile-Proxy + Leaflet lokal — DSGVO-Sanierung fuer Kartendienste
- Leaflet 1.9.4 (CSS + JS + 5 Marker-Images) lokal unter
  App/assets/vendor/leaflet/ statt via unpkg.com/Cloudflare
- Neuer PHP-Endpunkt App/php/tile-proxy.php mit Disk-Cache, liefert
  OSM- und CARTO-Kacheln serverseitig aus; Browser kontaktiert keinen
  Drittanbieter mehr
- Whitelist (osm, carto), Zoom 3-18, 30 Tage Browser-Cache, ETag +
  If-Modified-Since, sauberer User-Agent fuer OSM-Policy
- Cache-Pfad: APP_ROOT/data/tiles lokal, via .env TILE_CACHE_DIR
  auf Produktions-Volume /var/www/html/geograsim/data/tiles
- Heli (heli.php + heli-game.php), Logistik (logistik.php), Routes-
  Dev-Tool und admin-levels.html alle auf Proxy umgestellt
- Datenschutzerklaerung: alter Google-AdSense-Passus (falsch, nicht
  im Einsatz) entfernt, neuer Abschnitt zur serverseitigen
  Tile-Auslieferung mit Rechtsgrundlage Art. 6 Abs. 1 lit. f DSGVO
- .gitignore: App/data/tiles ausgeschlossen
- .env.example: TILE_CACHE_DIR + OpenAI/ElevenLabs dokumentiert

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 00:53:43 +02:00

503 lines
31 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Heli-Routen Vorarlberg</title>
<link rel="icon" type="image/png" href="../../favicon-96x96.png">
<link rel="stylesheet" href="../../assets/vendor/leaflet/leaflet.css">
<link rel="stylesheet" href="../../assets/fonts/inter.css">
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',sans-serif;background:#f7f6f3;height:100vh;display:flex;flex-direction:column}
.topbar{background:#fff;padding:.5rem 1rem;display:flex;align-items:center;gap:.8rem;border-bottom:1px solid rgba(0,0,0,.06);flex-shrink:0;flex-wrap:wrap}
.topbar h1{font-size:.9rem;font-weight:800;color:#1f4e5a}
.topbar select{padding:.3rem .5rem;border:1.5px solid rgba(0,0,0,.1);border-radius:6px;font-size:.75rem;font-family:inherit;font-weight:600;max-width:350px}
.topbar .info{font-size:.68rem;color:#8a8a8a;flex:1}
.badge{display:inline-block;font-size:.6rem;font-weight:700;padding:1px 6px;border-radius:4px;margin-left:4px}
.badge-easy{background:#dceadd;color:#3a6b3e}
.badge-medium{background:#f2eacc;color:#8a7020}
.badge-hard{background:#f2ddd8;color:#8a3a2a}
#map{flex:1}
.wp-marker{width:22px;height:22px;background:#fff;border:2px solid #1f4e5a;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#1f4e5a;box-shadow:0 1px 4px rgba(0,0,0,.25)}
.wp-marker.start{background:#e8833a;border-color:#c06020;color:#fff;width:28px;height:28px;font-size:12px}
.wp-marker.end{background:#c85c4a;border-color:#a04030;color:#fff;width:28px;height:28px;font-size:12px}
.wp-label{font-family:'Inter',sans-serif;font-weight:700;font-size:9px;color:#1f4e5a;white-space:nowrap;background:rgba(255,255,255,.88);padding:1px 5px;border-radius:3px;box-shadow:0 1px 2px rgba(0,0,0,.1)}
.route-desc{position:absolute;bottom:12px;left:12px;right:12px;background:rgba(255,255,255,.95);border-radius:10px;padding:10px 14px;font-size:.75rem;color:#333;box-shadow:0 4px 16px rgba(0,0,0,.12);z-index:1000;line-height:1.5;max-height:30vh;overflow-y:auto}
.route-desc h3{font-size:.85rem;font-weight:800;color:#1f4e5a;margin-bottom:4px}
.route-desc .meta{font-size:.65rem;color:#8a8a8a}
</style>
</head>
<body>
<div class="topbar">
<h1>🚁 Heli-Routen</h1>
<select id="region-select" onchange="filterRoutes()" style="padding:.3rem .5rem;border:1.5px solid rgba(0,0,0,.1);border-radius:6px;font-size:.75rem;font-family:inherit;font-weight:600">
<option value="all">Alle Regionen</option>
<option value="vlbg">Vorarlberg</option>
<option value="tirol">Tirol</option>
</select>
<select id="route-select" onchange="showRoute()"></select>
<div class="info" id="route-info">60 Routen · Vorarlberg + Tirol</div>
</div>
<div id="map" style="position:relative">
<div class="route-desc" id="route-desc"></div>
</div>
<script src="../../assets/vendor/leaflet/leaflet.js"></script>
<script>
var map = L.map('map', {zoomControl:false}).setView([47.2, 11.0], 9);
L.tileLayer('../../php/tile-proxy.php?z={z}&x={x}&y={y}&p=osm', {
attribution:'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>', maxZoom:16
}).addTo(map);
L.control.zoom({position:'topright'}).addTo(map);
L.control.scale({position:'bottomleft',metric:true,imperial:false}).addTo(map);
// Waypoints: echte Vorarlberger Orte
var WP = {
// Basen
nenzing: {lat:47.1828, lon:9.7072, name:'C8 Nenzing (ÖAMTC)'},
hohenems: {lat:47.3650, lon:9.6892, name:'Hohenems (Polizei)'},
// Rheintal
feldkirch: {lat:47.2376, lon:9.5982, name:'Feldkirch'},
rankweil: {lat:47.2725, lon:9.6450, name:'Rankweil'},
goetzis: {lat:47.3333, lon:9.6333, name:'Götzis'},
dornbirn: {lat:47.4136, lon:9.7424, name:'Dornbirn'},
bregenz: {lat:47.5026, lon:9.7473, name:'Bregenz'},
lustenau: {lat:47.4267, lon:9.6583, name:'Lustenau'},
// Walgau / Klostertal
bludenz: {lat:47.1546, lon:9.8222, name:'Bludenz'},
buers: {lat:47.1500, lon:9.8000, name:'Bürs'},
nüziders: {lat:47.1700, lon:9.8000, name:'Nüziders'},
innerbraz: {lat:47.1347, lon:9.9208, name:'Innerbraz'},
kloeserle: {lat:47.1283, lon:10.0750, name:'Klösterle'},
stuben: {lat:47.1300, lon:10.1900, name:'Stuben am Arlberg'},
langen: {lat:47.1283, lon:10.1167, name:'Langen am Arlberg'},
// Montafon
schruns: {lat:47.0800, lon:9.9167, name:'Schruns'},
tschagguns: {lat:47.0750, lon:9.9000, name:'Tschagguns'},
stgallenk: {lat:47.0500, lon:9.8833, name:'St. Gallenkirch'},
gaschurn: {lat:47.0167, lon:10.0167, name:'Gaschurn'},
partenen: {lat:47.0000, lon:10.0667, name:'Partenen'},
silvretta: {lat:46.9167, lon:10.0833, name:'Silvretta-Stausee'},
// Großes Walsertal
thueringen: {lat:47.2200, lon:9.7600, name:'Thüringen'},
zwischenwasser:{lat:47.2300, lon:9.8000, name:'Zwischenwasser'},
laterns: {lat:47.2500, lon:9.8700, name:'Laterns'},
damuels: {lat:47.2833, lon:9.8917, name:'Damüls'},
fontanella: {lat:47.2600, lon:9.9400, name:'Fontanella'},
sonntag: {lat:47.2300, lon:9.9200, name:'Sonntag'},
// Bregenzerwald
egg: {lat:47.4333, lon:9.8917, name:'Egg'},
bezau: {lat:47.3833, lon:9.9000, name:'Bezau'},
mellau: {lat:47.3500, lon:9.8833, name:'Mellau'},
au: {lat:47.3333, lon:9.9667, name:'Au'},
schoppernau:{lat:47.3167, lon:10.0167, name:'Schoppernau'},
warth: {lat:47.2533, lon:10.1883, name:'Warth'},
schroecken: {lat:47.2583, lon:10.0917, name:'Schröcken'},
lech: {lat:47.2083, lon:10.1417, name:'Lech am Arlberg'},
zuers: {lat:47.1700, lon:10.1583, name:'Zürs'},
// Brandnertal / Rätikon
brand: {lat:47.1000, lon:9.7333, name:'Brand'},
// Kleinwalsertal
riezlern: {lat:47.3583, lon:10.1917, name:'Riezlern'},
mittelberg: {lat:47.3333, lon:10.1500, name:'Mittelberg'},
// Pfänder / Bodensee
pfaender: {lat:47.5100, lon:9.7800, name:'Pfänder (1064 m)'},
// Kanisfluh
kanisfluh: {lat:47.3600, lon:9.9400, name:'Kanisfluh (2044 m)'},
// Spezielle Einsatzorte
damuels_ski:{lat:47.2900, lon:9.8950, name:'Skigebiet Damüls'},
lech_ski: {lat:47.2150, lon:10.1500, name:'Skigebiet Lech-Zürs'},
silvretta_bielerhöhe:{lat:46.9200, lon:10.0900, name:'Bielerhöhe'},
brandnergletscher:{lat:47.0800, lon:9.7500, name:'Brandner Gletscher'},
// Einsatzorte
verkehr_a14:{lat:47.2800, lon:9.6600, name:'Unfall A14 Rankweil'},
bergrettung_muels:{lat:47.2700, lon:9.8800, name:'Skiunfall Damüls-Mellau'},
vermisst_silvretta:{lat:46.9500, lon:10.0700, name:'Vermisste Person Silvretta'},
hochwasser_ill:{lat:47.1200, lon:9.8500, name:'Hochwasser Ill-Tal'},
// === TIROL ===
// Basen
innsbruck_c1:{lat:47.2600, lon:11.3439, name:'C1 Innsbruck (ÖAMTC)'},
zams_c5: {lat:47.1597, lon:10.5933, name:'C5 Zams (ÖAMTC)'},
kitzbuehel_c4:{lat:47.3801, lon:12.3580, name:'C4 Kitzbühel (ÖAMTC)'},
lienz_c7: {lat:46.8297, lon:12.7647, name:'C7 Lienz (ÖAMTC)'},
// Inntal
hall: {lat:47.2894, lon:11.5083, name:'Hall in Tirol'},
schwaz: {lat:47.3517, lon:11.7100, name:'Schwaz'},
woergl: {lat:47.4873, lon:12.0638, name:'Wörgl'},
kufstein: {lat:47.5836, lon:12.1647, name:'Kufstein'},
telfs: {lat:47.3128, lon:11.0697, name:'Telfs'},
imst: {lat:47.2450, lon:10.7397, name:'Imst'},
landeck: {lat:47.1397, lon:10.5669, name:'Landeck'},
reutte: {lat:47.4858, lon:10.7181, name:'Reutte'},
// Stubaital
fulpmes: {lat:47.1558, lon:11.3533, name:'Fulpmes'},
neustift: {lat:47.1083, lon:11.3117, name:'Neustift im Stubaital'},
stubaier_gl: {lat:46.9972, lon:11.1167, name:'Stubaier Gletscher'},
// Ötztal
oetz: {lat:47.2083, lon:10.8933, name:'Ötz'},
soelden: {lat:46.9667, lon:10.8750, name:'Sölden'},
obergurgl: {lat:46.8700, lon:11.0300, name:'Obergurgl'},
// Zillertal
jenbach: {lat:47.3917, lon:11.7750, name:'Jenbach'},
zell_ziller: {lat:47.2286, lon:11.8822, name:'Zell am Ziller'},
mayrhofen: {lat:47.1592, lon:11.8614, name:'Mayrhofen'},
hintertux: {lat:47.0833, lon:11.6500, name:'Hintertux'},
// Wipptal / Brenner
steinach: {lat:47.0886, lon:11.4672, name:'Steinach am Brenner'},
brenner_ort: {lat:47.0422, lon:11.5067, name:'Brenner'},
// Osttirol
matrei: {lat:47.0000, lon:12.5333, name:'Matrei in Osttirol'},
kals: {lat:47.0083, lon:12.6417, name:'Kals am Großglockner'},
sillian: {lat:46.7519, lon:12.4219, name:'Sillian'},
// Arlberg
st_anton: {lat:47.1286, lon:10.2653, name:'St. Anton am Arlberg'},
// Kitzbühel
kitzbuehel_ort:{lat:47.4464, lon:12.3922, name:'Kitzbühel'},
st_johann: {lat:47.3528, lon:12.4247, name:'St. Johann in Tirol'},
// Seefeld / Karwendel
seefeld: {lat:47.3300, lon:11.1900, name:'Seefeld'},
scharnitz: {lat:47.3889, lon:11.2647, name:'Scharnitz'},
// Einsatzorte Tirol
lawine_arlberg:{lat:47.1400, lon:10.2200, name:'Lawine St. Anton'},
skiunfall_soelden:{lat:46.9800, lon:10.8600, name:'Skiunfall Sölden'},
bergunfall_glockner:{lat:47.0750, lon:12.6950, name:'Bergunfall Großglockner'},
vermisst_karwendel:{lat:47.3600, lon:11.3900, name:'Vermisste Person Karwendel'},
verkehr_inntal:{lat:47.3000, lon:11.6000, name:'Unfall A12 Inntal'},
hochwasser_inn:{lat:47.2700, lon:10.8500, name:'Hochwasser Inn bei Imst'},
};
// === 30 ROUTEN ===
var ROUTES = [
// --- VON NENZING (C8) ---
{id:1, name:'Nenzing → Damüls (Skiunfall)', start:'nenzing', end:'bergrettung_muels', difficulty:'medium',
waypoints:['nenzing','thueringen','zwischenwasser','laterns','damuels','bergrettung_muels'],
desc:'Skiunfall im Gebiet Damüls-Mellau. Route über das Laternsertal, da Direktflug über den Grat bei Wind nicht möglich.', reason:'Gebirgsumgehung über Talroute'},
{id:2, name:'Nenzing → Lech (Lawinenunfall)', start:'nenzing', end:'lech', difficulty:'hard',
waypoints:['nenzing','bludenz','kloeserle','stuben','zuers','lech'],
desc:'Lawinenunfall bei Lech. Klassische Route durch das Klostertal und über den Arlberg.', reason:'Standardroute durch Klostertal'},
{id:3, name:'Nenzing → Silvretta (Vermisste)', start:'nenzing', end:'vermisst_silvretta', difficulty:'hard',
waypoints:['nenzing','bludenz','schruns','stgallenk','gaschurn','partenen','silvretta','vermisst_silvretta'],
desc:'Vermisste Wandergruppe im Silvrettagebiet. Langer Flug durch das gesamte Montafon bis zur Bielerhöhe.', reason:'Einzige Zugangsroute durch das enge Montafon'},
{id:4, name:'Nenzing → Bregenz (Seerettung)', start:'nenzing', end:'bregenz', difficulty:'easy',
waypoints:['nenzing','feldkirch','rankweil','goetzis','dornbirn','bregenz'],
desc:'Notfall am Bodensee. Einfacher Rheintal-Flug nach Norden.', reason:'Flaches Rheintal, keine Hindernisse'},
{id:5, name:'Nenzing → Brand (Bergrettung)', start:'nenzing', end:'brand', difficulty:'medium',
waypoints:['nenzing','buers','brand'],
desc:'Kletterunfall im Brandnertal (Rätikon). Kurzer, aber enger Talflug.', reason:'Kurze Distanz, enges Tal'},
{id:6, name:'Nenzing → Schoppernau (Verkehr)', start:'nenzing', end:'schoppernau', difficulty:'medium',
waypoints:['nenzing','feldkirch','rankweil','goetzis','egg','bezau','au','schoppernau'],
desc:'Schwerer Verkehrsunfall bei Schoppernau. Route über Rheintal und Bregenzerwald.', reason:'Umweg über Rheintal nötig — Direktflug über Gebirge bei Wetter nicht möglich'},
{id:7, name:'Nenzing → Gaschurn (Hochwasser)', start:'nenzing', end:'hochwasser_ill', difficulty:'medium',
waypoints:['nenzing','bludenz','schruns','tschagguns','stgallenk','hochwasser_ill'],
desc:'Hochwasser an der Ill. Evakuierung im vorderen Montafon.', reason:'Flusstal-Route'},
{id:8, name:'Nenzing → Warth (Skiunfall)', start:'nenzing', end:'warth', difficulty:'hard',
waypoints:['nenzing','bludenz','kloeserle','langen','stuben','zuers','lech','warth'],
desc:'Skiunfall bei Warth-Schröcken. Lange Route über Klostertal und Arlberg.', reason:'Einzige wettersichere Route über den Arlberg'},
{id:9, name:'Nenzing → A14 Rankweil (Verkehr)', start:'nenzing', end:'verkehr_a14', difficulty:'easy',
waypoints:['nenzing','thueringen','rankweil','verkehr_a14'],
desc:'Massenkarambolage auf der A14. Kürzester Weg.', reason:'Direktflug, minimale Distanz'},
{id:10, name:'Nenzing → Fontanella (Großes Walsertal)', start:'nenzing', end:'fontanella', difficulty:'hard',
waypoints:['nenzing','thueringen','zwischenwasser','sonntag','fontanella'],
desc:'Akuter Notfall im hinteren Großen Walsertal. Enges, winkeliges Tal.', reason:'Große Walsertal nur durch Taleingang erreichbar'},
{id:11, name:'Nenzing → Dornbirn (Industrieunfall)', start:'nenzing', end:'dornbirn', difficulty:'easy',
waypoints:['nenzing','feldkirch','rankweil','goetzis','hohenems','dornbirn'],
desc:'Chemieunfall in Dornbirn. Rheintal-Direktflug.', reason:'Flaches Gelände, gute Sicht'},
{id:12, name:'Nenzing → Kleinwalsertal', start:'nenzing', end:'mittelberg', difficulty:'hard',
waypoints:['nenzing','feldkirch','rankweil','goetzis','egg','bezau','au','schroecken','warth','riezlern','mittelberg'],
desc:'Notfall im Kleinwalsertal. Nur über den Bregenzerwald erreichbar (keine Straße nach Österreich!).', reason:'Kleinwalsertal ist nur von Deutschland oder per Luft erreichbar'},
{id:13, name:'Nenzing → Zürs (Piste)', start:'nenzing', end:'zuers', difficulty:'medium',
waypoints:['nenzing','bludenz','innerbraz','kloeserle','langen','stuben','zuers'],
desc:'Verletzung auf der Skipiste in Zürs. Route durch Klostertal.', reason:'Klassische Arlberg-Zufahrt'},
{id:14, name:'Nenzing → Pfänder (Wanderunfall)', start:'nenzing', end:'pfaender', difficulty:'easy',
waypoints:['nenzing','feldkirch','rankweil','goetzis','dornbirn','bregenz','pfaender'],
desc:'Wanderunfall am Pfänder über Bregenz. Einfacher Rheintal-Flug mit kurzem Anstieg.', reason:'Pfänder ist niedrig und gut erreichbar'},
{id:15, name:'Nenzing → Mellau (Canyoning)', start:'nenzing', end:'mellau', difficulty:'medium',
waypoints:['nenzing','rankweil','goetzis','egg','bezau','mellau'],
desc:'Canyoning-Unfall bei Mellau. Route über Bregenzerwald.', reason:'Bregenzerwald-Route'},
// --- VON HOHENEMS (Polizei) ---
{id:16, name:'Hohenems → Damüls (Skiunfall)', start:'hohenems', end:'bergrettung_muels', difficulty:'medium',
waypoints:['hohenems','goetzis','rankweil','zwischenwasser','laterns','damuels','bergrettung_muels'],
desc:'Polizeieinsatz nach Skiunfall Damüls. Route über Götzis und Laternsertal.', reason:'Umgehung des Gebirges über Talroute'},
{id:17, name:'Hohenems → Bregenz (Demonstration)', start:'hohenems', end:'bregenz', difficulty:'easy',
waypoints:['hohenems','dornbirn','bregenz'],
desc:'Polizeieinsatz bei Großveranstaltung in Bregenz. Kurzer Rheintal-Flug.', reason:'Minimale Distanz'},
{id:18, name:'Hohenems → Lech (Sucheinsatz)', start:'hohenems', end:'lech', difficulty:'hard',
waypoints:['hohenems','dornbirn','egg','bezau','au','schroecken','warth','lech'],
desc:'Vermisstensuche bei Lech. Route über den gesamten Bregenzerwald.', reason:'Bregenzerwald-Route vermeidet hohe Pässe'},
{id:19, name:'Hohenems → Schruns (Fahndung)', start:'hohenems', end:'schruns', difficulty:'medium',
waypoints:['hohenems','rankweil','nenzing','bludenz','schruns'],
desc:'Fahndungseinsatz in Schruns. Route über Rheintal und Walgau.', reason:'Standardroute ins Montafon'},
{id:20, name:'Hohenems → Feldkirch (Amtshilfe)', start:'hohenems', end:'feldkirch', difficulty:'easy',
waypoints:['hohenems','rankweil','feldkirch'],
desc:'Polizeieinsatz in Feldkirch. Sehr kurzer Flug.', reason:'Direkte Linie im Rheintal'},
{id:21, name:'Hohenems → Lustenau (Grenze)', start:'hohenems', end:'lustenau', difficulty:'easy',
waypoints:['hohenems','lustenau'],
desc:'Grenzeinsatz bei Lustenau (Schweizer Grenze). Kürzeste Route.', reason:'Nachbarort, Sichtflug'},
{id:22, name:'Hohenems → Egg (Bregenzerwald)', start:'hohenems', end:'egg', difficulty:'easy',
waypoints:['hohenems','dornbirn','egg'],
desc:'Einsatz im vorderen Bregenzerwald. Route über Dornbirn.', reason:'Einfache Talroute'},
{id:23, name:'Hohenems → Gaschurn (Großeinsatz)', start:'hohenems', end:'gaschurn', difficulty:'hard',
waypoints:['hohenems','rankweil','nenzing','bludenz','schruns','stgallenk','gaschurn'],
desc:'Großeinsatz im hinteren Montafon. Langer Flug durch mehrere Täler.', reason:'Montafon nur von Bludenz aus erreichbar'},
{id:24, name:'Hohenems → Brand (Kletterunfall)', start:'hohenems', end:'brand', difficulty:'medium',
waypoints:['hohenems','rankweil','nenzing','buers','brand'],
desc:'Kletterunfall im Brandnertal. Route über Walgau.', reason:'Brandnertal-Zugang über Bürs'},
{id:25, name:'Hohenems → Sonntag (Walsertal)', start:'hohenems', end:'sonntag', difficulty:'hard',
waypoints:['hohenems','rankweil','thueringen','zwischenwasser','sonntag'],
desc:'Notfall im Großen Walsertal. Enges Tal, schwieriger Zugang.', reason:'Talenge erfordert präzise Navigation'},
{id:26, name:'Hohenems → Bezau (Verkehr)', start:'hohenems', end:'bezau', difficulty:'easy',
waypoints:['hohenems','dornbirn','egg','bezau'],
desc:'Verkehrsunfall bei Bezau. Route über den vorderen Bregenzerwald.', reason:'Einfache Bregenzerwald-Route'},
{id:27, name:'Hohenems → Stuben (Arlberg)', start:'hohenems', end:'stuben', difficulty:'hard',
waypoints:['hohenems','rankweil','nenzing','bludenz','innerbraz','kloeserle','stuben'],
desc:'Einsatz am Arlberg. Langer Flug durch Walgau und Klostertal.', reason:'Arlberg nur über Klostertal erreichbar'},
{id:28, name:'Hohenems → Silvretta', start:'hohenems', end:'silvretta', difficulty:'hard',
waypoints:['hohenems','rankweil','nenzing','bludenz','schruns','gaschurn','partenen','silvretta'],
desc:'Bergunfall an der Silvretta. Längste Route — komplettes Montafon.', reason:'Silvretta nur über Montafon erreichbar'},
{id:29, name:'Hohenems → Kanisfluh (Sucheinsatz)', start:'hohenems', end:'kanisfluh', difficulty:'medium',
waypoints:['hohenems','dornbirn','egg','bezau','mellau','kanisfluh'],
desc:'Vermisstensuche am Kanisfluh. Route über den Bregenzerwald, dann Anflug zum Bergmassiv.', reason:'Kanisfluh ist isoliertes Massiv im Bregenzerwald'},
{id:30, name:'Hohenems → Riezlern (Kleinwalsertal)', start:'hohenems', end:'riezlern', difficulty:'hard',
waypoints:['hohenems','dornbirn','egg','bezau','au','schroecken','warth','riezlern'],
desc:'Einsatz im Kleinwalsertal. Das Tal ist nur von Deutschland oder per Luft erreichbar — eine der anspruchsvollsten Routen Vorarlbergs.', reason:'Funktionale Exklave — Luftweg einzige österreichische Verbindung', region:'vlbg'},
// === TIROL-ROUTEN (3160) ===
// Von C1 Innsbruck
{id:31, name:'Innsbruck → Sölden (Skiunfall)', start:'innsbruck_c1', end:'skiunfall_soelden', difficulty:'medium', region:'tirol',
waypoints:['innsbruck_c1','telfs','oetz','soelden','skiunfall_soelden'],
desc:'Skiunfall im Skigebiet Sölden. Route durch das Inntal und Ötztal.', reason:'Ötztal nur von Norden erreichbar'},
{id:32, name:'Innsbruck → Großglockner (Bergunfall)', start:'innsbruck_c1', end:'bergunfall_glockner', difficulty:'hard', region:'tirol',
waypoints:['innsbruck_c1','hall','schwaz','jenbach','woergl','kitzbuehel_ort','st_johann','matrei','kals','bergunfall_glockner'],
desc:'Kletterunfall am Großglockner. Längste Route — quer durch Tirol bis Osttirol.', reason:'Großglockner liegt an der Grenze Tirol/Kärnten, nur über Felbertauern oder Inntal erreichbar'},
{id:33, name:'Innsbruck → Stubaier Gletscher', start:'innsbruck_c1', end:'stubaier_gl', difficulty:'medium', region:'tirol',
waypoints:['innsbruck_c1','fulpmes','neustift','stubaier_gl'],
desc:'Notfall am Stubaier Gletscher. Kurzer, aber hochalpiner Flug.', reason:'Stubaital ist Sackgasse — ein Weg rein, ein Weg raus'},
{id:34, name:'Innsbruck → Karwendel (Vermisste)', start:'innsbruck_c1', end:'vermisst_karwendel', difficulty:'medium', region:'tirol',
waypoints:['innsbruck_c1','hall','scharnitz','vermisst_karwendel'],
desc:'Vermisstensuche im Karwendelgebirge. Unwegsames Gelände nördlich von Innsbruck.', reason:'Karwendel ist das größte Naturschutzgebiet der Nordalpen'},
{id:35, name:'Innsbruck → Kufstein (Verkehr)', start:'innsbruck_c1', end:'kufstein', difficulty:'easy', region:'tirol',
waypoints:['innsbruck_c1','hall','schwaz','jenbach','woergl','kufstein'],
desc:'Schwerer Verkehrsunfall auf der A12 bei Kufstein. Einfacher Inntal-Flug.', reason:'Flaches Inntal, gute Sicht'},
{id:36, name:'Innsbruck → Brenner', start:'innsbruck_c1', end:'brenner_ort', difficulty:'easy', region:'tirol',
waypoints:['innsbruck_c1','steinach','brenner_ort'],
desc:'Einsatz am Brennerpass. Kurzer Flug durchs Wipptal.', reason:'Direkte Talroute nach Süden'},
{id:37, name:'Innsbruck → Obergurgl', start:'innsbruck_c1', end:'obergurgl', difficulty:'hard', region:'tirol',
waypoints:['innsbruck_c1','telfs','oetz','soelden','obergurgl'],
desc:'Notfall in Obergurgl. Tief ins hintere Ötztal — hochalpin.', reason:'Obergurgl liegt auf 1.930 m, eine der höchsten Dauersiedlungen Österreichs'},
{id:38, name:'Innsbruck → Mayrhofen', start:'innsbruck_c1', end:'mayrhofen', difficulty:'medium', region:'tirol',
waypoints:['innsbruck_c1','hall','schwaz','jenbach','zell_ziller','mayrhofen'],
desc:'Canyoning-Unfall bei Mayrhofen. Route durch Inntal und Zillertal.', reason:'Zillertal-Zugang über Jenbach'},
{id:39, name:'Innsbruck → Hintertux', start:'innsbruck_c1', end:'hintertux', difficulty:'hard', region:'tirol',
waypoints:['innsbruck_c1','hall','schwaz','jenbach','zell_ziller','mayrhofen','hintertux'],
desc:'Gletscherunfall am Hintertuxer Gletscher. Langer Flug bis ans Talende.', reason:'Tuxertal ist Sackgasse, Gletscher auf 3.250 m'},
{id:40, name:'Innsbruck → Seefeld', start:'innsbruck_c1', end:'seefeld', difficulty:'easy', region:'tirol',
waypoints:['innsbruck_c1','seefeld'],
desc:'Wanderunfall am Seefelder Plateau. Kurzer Flug.', reason:'Seefeld liegt nur 20 km nordwestlich von Innsbruck'},
{id:41, name:'Innsbruck → St. Anton (Lawine)', start:'innsbruck_c1', end:'lawine_arlberg', difficulty:'hard', region:'tirol',
waypoints:['innsbruck_c1','telfs','imst','landeck','st_anton','lawine_arlberg'],
desc:'Lawinenabgang bei St. Anton. Langer Flug durch das gesamte Oberinntal.', reason:'Arlberg nur über Inntal-Route erreichbar'},
{id:42, name:'Innsbruck → Reutte', start:'innsbruck_c1', end:'reutte', difficulty:'medium', region:'tirol',
waypoints:['innsbruck_c1','telfs','imst','reutte'],
desc:'Notfall im Außerfern. Route über den Fernpass.', reason:'Außerfern ist vom Rest Tirols durch Gebirge getrennt'},
{id:43, name:'Innsbruck → Inntal A12 (Verkehr)', start:'innsbruck_c1', end:'verkehr_inntal', difficulty:'easy', region:'tirol',
waypoints:['innsbruck_c1','hall','verkehr_inntal'],
desc:'Massenkarambolage auf der A12. Sehr kurzer Einsatz.', reason:'Direktflug im Inntal'},
{id:44, name:'Innsbruck → Hochwasser Inn', start:'innsbruck_c1', end:'hochwasser_inn', difficulty:'medium', region:'tirol',
waypoints:['innsbruck_c1','telfs','imst','hochwasser_inn'],
desc:'Hochwasser am Inn bei Imst. Evakuierungseinsatz.', reason:'Inntal-Route, Fluss folgen'},
{id:45, name:'Innsbruck → Kitzbühel', start:'innsbruck_c1', end:'kitzbuehel_ort', difficulty:'medium', region:'tirol',
waypoints:['innsbruck_c1','hall','schwaz','jenbach','woergl','kitzbuehel_ort'],
desc:'Einsatz in Kitzbühel. Inntal-Route über Wörgl.', reason:'Kitzbühel liegt südlich des Inntals'},
// Von C5 Zams
{id:46, name:'Zams → St. Anton (Lawine)', start:'zams_c5', end:'lawine_arlberg', difficulty:'medium', region:'tirol',
waypoints:['zams_c5','landeck','st_anton','lawine_arlberg'],
desc:'Lawinenunfall bei St. Anton. Kurzer Flug von Zams über Landeck.', reason:'C5 ist die nächste Basis zum Arlberg'},
{id:47, name:'Zams → Sölden', start:'zams_c5', end:'soelden', difficulty:'medium', region:'tirol',
waypoints:['zams_c5','imst','oetz','soelden'],
desc:'Skiunfall in Sölden. Route über Imst ins Ötztal.', reason:'Ötztal-Zugang über Imst'},
{id:48, name:'Zams → Ischgl', start:'zams_c5', end:'sillian', difficulty:'hard', region:'tirol',
waypoints:['zams_c5','landeck','sillian'],
desc:'Notfall im Paznauntal. Enges Hochgebirgstal.', reason:'Paznauntal ist eine der engsten Talrouten Tirols'},
{id:49, name:'Zams → Reutte', start:'zams_c5', end:'reutte', difficulty:'medium', region:'tirol',
waypoints:['zams_c5','imst','reutte'],
desc:'Einsatz im Außerfern. Route über Imst und Fernpass.', reason:'Außerfern-Zugang'},
{id:50, name:'Zams → Innsbruck', start:'zams_c5', end:'innsbruck_c1', difficulty:'easy', region:'tirol',
waypoints:['zams_c5','imst','telfs','innsbruck_c1'],
desc:'Patiententransport nach Innsbruck. Inntal-Flug.', reason:'Inntal-Standardroute'},
// Von C4 Kitzbühel
{id:51, name:'Kitzbühel → Mayrhofen', start:'kitzbuehel_c4', end:'mayrhofen', difficulty:'medium', region:'tirol',
waypoints:['kitzbuehel_c4','woergl','jenbach','zell_ziller','mayrhofen'],
desc:'Bergunfall bei Mayrhofen. Route über das Inntal ins Zillertal.', reason:'Zillertal-Zugang über Jenbach'},
{id:52, name:'Kitzbühel → Kufstein', start:'kitzbuehel_c4', end:'kufstein', difficulty:'easy', region:'tirol',
waypoints:['kitzbuehel_c4','woergl','kufstein'],
desc:'Verkehrsunfall bei Kufstein. Kurzer Inntal-Flug.', reason:'Direkter Inntal-Flug'},
{id:53, name:'Kitzbühel → St. Johann', start:'kitzbuehel_c4', end:'st_johann', difficulty:'easy', region:'tirol',
waypoints:['kitzbuehel_c4','st_johann'],
desc:'Notfall in St. Johann. Kürzeste Route.', reason:'Nachbarort'},
{id:54, name:'Kitzbühel → Hintertux', start:'kitzbuehel_c4', end:'hintertux', difficulty:'hard', region:'tirol',
waypoints:['kitzbuehel_c4','woergl','jenbach','zell_ziller','mayrhofen','hintertux'],
desc:'Gletscherunfall Hintertux. Lange Route durchs gesamte Zillertal.', reason:'Tuxertal nur über Zillertal erreichbar'},
// Von C7 Lienz
{id:55, name:'Lienz → Großglockner', start:'lienz_c7', end:'bergunfall_glockner', difficulty:'hard', region:'tirol',
waypoints:['lienz_c7','matrei','kals','bergunfall_glockner'],
desc:'Kletterunfall am Großglockner. Route durch das Iseltal.', reason:'Kürzeste Route zum Glockner von Süden'},
{id:56, name:'Lienz → Sillian', start:'lienz_c7', end:'sillian', difficulty:'easy', region:'tirol',
waypoints:['lienz_c7','sillian'],
desc:'Einsatz bei Sillian nahe der italienischen Grenze. Kurzer Drautal-Flug.', reason:'Drautal-Route Richtung Osten'},
{id:57, name:'Lienz → Matrei', start:'lienz_c7', end:'matrei', difficulty:'easy', region:'tirol',
waypoints:['lienz_c7','matrei'],
desc:'Notfall in Matrei. Direkter Flug ins Iseltal.', reason:'Iseltal-Route'},
{id:58, name:'Lienz → Kals (Bergrettung)', start:'lienz_c7', end:'kals', difficulty:'medium', region:'tirol',
waypoints:['lienz_c7','matrei','kals'],
desc:'Bergrettung in Kals am Großglockner. Route über Matrei.', reason:'Kalser Tal nur über Matrei erreichbar'},
{id:59, name:'Lienz → Kitzbühel (Transport)', start:'lienz_c7', end:'kitzbuehel_ort', difficulty:'hard', region:'tirol',
waypoints:['lienz_c7','matrei','st_johann','kitzbuehel_ort'],
desc:'Patiententransport nach Kitzbühel. Route über den Felbertauern.', reason:'Felbertauernroute verbindet Ost- und Nordtirol'},
{id:60, name:'Lienz → Innsbruck (Intensivtransport)', start:'lienz_c7', end:'innsbruck_c1', difficulty:'hard', region:'tirol',
waypoints:['lienz_c7','matrei','st_johann','kitzbuehel_ort','woergl','jenbach','schwaz','hall','innsbruck_c1'],
desc:'Intensivtransport nach Innsbruck. Die längste Route — quer durch ganz Tirol.', reason:'Osttirol hat kein eigenes Traumazentrum'},
];
// Farben nach Schwierigkeit
var COLORS = {easy:'#5a8a5e', medium:'#c4a35a', hard:'#c85c4a'};
var routeLayers = [];
function buildSelect(region) {
var sel = document.getElementById('route-select');
sel.innerHTML = '';
var filtered = region === 'all' ? ROUTES : ROUTES.filter(function(r){return r.region===region;});
filtered.forEach(function(r) {
var opt = document.createElement('option');
opt.value = r.id;
var badge = r.difficulty === 'easy' ? '🟢' : r.difficulty === 'medium' ? '🟡' : '🔴';
opt.textContent = badge + ' #' + r.id + ' ' + r.name;
sel.appendChild(opt);
});
}
function showRoute() {
var id = parseInt(document.getElementById('route-select').value);
var r = ROUTES.find(function(x){return x.id===id;});
if (!r) return;
// Clear old
routeLayers.forEach(function(l){map.removeLayer(l);});
routeLayers = [];
// Build points
var latlngs = r.waypoints.map(function(wpId){
var wp = WP[wpId];
return wp ? [wp.lat, wp.lon] : null;
}).filter(Boolean);
// Fit map
if (latlngs.length > 0) map.fitBounds(L.latLngBounds(latlngs).pad(0.15));
// Draw line
var line = L.polyline(latlngs, {color:COLORS[r.difficulty], weight:4, opacity:0.8, dashArray:r.difficulty==='hard'?'8,6':null}).addTo(map);
routeLayers.push(line);
// Waypoint markers
r.waypoints.forEach(function(wpId, i) {
var wp = WP[wpId];
if (!wp) return;
var isStart = i === 0;
var isEnd = i === r.waypoints.length - 1;
var cls = isStart ? 'wp-marker start' : isEnd ? 'wp-marker end' : 'wp-marker';
var label = isStart ? '🚁' : isEnd ? '🎯' : (i);
var size = (isStart||isEnd) ? 28 : 22;
var m = L.marker([wp.lat, wp.lon], {
icon: L.divIcon({className:'', html:'<div class="'+cls+'">'+label+'</div>', iconSize:[size,size], iconAnchor:[size/2,size/2]}),
zIndexOffset: (isStart||isEnd) ? 1000 : 500
}).addTo(map).bindPopup('<strong>'+wp.name+'</strong><br><span style="font-size:10px;color:#8a8a8a">Waypoint '+(i+1)+' von '+r.waypoints.length+'</span>');
routeLayers.push(m);
// Label
var lbl = L.marker([wp.lat, wp.lon], {
icon: L.divIcon({className:'wp-label', html:wp.name, iconSize:[120,14], iconAnchor:[-14,7]}),
interactive:false
}).addTo(map);
routeLayers.push(lbl);
});
// Description
var diffLabel = r.difficulty==='easy'?'Einfach':r.difficulty==='medium'?'Mittel':'Schwierig';
var diffBadge = '<span class="badge badge-'+r.difficulty+'">'+diffLabel+'</span>';
document.getElementById('route-desc').innerHTML =
'<h3>#'+r.id+' '+r.name+' '+diffBadge+'</h3>'
+'<p>'+r.desc+'</p>'
+'<div class="meta">Grund für diese Route: <strong>'+r.reason+'</strong> · '+r.waypoints.length+' Wegpunkte</div>';
}
function filterRoutes() {
var region = document.getElementById('region-select').value;
buildSelect(region);
showRoute();
}
buildSelect('all');
showRoute();
</script>
</body>
</html>