GEOINT-Modus: Experimentelle taktische Kartenansicht mit Echtzeit-Datenlayern
Neuer experimenteller GEOINT-Modus per Checkbox auf der Karten-Kachel: - Satellitenbilder (Esri World Imagery) statt OSM-Strassenkarte - Echtzeit-Flugverkehr (airplanes.live via Backend-Proxy, 15s Refresh) - Erdbeben-Layer (USGS M2.5+, pulsierende Kreise nach Magnitude) - GDELT Nachrichten (geokodierte Echtzeit-News, Cluster-Darstellung) - Heatmap-Visualisierung der Artikel-Standorte (Leaflet.heat) - Timeline-Slider fuer zeitliche Filterung der Artikel-Marker - Koordinatenanzeige (Lat/Lon unter Mauszeiger) - Distanzmessung (Klick-zu-Klick mit km-Anzeige) - Taktisches Styling (dunkle Tonung, gruene Akzente, Scanlines) Neue Dateien: geoint.js, geoint.css, routers/geoint.py Inspiriert von WorldView/Gods Eye Konzept, komplett eigenentwickelt.
Dieser Commit ist enthalten in:
308
src/static/css/geoint.css
Normale Datei
308
src/static/css/geoint.css
Normale Datei
@@ -0,0 +1,308 @@
|
||||
/* =====================================================================
|
||||
GEOINT-Modus: Taktische Kartenansicht mit Echtzeit-Datenlayern
|
||||
===================================================================== */
|
||||
|
||||
/* --- Toggle-Checkbox im Card-Header --- */
|
||||
.geoint-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.geoint-toggle input[type="checkbox"] {
|
||||
accent-color: #00ff88;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.geoint-toggle-label {
|
||||
font-family: var(--font-mono, 'Courier New', monospace);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-secondary);
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.geoint-toggle input:checked + .geoint-toggle-label {
|
||||
color: #00ff88;
|
||||
text-shadow: 0 0 6px rgba(0, 255, 136, 0.4);
|
||||
}
|
||||
|
||||
/* --- Taktisches Styling (aktiv) --- */
|
||||
.geoint-active .leaflet-tile-pane {
|
||||
filter: brightness(0.88) contrast(1.08) saturate(0.85);
|
||||
transition: filter 0.4s ease;
|
||||
}
|
||||
.geoint-active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 800;
|
||||
background: repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 3px,
|
||||
rgba(0, 255, 100, 0.012) 3px,
|
||||
rgba(0, 255, 100, 0.012) 6px
|
||||
);
|
||||
}
|
||||
.geoint-active .map-empty { display: none !important; }
|
||||
|
||||
/* Gruener Akzent am Card-Header wenn aktiv */
|
||||
.map-card.geoint-card-active .card-header {
|
||||
border-bottom: 2px solid rgba(0, 255, 136, 0.25);
|
||||
}
|
||||
|
||||
/* --- Sub-Layer Control Panel --- */
|
||||
.geoint-sub-control {
|
||||
background: rgba(11, 17, 33, 0.92);
|
||||
border: 1px solid rgba(0, 255, 136, 0.2);
|
||||
border-radius: 6px;
|
||||
padding: 10px 12px;
|
||||
min-width: 170px;
|
||||
backdrop-filter: blur(8px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
.geoint-sub-control h4 {
|
||||
font-family: var(--font-mono, 'Courier New', monospace);
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
text-transform: uppercase;
|
||||
color: #00ff88;
|
||||
margin: 0 0 8px 0;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid rgba(0, 255, 136, 0.15);
|
||||
}
|
||||
.geoint-sub-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 3px 0;
|
||||
}
|
||||
.geoint-sub-item input[type="checkbox"] {
|
||||
accent-color: #00ff88;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.geoint-sub-item label {
|
||||
font-family: var(--font-mono, 'Courier New', monospace);
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.geoint-sub-item label .geoint-dot {
|
||||
display: inline-block;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
margin-right: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.geoint-dot-flights { background: #00ff88; }
|
||||
.geoint-dot-quakes { background: #ff4444; }
|
||||
.geoint-dot-gdelt { background: #44aaff; }
|
||||
.geoint-dot-heatmap { background: #ff8800; }
|
||||
.geoint-dot-coords { background: #aaaaaa; }
|
||||
.geoint-dot-distance { background: #ffdd00; }
|
||||
.geoint-sub-separator {
|
||||
height: 1px;
|
||||
background: rgba(0, 255, 136, 0.1);
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
/* --- Flugzeug-Icons --- */
|
||||
.geoint-aircraft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: filter 0.15s;
|
||||
}
|
||||
.geoint-aircraft:hover {
|
||||
filter: drop-shadow(0 0 6px #00ff88);
|
||||
}
|
||||
.geoint-aircraft svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
/* --- Erdbeben Puls-Animation --- */
|
||||
.geoint-quake-marker {
|
||||
animation: geoint-pulse 2.5s ease-in-out infinite;
|
||||
}
|
||||
@keyframes geoint-pulse {
|
||||
0%, 100% { opacity: 0.7; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* --- GDELT Nachrichtenmarker --- */
|
||||
.geoint-gdelt-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: rgba(68, 170, 255, 0.85);
|
||||
border: 1.5px solid rgba(68, 170, 255, 1);
|
||||
border-radius: 50%;
|
||||
font-size: 10px;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 0 4px rgba(68, 170, 255, 0.5);
|
||||
}
|
||||
|
||||
/* --- Koordinatenanzeige --- */
|
||||
.geoint-coord-display {
|
||||
background: rgba(11, 17, 33, 0.88);
|
||||
border: 1px solid rgba(0, 255, 136, 0.2);
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
font-family: var(--font-mono, 'Courier New', monospace);
|
||||
font-size: 11px;
|
||||
color: #00ff88;
|
||||
letter-spacing: 0.5px;
|
||||
white-space: nowrap;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
/* --- Distanzmessung --- */
|
||||
.geoint-distance-label {
|
||||
background: rgba(11, 17, 33, 0.9);
|
||||
border: 1px solid rgba(255, 221, 0, 0.3);
|
||||
border-radius: 3px;
|
||||
padding: 2px 6px;
|
||||
font-family: var(--font-mono, 'Courier New', monospace);
|
||||
font-size: 10px;
|
||||
color: #ffdd00;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* --- Timeline-Slider --- */
|
||||
.geoint-timeline {
|
||||
display: none;
|
||||
padding: 6px 12px 8px;
|
||||
background: rgba(11, 17, 33, 0.6);
|
||||
border-top: 1px solid rgba(0, 255, 136, 0.1);
|
||||
}
|
||||
.geoint-active .geoint-timeline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.geoint-timeline input[type="range"] {
|
||||
flex: 1;
|
||||
height: 4px;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.geoint-timeline input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: #00ff88;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(11, 17, 33, 0.8);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 6px rgba(0, 255, 136, 0.5);
|
||||
}
|
||||
.geoint-timeline input[type="range"]::-moz-range-thumb {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: #00ff88;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(11, 17, 33, 0.8);
|
||||
cursor: pointer;
|
||||
}
|
||||
.geoint-timeline-label {
|
||||
font-family: var(--font-mono, 'Courier New', monospace);
|
||||
font-size: 10px;
|
||||
color: #00ff88;
|
||||
min-width: 90px;
|
||||
text-align: center;
|
||||
}
|
||||
.geoint-timeline-btn {
|
||||
background: none;
|
||||
border: 1px solid rgba(0, 255, 136, 0.3);
|
||||
border-radius: 3px;
|
||||
color: #00ff88;
|
||||
font-size: 11px;
|
||||
padding: 2px 6px;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-mono, 'Courier New', monospace);
|
||||
}
|
||||
.geoint-timeline-btn:hover {
|
||||
background: rgba(0, 255, 136, 0.1);
|
||||
}
|
||||
|
||||
/* --- Popup-Styling fuer GEOINT-Layer --- */
|
||||
.geoint-popup {
|
||||
font-family: var(--font-mono, 'Courier New', monospace);
|
||||
font-size: 11px;
|
||||
line-height: 1.5;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
.geoint-popup strong {
|
||||
color: #00ff88;
|
||||
}
|
||||
.geoint-popup .geoint-popup-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.geoint-popup .geoint-popup-key {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
/* --- Light Theme Overrides --- */
|
||||
[data-theme="light"] .geoint-sub-control {
|
||||
background: rgba(240, 243, 248, 0.95);
|
||||
border-color: rgba(0, 160, 80, 0.25);
|
||||
}
|
||||
[data-theme="light"] .geoint-sub-control h4 {
|
||||
color: #008844;
|
||||
}
|
||||
[data-theme="light"] .geoint-sub-item label {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
[data-theme="light"] .geoint-coord-display {
|
||||
background: rgba(240, 243, 248, 0.92);
|
||||
color: #006633;
|
||||
border-color: rgba(0, 160, 80, 0.25);
|
||||
}
|
||||
[data-theme="light"] .geoint-timeline {
|
||||
background: rgba(240, 243, 248, 0.7);
|
||||
border-top-color: rgba(0, 160, 80, 0.15);
|
||||
}
|
||||
[data-theme="light"] .geoint-timeline input[type="range"]::-webkit-slider-thumb {
|
||||
background: #008844;
|
||||
}
|
||||
[data-theme="light"] .geoint-timeline-label {
|
||||
color: #006633;
|
||||
}
|
||||
[data-theme="light"] .geoint-toggle input:checked + .geoint-toggle-label {
|
||||
color: #008844;
|
||||
text-shadow: none;
|
||||
}
|
||||
[data-theme="light"] .geoint-active .leaflet-tile-pane {
|
||||
filter: brightness(0.95) contrast(1.05) saturate(0.9);
|
||||
}
|
||||
[data-theme="light"] .geoint-active::after {
|
||||
background: repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 3px,
|
||||
rgba(0, 100, 50, 0.008) 3px,
|
||||
rgba(0, 100, 50, 0.008) 6px
|
||||
);
|
||||
}
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren