Tutorial Karte: Echte Map in Kachel + Zwei-Step-Flow mit Legende
Kachel-Ansicht (Step 17): - Echte Leaflet-Map mit OSM-Tiles und 3 Markern direkt in der Kachel (statt grauem Platzhalter), gezoomt auf Hamburg - Orte einlesen + Vollbild-Buttons werden nacheinander gehighlightet - Erklaerung der Geoparsing-Funktion in der Bubble Vollbild-Ansicht (Step 18 - neu): - Oeffnet Karten-Vollbild, startet bei Europa-Zoom, fliegt auf Hamburg - Bubble erklaert Legende detailliert (Farben + Kategorien + Artikelanzahl) - Cursor besucht alle 3 Marker nacheinander, oeffnet jeweiliges Popup fuer 2.5s (Burchardkai -> Innenstadt -> Elbe) - Nach Demo: Weiter-Button erscheint Refactoring: - Marker-Erstellung und Legende in wiederverwendbare Methoden extrahiert (_createDemoMarkers, _addDemoLegend) - Gemeinsame Konstanten fuer Locations, Farben, Labels Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -764,7 +764,7 @@
|
|||||||
<script src="/static/js/api_network.js?v=20260316a"></script>
|
<script src="/static/js/api_network.js?v=20260316a"></script>
|
||||||
<script src="/static/js/network-graph.js?v=20260316a"></script>
|
<script src="/static/js/network-graph.js?v=20260316a"></script>
|
||||||
<script src="/static/js/app_network.js?v=20260316a"></script>
|
<script src="/static/js/app_network.js?v=20260316a"></script>
|
||||||
<script src="/static/js/tutorial.js?v=20260316v"></script>
|
<script src="/static/js/tutorial.js?v=20260316w"></script>
|
||||||
<script src="/static/js/chat.js?v=20260316f"></script>
|
<script src="/static/js/chat.js?v=20260316f"></script>
|
||||||
<script>document.addEventListener("DOMContentLoaded",function(){Chat.init();Tutorial.init()});</script>
|
<script>document.addEventListener("DOMContentLoaded",function(){Chat.init();Tutorial.init()});</script>
|
||||||
|
|
||||||
|
|||||||
@@ -254,23 +254,12 @@ const Tutorial = {
|
|||||||
var articleCount = document.getElementById('article-count');
|
var articleCount = document.getElementById('article-count');
|
||||||
if (articleCount) articleCount.textContent = '7 Einträge';
|
if (articleCount) articleCount.textContent = '7 Einträge';
|
||||||
|
|
||||||
// Karte: Stats setzen + Platzhalter anzeigen, echte Map erst im Vollbild-Step
|
// Karte: Echte Leaflet-Map in der Kachel initialisieren
|
||||||
var mapEmpty = document.getElementById('map-empty');
|
var mapEmpty = document.getElementById('map-empty');
|
||||||
if (mapEmpty) mapEmpty.style.display = 'none';
|
if (mapEmpty) mapEmpty.style.display = 'none';
|
||||||
var mapStats = document.getElementById('map-stats');
|
var mapStats = document.getElementById('map-stats');
|
||||||
if (mapStats) mapStats.textContent = '3 Orte / 9 Artikel';
|
if (mapStats) mapStats.textContent = '3 Orte / 9 Artikel';
|
||||||
var mapContainer = document.getElementById('map-container');
|
this._initDemoMapInTile();
|
||||||
if (mapContainer) {
|
|
||||||
var ph = document.createElement('div');
|
|
||||||
ph.className = 'tutorial-demo tutorial-map-placeholder';
|
|
||||||
ph.style.cssText = 'width:100%;height:100%;display:flex;align-items:center;justify-content:center;'
|
|
||||||
+ 'background:var(--bg-secondary);color:var(--text-secondary);font-size:13px;border-radius:var(--radius);';
|
|
||||||
ph.innerHTML = '<div style="text-align:center;">'
|
|
||||||
+ '<div style="font-size:40px;margin-bottom:12px;opacity:0.4;">🌎</div>'
|
|
||||||
+ '<div>3 Orte erkannt: Hamburg, Burchardkai, Elbe</div>'
|
|
||||||
+ '<div style="font-size:11px;margin-top:4px;opacity:0.6;">Karte wird im Vollbild-Schritt angezeigt</div></div>';
|
|
||||||
mapContainer.appendChild(ph);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Meta
|
// Meta
|
||||||
var metaUpdated = document.getElementById('meta-updated');
|
var metaUpdated = document.getElementById('meta-updated');
|
||||||
@@ -318,10 +307,8 @@ const Tutorial = {
|
|||||||
var mapStats = document.getElementById('map-stats');
|
var mapStats = document.getElementById('map-stats');
|
||||||
if (mapStats) mapStats.innerHTML = s.mapStats;
|
if (mapStats) mapStats.innerHTML = s.mapStats;
|
||||||
|
|
||||||
// Demo-Map und Platzhalter entfernen
|
// Demo-Map entfernen (Kachel + Fullscreen)
|
||||||
this._destroyDemoMap();
|
this._destroyDemoMap();
|
||||||
var mapPh = document.querySelector('.tutorial-map-placeholder');
|
|
||||||
if (mapPh) mapPh.remove();
|
|
||||||
|
|
||||||
// Meta
|
// Meta
|
||||||
var metaUpdated = document.getElementById('meta-updated');
|
var metaUpdated = document.getElementById('meta-updated');
|
||||||
@@ -346,80 +333,45 @@ const Tutorial = {
|
|||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
_demoMap: null,
|
_demoMap: null,
|
||||||
_demoMapMarkers: [],
|
_demoMapMarkers: [],
|
||||||
|
_demoMapLegend: null,
|
||||||
|
_demoMapTileMap: null, // Map-Instanz in der Kachel
|
||||||
|
|
||||||
_initDemoMap() {
|
_DEMO_MAP_LOCATIONS: [
|
||||||
if (typeof L === 'undefined') return;
|
{ lat: 53.5325, lon: 9.9275, name: 'Burchardkai Terminal', articles: 6, cat: 'primary' },
|
||||||
var container = document.getElementById('map-container');
|
{ lat: 53.5460, lon: 9.9690, name: 'Hamburg Innenstadt', articles: 2, cat: 'secondary' },
|
||||||
if (!container) return;
|
{ lat: 53.5380, lon: 9.9400, name: 'Elbe / Hafengebiet', articles: 1, cat: 'tertiary' },
|
||||||
|
],
|
||||||
|
_DEMO_MAP_COLORS: { primary: '#EF4444', secondary: '#F59E0B', tertiary: '#3B82F6' },
|
||||||
|
_DEMO_MAP_LABELS: { primary: 'Hauptereignisort', secondary: 'Erwähnt', tertiary: 'Kontext' },
|
||||||
|
|
||||||
// Container-Höhe sicherstellen
|
_createDemoMarkers(map) {
|
||||||
var gsItem = container.closest('.grid-stack-item');
|
var markers = [];
|
||||||
if (gsItem) {
|
|
||||||
var headerEl = container.closest('.map-card');
|
|
||||||
var hdr = headerEl ? headerEl.querySelector('.card-header') : null;
|
|
||||||
var headerH = hdr ? hdr.offsetHeight : 40;
|
|
||||||
var available = gsItem.offsetHeight - headerH - 4;
|
|
||||||
container.style.height = Math.max(available, 200) + 'px';
|
|
||||||
} else if (container.offsetHeight < 50) {
|
|
||||||
container.style.height = '300px';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Falls UI._map existiert, vorher sichern
|
|
||||||
if (typeof UI !== 'undefined' && UI._map) {
|
|
||||||
this._savedUIMap = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._demoMap = L.map(container, {
|
|
||||||
zoomControl: true,
|
|
||||||
attributionControl: true,
|
|
||||||
}).setView([53.545, 9.98], 13);
|
|
||||||
|
|
||||||
// Tile-Layer (Theme-abhängig)
|
|
||||||
var isDark = document.documentElement.getAttribute('data-theme') !== 'light';
|
|
||||||
if (isDark) {
|
|
||||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', {
|
|
||||||
attribution: '\u00a9 OpenStreetMap, \u00a9 CARTO',
|
|
||||||
maxZoom: 19,
|
|
||||||
}).addTo(this._demoMap);
|
|
||||||
} else {
|
|
||||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
|
|
||||||
attribution: '\u00a9 OpenStreetMap, \u00a9 CARTO',
|
|
||||||
maxZoom: 19,
|
|
||||||
}).addTo(this._demoMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Demo-Marker
|
|
||||||
var locations = [
|
|
||||||
{ lat: 53.5325, lon: 9.9275, name: 'Burchardkai Terminal', articles: 6, cat: 'primary' },
|
|
||||||
{ lat: 53.5460, lon: 9.9690, name: 'Hamburg Innenstadt', articles: 2, cat: 'secondary' },
|
|
||||||
{ lat: 53.5380, lon: 9.9400, name: 'Elbe / Hafengebiet', articles: 1, cat: 'tertiary' },
|
|
||||||
];
|
|
||||||
|
|
||||||
var catColors = { primary: '#EF4444', secondary: '#F59E0B', tertiary: '#3B82F6' };
|
|
||||||
var catLabels = { primary: 'Hauptereignisort', secondary: 'Erw\u00e4hnt', tertiary: 'Kontext' };
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
this._DEMO_MAP_LOCATIONS.forEach(function(loc) {
|
||||||
locations.forEach(function(loc) {
|
var color = self._DEMO_MAP_COLORS[loc.cat];
|
||||||
var color = catColors[loc.cat] || '#7b7b7b';
|
|
||||||
var icon = L.divIcon({
|
var icon = L.divIcon({
|
||||||
className: 'tutorial-map-marker',
|
className: 'tutorial-map-marker',
|
||||||
html: '<div style="width:14px;height:14px;border-radius:50%;background:' + color
|
html: '<div style="width:14px;height:14px;border-radius:50%;background:' + color
|
||||||
+ ';border:2px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.4);"></div>',
|
+ ';border:2px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,0.5);"></div>',
|
||||||
iconSize: [14, 14],
|
iconSize: [14, 14],
|
||||||
iconAnchor: [7, 7],
|
iconAnchor: [7, 7],
|
||||||
});
|
});
|
||||||
var marker = L.marker([loc.lat, loc.lon], { icon: icon });
|
var marker = L.marker([loc.lat, loc.lon], { icon: icon });
|
||||||
|
var label = self._DEMO_MAP_LABELS[loc.cat];
|
||||||
var popupHtml = '<div class="map-popup">'
|
var popupHtml = '<div class="map-popup">'
|
||||||
+ '<div class="map-popup-title">' + loc.name + '</div>'
|
+ '<div class="map-popup-title">' + loc.name + '</div>'
|
||||||
+ '<div style="font-size:11px;margin:4px 0;"><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' + color + ';margin-right:4px;vertical-align:middle;"></span>' + catLabels[loc.cat] + '</div>'
|
+ '<div style="font-size:11px;margin:4px 0;"><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' + color + ';margin-right:4px;vertical-align:middle;"></span>' + label + '</div>'
|
||||||
+ '<div class="map-popup-count">' + loc.articles + ' Artikel</div>'
|
+ '<div class="map-popup-count">' + loc.articles + ' Artikel</div>'
|
||||||
+ '</div>';
|
+ '</div>';
|
||||||
marker.bindPopup(popupHtml, { maxWidth: 250, className: 'map-popup-container' });
|
marker.bindPopup(popupHtml, { maxWidth: 250, className: 'map-popup-container' });
|
||||||
marker.addTo(self._demoMap);
|
marker.addTo(map);
|
||||||
self._demoMapMarkers.push(marker);
|
markers.push(marker);
|
||||||
});
|
});
|
||||||
|
return markers;
|
||||||
|
},
|
||||||
|
|
||||||
// Legende
|
_addDemoLegend(map) {
|
||||||
|
var self = this;
|
||||||
var legend = L.control({ position: 'bottomright' });
|
var legend = L.control({ position: 'bottomright' });
|
||||||
legend.onAdd = function() {
|
legend.onAdd = function() {
|
||||||
var div = L.DomUtil.create('div', 'map-legend-ctrl');
|
var div = L.DomUtil.create('div', 'map-legend-ctrl');
|
||||||
@@ -427,39 +379,61 @@ const Tutorial = {
|
|||||||
var html = '<strong style="display:block;margin-bottom:6px;">Legende</strong>';
|
var html = '<strong style="display:block;margin-bottom:6px;">Legende</strong>';
|
||||||
['primary', 'secondary', 'tertiary'].forEach(function(cat) {
|
['primary', 'secondary', 'tertiary'].forEach(function(cat) {
|
||||||
html += '<div class="map-legend-item" style="display:flex;align-items:center;gap:6px;margin:3px 0;">'
|
html += '<div class="map-legend-item" style="display:flex;align-items:center;gap:6px;margin:3px 0;">'
|
||||||
+ '<span style="width:10px;height:10px;border-radius:50%;background:' + catColors[cat] + ';flex-shrink:0;"></span>'
|
+ '<span style="width:10px;height:10px;border-radius:50%;background:' + self._DEMO_MAP_COLORS[cat] + ';flex-shrink:0;"></span>'
|
||||||
+ '<span>' + catLabels[cat] + '</span></div>';
|
+ '<span>' + self._DEMO_MAP_LABELS[cat] + '</span></div>';
|
||||||
});
|
});
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
legend.addTo(this._demoMap);
|
legend.addTo(map);
|
||||||
this._demoMapLegend = legend;
|
return legend;
|
||||||
|
},
|
||||||
|
|
||||||
// Resize-Fix
|
// Map in der Dashboard-Kachel initialisieren
|
||||||
var map = this._demoMap;
|
_initDemoMapInTile() {
|
||||||
[100, 300, 800].forEach(function(delay) {
|
if (typeof L === 'undefined') return;
|
||||||
setTimeout(function() {
|
var container = document.getElementById('map-container');
|
||||||
if (map) map.invalidateSize();
|
if (!container) return;
|
||||||
}, delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Hauptereignisort-Popup nach kurzer Verz\u00f6gerung \u00f6ffnen
|
// Container-Höhe sicherstellen
|
||||||
var mainMarker = this._demoMapMarkers[0];
|
var gsItem = container.closest('.grid-stack-item');
|
||||||
if (mainMarker) {
|
if (gsItem) {
|
||||||
setTimeout(function() {
|
var hdr = container.closest('.map-card');
|
||||||
if (map && mainMarker) mainMarker.openPopup();
|
var headerEl = hdr ? hdr.querySelector('.card-header') : null;
|
||||||
}, 1500);
|
var headerH = headerEl ? headerEl.offsetHeight : 40;
|
||||||
|
var available = gsItem.offsetHeight - headerH - 4;
|
||||||
|
container.style.height = Math.max(available, 200) + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._demoMapTileMap = L.map(container, {
|
||||||
|
zoomControl: true,
|
||||||
|
attributionControl: false,
|
||||||
|
}).setView([53.545, 9.98], 12);
|
||||||
|
|
||||||
|
L.tileLayer('https://tile.openstreetmap.de/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 18, noWrap: true,
|
||||||
|
}).addTo(this._demoMapTileMap);
|
||||||
|
|
||||||
|
this._createDemoMarkers(this._demoMapTileMap);
|
||||||
|
this._addDemoLegend(this._demoMapTileMap);
|
||||||
|
|
||||||
|
var map = this._demoMapTileMap;
|
||||||
|
[200, 500, 1000].forEach(function(d) {
|
||||||
|
setTimeout(function() { if (map) map.invalidateSize(); }, d);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_destroyDemoMap() {
|
_destroyDemoMap() {
|
||||||
if (this._demoMap) {
|
if (this._demoMap) {
|
||||||
this._demoMap.remove();
|
this._demoMap.remove();
|
||||||
this._demoMap = null;
|
this._demoMap = null;
|
||||||
this._demoMapMarkers = [];
|
|
||||||
this._demoMapLegend = null;
|
|
||||||
}
|
}
|
||||||
|
if (this._demoMapTileMap) {
|
||||||
|
this._demoMapTileMap.remove();
|
||||||
|
this._demoMapTileMap = null;
|
||||||
|
}
|
||||||
|
this._demoMapMarkers = [];
|
||||||
|
this._demoMapLegend = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@@ -966,30 +940,54 @@ const Tutorial = {
|
|||||||
Tutorial._clearSubHighlights();
|
Tutorial._clearSubHighlights();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 17 - Karte (Vollbild)
|
// 17 - Karte: Kachel-Ansicht
|
||||||
{
|
{
|
||||||
id: 'karte',
|
id: 'karte',
|
||||||
target: '.map-fullscreen-header',
|
target: '[gs-id="karte"]',
|
||||||
title: 'Geografische Verteilung',
|
title: 'Geografische Verteilung',
|
||||||
text: 'Die Karte zeigt per Geoparsing automatisch erkannte Orte aus den Quellen.<br><br>'
|
text: 'Die Karte zeigt per <strong>Geoparsing</strong> automatisch erkannte Orte aus den Quellen.<br><br>'
|
||||||
+ '<strong style="color:#EF4444;">●</strong> <strong>Hauptereignisort</strong> - Zentraler Ort des Geschehens<br>'
|
+ '<strong>Orte einlesen</strong> - Startet das Geoparsing manuell neu<br>'
|
||||||
+ '<strong style="color:#F59E0B;">●</strong> <strong>Erw\u00e4hnt</strong> - In Artikeln genannte Orte<br>'
|
+ '<strong>Vollbild</strong> - Vergr\u00f6\u00dfert die Karte auf den gesamten Bildschirm<br><br>'
|
||||||
+ '<strong style="color:#3B82F6;">●</strong> <strong>Kontext</strong> - Relevante Umgebung<br><br>'
|
+ 'Im n\u00e4chsten Schritt \u00f6ffnen wir die Vollbildansicht und schauen uns die Marker im Detail an.',
|
||||||
+ 'Klicken Sie auf Marker f\u00fcr Details und verkn\u00fcpfte Artikel. '
|
position: 'top',
|
||||||
+ 'Bei vielen Markern werden nahe Orte zu Clustern gruppiert.<br><br>'
|
onEnter: function() {
|
||||||
+ '<strong>Orte einlesen</strong> startet das Geoparsing manuell neu. '
|
// Tile-Map Resize triggern
|
||||||
+ '<strong>Vollbild</strong> zeigt die Karte in dieser gro\u00dfen Ansicht.',
|
if (Tutorial._demoMapTileMap) {
|
||||||
|
Tutorial._demoMapTileMap.invalidateSize();
|
||||||
|
setTimeout(function() {
|
||||||
|
if (Tutorial._demoMapTileMap) Tutorial._demoMapTileMap.setView([53.545, 9.98], 12);
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
Tutorial._highlightSub('#geoparse-btn');
|
||||||
|
Tutorial._stepTimeout(function() {
|
||||||
|
Tutorial._clearSubHighlights();
|
||||||
|
Tutorial._highlightSub('#map-expand-btn');
|
||||||
|
}, 2500);
|
||||||
|
},
|
||||||
|
onExit: function() {
|
||||||
|
Tutorial._clearSubHighlights();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 18 - Karte: Vollbild + Zoom + Marker-Demo
|
||||||
|
{
|
||||||
|
id: 'karte-fullscreen',
|
||||||
|
target: '.map-fullscreen-header',
|
||||||
|
title: 'Karte im Vollbild',
|
||||||
|
text: 'Die Karte zoomt jetzt auf den Ereignisort. Die Marker zeigen:<br><br>'
|
||||||
|
+ '<strong style="color:#EF4444;">● Hauptereignisort</strong> - Burchardkai Terminal (6 Artikel)<br>'
|
||||||
|
+ '<strong style="color:#F59E0B;">● Erw\u00e4hnt</strong> - Hamburg Innenstadt (2 Artikel)<br>'
|
||||||
|
+ '<strong style="color:#3B82F6;">● Kontext</strong> - Elbe / Hafengebiet (1 Artikel)<br><br>'
|
||||||
|
+ 'Die <strong>Legende</strong> unten rechts erkl\u00e4rt die Farbkategorien. '
|
||||||
|
+ 'Klicken Sie auf einen Marker f\u00fcr Details und verkn\u00fcpfte Artikel.',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
disableNav: true,
|
disableNav: true,
|
||||||
onEnter: function() {
|
onEnter: function() {
|
||||||
// Chat-Button verstecken im Vollbild
|
|
||||||
var chatBtn = document.getElementById('chat-toggle-btn');
|
var chatBtn = document.getElementById('chat-toggle-btn');
|
||||||
if (chatBtn) chatBtn.style.display = 'none';
|
if (chatBtn) chatBtn.style.display = 'none';
|
||||||
Tutorial._openDemoMapFullscreen();
|
Tutorial._openDemoMapFullscreen();
|
||||||
},
|
},
|
||||||
onExit: function() {
|
onExit: function() {
|
||||||
Tutorial._closeDemoMapFullscreen();
|
Tutorial._closeDemoMapFullscreen();
|
||||||
// Chat-Button wieder anzeigen
|
|
||||||
var chatBtn = document.getElementById('chat-toggle-btn');
|
var chatBtn = document.getElementById('chat-toggle-btn');
|
||||||
if (chatBtn) chatBtn.style.display = '';
|
if (chatBtn) chatBtn.style.display = '';
|
||||||
Tutorial._clearSubHighlights();
|
Tutorial._clearSubHighlights();
|
||||||
@@ -1572,53 +1570,9 @@ const Tutorial = {
|
|||||||
noWrap: true,
|
noWrap: true,
|
||||||
}).addTo(this._demoMap);
|
}).addTo(this._demoMap);
|
||||||
|
|
||||||
// Marker (aber noch nicht sichtbar bei Zoom 5)
|
// Marker + Legende hinzufügen
|
||||||
var locations = [
|
this._demoMapMarkers = this._createDemoMarkers(this._demoMap);
|
||||||
{ lat: 53.5325, lon: 9.9275, name: 'Burchardkai Terminal', articles: 6, cat: 'primary' },
|
this._demoMapLegend = this._addDemoLegend(this._demoMap);
|
||||||
{ lat: 53.5460, lon: 9.9690, name: 'Hamburg Innenstadt', articles: 2, cat: 'secondary' },
|
|
||||||
{ lat: 53.5380, lon: 9.9400, name: 'Elbe / Hafengebiet', articles: 1, cat: 'tertiary' },
|
|
||||||
];
|
|
||||||
var catColors = { primary: '#EF4444', secondary: '#F59E0B', tertiary: '#3B82F6' };
|
|
||||||
var catLabels = { primary: 'Hauptereignisort', secondary: 'Erw\u00e4hnt', tertiary: 'Kontext' };
|
|
||||||
var self = this;
|
|
||||||
this._demoMapMarkers = [];
|
|
||||||
|
|
||||||
locations.forEach(function(loc) {
|
|
||||||
var color = catColors[loc.cat];
|
|
||||||
var icon = L.divIcon({
|
|
||||||
className: 'tutorial-map-marker',
|
|
||||||
html: '<div style="width:16px;height:16px;border-radius:50%;background:' + color
|
|
||||||
+ ';border:2px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,0.5);"></div>',
|
|
||||||
iconSize: [16, 16],
|
|
||||||
iconAnchor: [8, 8],
|
|
||||||
});
|
|
||||||
var marker = L.marker([loc.lat, loc.lon], { icon: icon });
|
|
||||||
var popupHtml = '<div class="map-popup">'
|
|
||||||
+ '<div class="map-popup-title">' + loc.name + '</div>'
|
|
||||||
+ '<div style="font-size:11px;margin:4px 0;"><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' + color + ';margin-right:4px;vertical-align:middle;"></span>' + catLabels[loc.cat] + '</div>'
|
|
||||||
+ '<div class="map-popup-count">' + loc.articles + ' Artikel</div>'
|
|
||||||
+ '</div>';
|
|
||||||
marker.bindPopup(popupHtml, { maxWidth: 250, className: 'map-popup-container' });
|
|
||||||
marker.addTo(self._demoMap);
|
|
||||||
self._demoMapMarkers.push(marker);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Legende
|
|
||||||
var legend = L.control({ position: 'bottomright' });
|
|
||||||
legend.onAdd = function() {
|
|
||||||
var div = L.DomUtil.create('div', 'map-legend-ctrl');
|
|
||||||
L.DomEvent.disableClickPropagation(div);
|
|
||||||
var html = '<strong style="display:block;margin-bottom:6px;">Legende</strong>';
|
|
||||||
['primary', 'secondary', 'tertiary'].forEach(function(cat) {
|
|
||||||
html += '<div class="map-legend-item" style="display:flex;align-items:center;gap:6px;margin:3px 0;">'
|
|
||||||
+ '<span style="width:10px;height:10px;border-radius:50%;background:' + catColors[cat] + ';flex-shrink:0;"></span>'
|
|
||||||
+ '<span>' + catLabels[cat] + '</span></div>';
|
|
||||||
});
|
|
||||||
div.innerHTML = html;
|
|
||||||
return div;
|
|
||||||
};
|
|
||||||
legend.addTo(this._demoMap);
|
|
||||||
this._demoMapLegend = legend;
|
|
||||||
|
|
||||||
// Resize + animierter Zoom auf Hamburg
|
// Resize + animierter Zoom auf Hamburg
|
||||||
var map = this._demoMap;
|
var map = this._demoMap;
|
||||||
@@ -1656,41 +1610,43 @@ const Tutorial = {
|
|||||||
|
|
||||||
async _simulateMapDemo() {
|
async _simulateMapDemo() {
|
||||||
this._demoRunning = true;
|
this._demoRunning = true;
|
||||||
|
await this._wait(800);
|
||||||
|
|
||||||
await this._wait(500);
|
if (!this._demoMapMarkers.length || !this._demoMap) {
|
||||||
|
this._demoRunning = false;
|
||||||
|
this._enableNavAfterDemo();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Cursor zu Hauptmarker und klicken
|
var mapEl = document.getElementById('tutorial-fs-map');
|
||||||
if (this._demoMapMarkers.length > 0 && this._demoMap) {
|
if (!mapEl) { this._demoRunning = false; this._enableNavAfterDemo(); return; }
|
||||||
var mainMarker = this._demoMapMarkers[0];
|
var mapRect = mapEl.getBoundingClientRect();
|
||||||
var latLng = mainMarker.getLatLng();
|
|
||||||
|
// Alle 3 Marker nacheinander besuchen
|
||||||
|
var names = ['Burchardkai Terminal (Hauptereignisort)', 'Hamburg Innenstadt (Erwähnt)', 'Elbe / Hafengebiet (Kontext)'];
|
||||||
|
var prevX, prevY;
|
||||||
|
|
||||||
|
for (var i = 0; i < this._demoMapMarkers.length; i++) {
|
||||||
|
if (!this._isActive) break;
|
||||||
|
var marker = this._demoMapMarkers[i];
|
||||||
|
var latLng = marker.getLatLng();
|
||||||
var point = this._demoMap.latLngToContainerPoint(latLng);
|
var point = this._demoMap.latLngToContainerPoint(latLng);
|
||||||
var mapEl = document.getElementById('tutorial-fs-map');
|
var mx = mapRect.left + point.x;
|
||||||
if (mapEl) {
|
var my = mapRect.top + point.y;
|
||||||
var mapRect = mapEl.getBoundingClientRect();
|
|
||||||
var markerX = mapRect.left + point.x;
|
|
||||||
var markerY = mapRect.top + point.y;
|
|
||||||
|
|
||||||
this._showCursor(markerX - 60, markerY - 60, 'default');
|
if (prevX !== undefined) {
|
||||||
await this._wait(300);
|
await this._animateCursor(prevX, prevY, mx, my, 600);
|
||||||
await this._animateCursor(markerX - 60, markerY - 60, markerX, markerY, 700);
|
} else {
|
||||||
|
this._showCursor(mx - 60, my - 50, 'default');
|
||||||
await this._wait(200);
|
await this._wait(200);
|
||||||
mainMarker.openPopup();
|
await this._animateCursor(mx - 60, my - 50, mx, my, 500);
|
||||||
await this._wait(2500);
|
|
||||||
mainMarker.closePopup();
|
|
||||||
|
|
||||||
// 2. Zum zweiten Marker
|
|
||||||
var secondMarker = this._demoMapMarkers[1];
|
|
||||||
if (secondMarker) {
|
|
||||||
var p2 = this._demoMap.latLngToContainerPoint(secondMarker.getLatLng());
|
|
||||||
var m2x = mapRect.left + p2.x;
|
|
||||||
var m2y = mapRect.top + p2.y;
|
|
||||||
await this._animateCursor(markerX, markerY, m2x, m2y, 600);
|
|
||||||
await this._wait(200);
|
|
||||||
secondMarker.openPopup();
|
|
||||||
await this._wait(2000);
|
|
||||||
secondMarker.closePopup();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
await this._wait(200);
|
||||||
|
marker.openPopup();
|
||||||
|
await this._wait(2500);
|
||||||
|
marker.closePopup();
|
||||||
|
prevX = mx;
|
||||||
|
prevY = my;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._hideCursor();
|
this._hideCursor();
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren