feat: Karte reagiert auf Karussell-Wechsel
- Map-Instanz wird einmalig erstellt, Marker dynamisch gewechselt - data-lage Attribute auf Carousel-Cards fuer Lagen-Zuordnung - Bei Lage mit Daten: Marker + Legende angezeigt - Bei Platzhalter: Karte ausgeblendet, 'Kartendaten folgen' - Zukunftssicher: Neue Lagen brauchen nur data-lage + summary.json Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -179,6 +179,10 @@ a { color:inherit; text-decoration:none; }
|
|||||||
/* ==================== MAP ==================== */
|
/* ==================== MAP ==================== */
|
||||||
.map-section { margin-top:48px; }
|
.map-section { margin-top:48px; }
|
||||||
.map-title { font-size:1.1rem; font-weight:600; color:var(--navy); margin-bottom:16px; text-align:center; }
|
.map-title { font-size:1.1rem; font-weight:600; color:var(--navy); margin-bottom:16px; text-align:center; }
|
||||||
|
.map-section { transition:opacity 0.3s; }
|
||||||
|
.map-section.map-hidden #map-container { display:none; }
|
||||||
|
.map-section.map-hidden .map-empty { display:flex!important; }
|
||||||
|
.map-empty { display:none; align-items:center; justify-content:center; height:300px; border:2px dashed var(--gray-200); border-radius:var(--radius-lg); color:var(--gray-400); font-size:1rem; background:var(--white); }
|
||||||
#map-container { height:420px; border-radius:var(--radius-lg); overflow:hidden; box-shadow:var(--shadow); border:1px solid var(--gray-100); }
|
#map-container { height:420px; border-radius:var(--radius-lg); overflow:hidden; box-shadow:var(--shadow); border:1px solid var(--gray-100); }
|
||||||
|
|
||||||
/* Map pulse markers (exact lagebild style) */
|
/* Map pulse markers (exact lagebild style) */
|
||||||
|
|||||||
@@ -163,7 +163,7 @@
|
|||||||
<button class="carousel-arrow carousel-next" aria-label="Nächste Lage">›</button>
|
<button class="carousel-arrow carousel-next" aria-label="Nächste Lage">›</button>
|
||||||
<div class="carousel-track" id="carousel">
|
<div class="carousel-track" id="carousel">
|
||||||
<!-- Iran Card -->
|
<!-- Iran Card -->
|
||||||
<div class="carousel-card card-live active" data-index="0">
|
<div class="carousel-card card-live active" data-index="0" data-lage="iran-konflikt">
|
||||||
<div class="demo-badge">LIVE</div>
|
<div class="demo-badge">LIVE</div>
|
||||||
<h3 class="demo-title">Iran-Konflikt</h3>
|
<h3 class="demo-title">Iran-Konflikt</h3>
|
||||||
|
|
||||||
@@ -173,13 +173,13 @@
|
|||||||
<a href="/lagen/iran-konflikt/" class="btn btn-primary btn-block">Vollständiges Lagebild öffnen</a>
|
<a href="/lagen/iran-konflikt/" class="btn btn-primary btn-block">Vollständiges Lagebild öffnen</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Placeholder 2 -->
|
<!-- Placeholder 2 -->
|
||||||
<div class="carousel-card card-placeholder" data-index="1">
|
<div class="carousel-card card-placeholder" data-index="1" data-lage="">
|
||||||
<div class="demo-badge badge-soon">Demnächst</div>
|
<div class="demo-badge badge-soon">Demnächst</div>
|
||||||
<h3 class="demo-title placeholder-title">Weitere Lage</h3>
|
<h3 class="demo-title placeholder-title">Weitere Lage</h3>
|
||||||
<p class="placeholder-text">In Vorbereitung</p>
|
<p class="placeholder-text">In Vorbereitung</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- Placeholder 3 -->
|
<!-- Placeholder 3 -->
|
||||||
<div class="carousel-card card-placeholder" data-index="2">
|
<div class="carousel-card card-placeholder" data-index="2" data-lage="">
|
||||||
<div class="demo-badge badge-soon">Demnächst</div>
|
<div class="demo-badge badge-soon">Demnächst</div>
|
||||||
<h3 class="demo-title placeholder-title">Weitere Lage</h3>
|
<h3 class="demo-title placeholder-title">Weitere Lage</h3>
|
||||||
<p class="placeholder-text">In Vorbereitung</p>
|
<p class="placeholder-text">In Vorbereitung</p>
|
||||||
@@ -193,9 +193,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Map -->
|
<!-- Map -->
|
||||||
<div class="map-section">
|
<div class="map-section" id="map-section">
|
||||||
<h3 class="map-title">Geografische Verortung der Meldungen</h3>
|
<h3 class="map-title" id="map-title">Geografische Verortung der Meldungen</h3>
|
||||||
<div id="map-container"></div>
|
<div id="map-container"></div>
|
||||||
|
<div class="map-empty" id="map-empty" style="display:none">Kartendaten folgen</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -71,6 +71,12 @@
|
|||||||
|
|
||||||
if (videos.length > 1) startRotation();
|
if (videos.length > 1) startRotation();
|
||||||
|
|
||||||
|
/* ==================== MAP STATE ==================== */
|
||||||
|
var mapInstance = null;
|
||||||
|
var markerLayer = null;
|
||||||
|
var legendControl = null;
|
||||||
|
var lageData = {};
|
||||||
|
|
||||||
/* ==================== 3D CAROUSEL ==================== */
|
/* ==================== 3D CAROUSEL ==================== */
|
||||||
var cards = document.querySelectorAll('.carousel-card');
|
var cards = document.querySelectorAll('.carousel-card');
|
||||||
var dots = document.querySelectorAll('.carousel-dot');
|
var dots = document.querySelectorAll('.carousel-dot');
|
||||||
@@ -88,6 +94,16 @@
|
|||||||
dots.forEach(function (dot, i) {
|
dots.forEach(function (dot, i) {
|
||||||
dot.classList.toggle('active', i === idx);
|
dot.classList.toggle('active', i === idx);
|
||||||
});
|
});
|
||||||
|
// Update map based on active Lage
|
||||||
|
var lage = cards[idx].getAttribute('data-lage');
|
||||||
|
var mapSection = document.getElementById('map-section');
|
||||||
|
if (lage && lageData[lage]) {
|
||||||
|
mapSection.classList.remove('map-hidden');
|
||||||
|
showMarkers(lageData[lage].locations, lageData[lage].category_labels);
|
||||||
|
} else {
|
||||||
|
if (mapSection) mapSection.classList.add('map-hidden');
|
||||||
|
clearMarkers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cards.forEach(function (card, i) {
|
cards.forEach(function (card, i) {
|
||||||
@@ -188,37 +204,43 @@ function mdToHtml(md) {
|
|||||||
excerptEl.innerHTML = mdToHtml(data.zusammenfassung);
|
excerptEl.innerHTML = mdToHtml(data.zusammenfassung);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map
|
// Store data and init map
|
||||||
if (data.locations && data.locations.length > 0) {
|
lageData['iran-konflikt'] = {
|
||||||
initMap(data.locations, data.category_labels || {});
|
locations: data.locations || [],
|
||||||
}
|
category_labels: data.category_labels || {}
|
||||||
|
};
|
||||||
|
createMap();
|
||||||
|
showMarkers(data.locations || [], data.category_labels || {});
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== LEAFLET MAP (exact lagebild style) ==================== */
|
/* ==================== LEAFLET MAP ==================== */
|
||||||
function initMap(locations, apiLabels) {
|
function clearMarkers() {
|
||||||
|
if (markerLayer) markerLayer.clearLayers();
|
||||||
|
if (legendControl && mapInstance) { mapInstance.removeControl(legendControl); legendControl = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMap() {
|
||||||
|
if (mapInstance) return;
|
||||||
var mapEl = document.getElementById('map-container');
|
var mapEl = document.getElementById('map-container');
|
||||||
if (!mapEl || typeof L === 'undefined') return;
|
if (!mapEl || typeof L === 'undefined') return;
|
||||||
|
|
||||||
var map = L.map(mapEl, {
|
mapInstance = L.map(mapEl, {
|
||||||
center: [33.0, 48.0],
|
center: [33.0, 48.0], zoom: 5, zoomControl: true, scrollWheelZoom: true,
|
||||||
zoom: 5,
|
minZoom: 2, maxBounds: [[-85, -180], [85, 180]], maxBoundsViscosity: 1.0
|
||||||
zoomControl: true,
|
|
||||||
scrollWheelZoom: true,
|
|
||||||
minZoom: 2,
|
|
||||||
maxBounds: [[-85, -180], [85, 180]],
|
|
||||||
maxBoundsViscosity: 1.0
|
|
||||||
});
|
});
|
||||||
|
|
||||||
L.tileLayer('https://tile.openstreetmap.de/{z}/{x}/{y}.png', {
|
L.tileLayer('https://tile.openstreetmap.de/{z}/{x}/{y}.png', {
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||||
maxZoom: 19,
|
maxZoom: 19, noWrap: true
|
||||||
noWrap: true
|
}).addTo(mapInstance);
|
||||||
}).addTo(map);
|
|
||||||
|
markerLayer = L.layerGroup().addTo(mapInstance);
|
||||||
|
setTimeout(function () { mapInstance.invalidateSize(); }, 500);
|
||||||
|
}
|
||||||
|
|
||||||
// Exact same pulse icon as lagebild
|
|
||||||
function pulseIcon(color) {
|
function pulseIcon(color) {
|
||||||
return L.divIcon({
|
return L.divIcon({
|
||||||
className: '',
|
className: '',
|
||||||
@@ -227,12 +249,15 @@ function mdToHtml(md) {
|
|||||||
+ '<div class="pulse-marker-ring" style="border-color:' + color + '"></div>'
|
+ '<div class="pulse-marker-ring" style="border-color:' + color + '"></div>'
|
||||||
+ '<div class="pulse-marker-dot" style="background:' + color + ';box-shadow:0 0 10px ' + color + '"></div>'
|
+ '<div class="pulse-marker-dot" style="background:' + color + ';box-shadow:0 0 10px ' + color + '"></div>'
|
||||||
+ '</div>',
|
+ '</div>',
|
||||||
iconSize: [20, 20],
|
iconSize: [20, 20], iconAnchor: [10, 10], popupAnchor: [0, -12]
|
||||||
iconAnchor: [10, 10],
|
|
||||||
popupAnchor: [0, -12]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showMarkers(locations, apiLabels) {
|
||||||
|
if (!mapInstance) createMap();
|
||||||
|
clearMarkers();
|
||||||
|
|
||||||
|
|
||||||
var categoryColors = {
|
var categoryColors = {
|
||||||
primary: '#ef4444',
|
primary: '#ef4444',
|
||||||
secondary: '#f59e0b',
|
secondary: '#f59e0b',
|
||||||
@@ -266,7 +291,7 @@ function mdToHtml(md) {
|
|||||||
popup += '<br><span style="font-size:0.85rem;color:#8896AB;">' + (loc.article_count || 0) + ' Artikel</span>';
|
popup += '<br><span style="font-size:0.85rem;color:#8896AB;">' + (loc.article_count || 0) + ' Artikel</span>';
|
||||||
|
|
||||||
L.marker([loc.lat, loc.lon], { icon: pulseIcon(color) })
|
L.marker([loc.lat, loc.lon], { icon: pulseIcon(color) })
|
||||||
.addTo(map)
|
.addTo(markerLayer)
|
||||||
.bindPopup(popup);
|
.bindPopup(popup);
|
||||||
bounds.push([loc.lat, loc.lon]);
|
bounds.push([loc.lat, loc.lon]);
|
||||||
});
|
});
|
||||||
@@ -285,13 +310,13 @@ function mdToHtml(md) {
|
|||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
legend.addTo(map);
|
legend.addTo(mapInstance);
|
||||||
|
|
||||||
if (bounds.length > 0) {
|
if (bounds.length > 0) {
|
||||||
map.fitBounds(bounds, { padding: [30, 30], maxZoom: 7 });
|
mapInstance.fitBounds(bounds, { padding: [30, 30], maxZoom: 7 });
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(function () { map.invalidateSize(); }, 500);
|
setTimeout(function () { mapInstance.invalidateSize(); }, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== INIT ==================== */
|
/* ==================== INIT ==================== */
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren