Files
geograsim/App/pages/heli.php
T
Adminator 9a61f55cb1 Atlas: Infrastruktur + Team-Konventionen + Sprachregel Lernarbeit
- Design-System (assets/css/design-system.css) mit 21 Komponenten,
  iPad-Responsive-Breakpoints, Touch-Ziele 36px, Music-Player,
  Glossar-Tooltips
- Templates (sims/template.html + student/teacher-Dashboard)
- Docs: module-interface.md (inkl. 4a Sprachregel, 4b Leichte Sprache,
  4c iPad), content-architecture.md, crash-recovery.md, music-registry.md
- Admin-Infrastruktur: admin-modules.html + api/admin-modules.php
  (Titel, Emoji, Bild, Status, Dauer, Alter pro Modul)
- Inbox-System: _inbox/README.md + _status.md fuer Atlas + Briefings
  an Klima, Glossar, Lehrplan, Fluss
- Zentrale SFX-Pipeline (scripts/generate-sounds.py)
- DALL-E-Bilder: 8 Badges + 5 Glossar-Repraesentationsbilder (Querformat)
- Logo + Inter-Font lokal
- PHP-APIs: admin, glossar, levels, licenses, progress, waypoints,
  assignments, profile, tickets
- Spielsprache entfernt (admin-modules, admin-levels, schueler)
- Landing-Page-Bearbeitungen (Boote sichtbarer, Button-Hintergrund)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:51:14 +02:00

122 lines
6.0 KiB
PHP

<?php
/**
* Heli-Übersichtskarte — Waypoints aus der DB
*/
require_once __DIR__ . '/../php/config/app.php';
require_once __DIR__ . '/../php/config/db.php';
$db = getDB();
$waypoints = $db->query("SELECT wp_key, name, lat, lon, region, wp_type, info FROM geo_waypoints ORDER BY region, name")->fetchAll(PDO::FETCH_ASSOC);
// Als JSON für JavaScript
$wpJson = json_encode($waypoints, JSON_UNESCAPED_UNICODE);
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Helikopter-Übersichtskarte</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="assets/fonts/inter.css">
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;overflow:hidden;height:100vh;background:#e8e4d8}
#map{width:100%;height:100vh}
.marker-circle{width:26px;height:26px;background:#fff;border:2.5px solid #1f4e5a;border-radius:50%;box-shadow:0 2px 6px rgba(0,0,0,.3);display:flex;align-items:center;justify-content:center;font-size:13px;line-height:1}
.marker-circle.capital{border-color:#e8833a;width:30px;height:30px;font-size:15px}
.marker-circle.peak{border-color:#5a8a5e;width:24px;height:24px;font-size:12px}
.marker-circle.base{border-color:#d4a017;width:30px;height:30px;font-size:16px}
.marker-circle.base-inactive{border-color:#888;width:22px;height:22px;font-size:11px;opacity:.7}
.wp-pill{font-family:'Inter',sans-serif;font-weight:700;font-size:11px;white-space:nowrap;padding:3px 9px;border-radius:5px;box-shadow:0 1px 4px rgba(0,0,0,.12);display:flex;align-items:center;height:20px}
.wp-pill.city{background:rgba(218,232,236,.94);color:#1f4e5a;border-bottom:2.5px solid #4a7c8a}
.wp-pill.capital{background:rgba(232,200,170,.92);color:#e8833a;border-bottom:2.5px solid #e8833a}
.wp-pill.peak{background:rgba(220,234,221,.94);color:#3a6b3e;border-bottom:2.5px solid #5a8a5e}
.wp-pill.base{background:rgba(255,255,255,.92);color:#9a7800;border-left:3px solid #d4a017;font-size:10px}
.wp-pill .pop{font-size:8px;font-weight:500;color:#8a8a8a;margin-left:4px}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// Waypoints direkt aus der DB (PHP-injiziert)
var DB_WAYPOINTS = <?= $wpJson ?>;
var map = L.map('map', {zoomControl:false, maxBoundsViscosity:1.0, minZoom:7, maxZoom:15})
.setView([47.4, 13.2], 8);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution:'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>', maxZoom:18
}).addTo(map);
L.control.zoom({position:'topright'}).addTo(map);
L.control.scale({position:'bottomleft', metric:true, imperial:false, maxWidth:200}).addTo(map);
// Render alle Waypoints nach Typ
DB_WAYPOINTS.forEach(function(w) {
var lat = parseFloat(w.lat), lon = parseFloat(w.lon);
var icon, pillClass, pillHtml, popupHtml, size;
if (w.wp_type === 'base') {
size = 30;
icon = '<div class="marker-circle base">🚁</div>';
pillClass = 'wp-pill base';
pillHtml = w.name;
popupHtml = '<div style="font-family:Inter,sans-serif;text-align:center;padding:4px">'
+'<div style="font-size:2rem">🚁</div>'
+'<div style="font-size:14px;font-weight:800;color:#1f4e5a">'+w.name+'</div>'
+(w.info?'<div style="font-size:11px;color:#8a8a8a">'+w.info+'</div>':'')
+'</div>';
} else if (w.wp_type === 'city') {
size = 26;
icon = '<div class="marker-circle">🏙️</div>';
pillClass = 'wp-pill city';
pillHtml = w.name;
popupHtml = '<div style="font-family:Inter,sans-serif;text-align:center;padding:4px">'
+'<div style="font-size:16px;font-weight:900;color:#1f4e5a">'+w.name+'</div>'
+'<div style="font-size:10px;color:#8a8a8a">'+w.region+'</div>'
+(w.info?'<div style="font-size:11px;color:#4a4a4a;margin-top:4px">'+w.info+'</div>':'')
+'</div>';
} else if (w.wp_type === 'peak') {
size = 24;
icon = '<div class="marker-circle peak">🏔️</div>';
pillClass = 'wp-pill peak';
pillHtml = w.name + (w.info?' <span class="pop">'+w.info+'</span>':'');
popupHtml = '<div style="font-family:Inter,sans-serif;text-align:center">'
+'<div style="font-size:2rem">🏔️</div>'
+'<div style="font-size:15px;font-weight:900;color:#3a6b3e">'+w.name+'</div>'
+(w.info?'<div style="font-size:13px;color:#1f4e5a;font-weight:800">'+w.info+'</div>':'')
+'</div>';
} else if (w.wp_type === 'village') {
size = 20;
icon = '<div style="width:16px;height:16px;background:#fff;border:2px solid #8a8a8a;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.2)"></div>';
pillClass = null; // Kein Pill für kleine Dörfer
popupHtml = '<div style="font-family:Inter,sans-serif"><strong>'+w.name+'</strong>'
+(w.info?'<br><span style="font-size:11px;color:#8a8a8a">'+w.info+'</span>':'')+'</div>';
} else {
size = 18;
icon = '<div style="width:14px;height:14px;background:#c85c4a;border:2px solid #fff;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.2)"></div>';
pillClass = null;
popupHtml = '<div style="font-family:Inter,sans-serif"><strong>'+w.name+'</strong>'
+(w.info?'<br><span style="font-size:11px;color:#8a8a8a">'+w.info+'</span>':'')+'</div>';
}
// Marker
L.marker([lat, lon], {
icon: L.divIcon({className:'', html:icon, iconSize:[size,size], iconAnchor:[size/2,size/2]}),
zIndexOffset: w.wp_type==='base'?1000:w.wp_type==='city'?500:w.wp_type==='peak'?300:100
}).addTo(map).bindPopup(popupHtml, {maxWidth:260});
// Pill (nur für Basen, Städte, Gipfel)
if (pillClass) {
L.marker([lat, lon], {
icon: L.divIcon({className:pillClass, html:pillHtml, iconSize:[140,20], iconAnchor:[-14,10]}),
interactive:false, zIndexOffset: w.wp_type==='base'?900:w.wp_type==='city'?400:200
}).addTo(map);
}
});
</script>
</body>
</html>