Vue.component('pop-map-modal', { template: `
`, data() { return { map: null, popLayer: null, searchQuery: '', filteredPops: [], showSuggestions: false, selectedIndex: -1, categories: { 1: 'Outdoor (Kasten/Schrank)', 2: 'Indoor (Keller Gebäude)', 3: 'Sender/Funk (Sendemast)', 4: 'Container (Garage, Container)', 99: 'Unbekannt' }, states: { 1: "Planung (Innenleben)", 2: "Bauphase (Schrank)", 3: "Grobdoku", 4: "in Betrieb", 5: "von Techniker abgenommen (Altbestand)" }, categoryImages: { 1: 'img/markers/marker-pop.png', 2: 'img/markers/marker-pop-o.png', 3: 'img/markers/marker-pop-b.png', 4: 'img/markers/marker-pop-v.png', 99: 'img/markers/marker-pop-bl.png' }, categoryColors: { 1: '#a1dfa0', 2: '#f8b767', 3: '#a9b8ec', 4: '#f89797', 99: '#808080' }, visibleCategories: { 1: true, 2: true, 3: true, 4: true, 99: true }, categoryCounts: { 1: 0, 2: 0, 3: 0, 4: 0, 99: 0 }, allPops: [], markers: [] }; }, computed: { totalCount() { return Object.values(this.categoryCounts).reduce((acc, count) => acc + count, 0); }, allCategoriesSelected: { get() { return Object.keys(this.categories).every(key => this.visibleCategories[key]); }, set(value) { Object.keys(this.categories).forEach(key => { this.visibleCategories[key] = value; }); this.updateMap(false); } } }, mounted() { const popsObj = window.TT_CONFIG.POPS || {}; this.allPops = Object.values(popsObj); this.calculateCounts(); $(document).on('shown.bs.modal', '#popMapModal', this.initMap); document.addEventListener('click', this.handleClickOutside); }, beforeDestroy() { $(document).off('shown.bs.modal', '#popMapModal', this.initMap); document.removeEventListener('click', this.handleClickOutside); }, methods: { calculateCounts() { for (let key in this.categoryCounts) { this.categoryCounts[key] = 0; } this.allPops.forEach(pop => { const gps = pop.gps; if (!gps) return; const parts = gps.split(','); if (parts.length !== 2) return; const lat = parseFloat(parts[0]); const lng = parseFloat(parts[1]); if (isNaN(lat) || isNaN(lng) || (lat === 0 && lng === 0)) return; const category = pop.category || 99; if (this.categoryCounts.hasOwnProperty(category)) { this.categoryCounts[category]++; } else { this.categoryCounts[99]++; } }); }, open() { $('#popMapModal').modal('show'); }, initMap() { if (this.map) { setTimeout(() => { this.map.invalidateSize(); }, 100); return; } if (typeof L === 'undefined' || !L.MakiMarkers) { console.error('Leaflet or MakiMarkers not loaded'); return; } L.MakiMarkers.accessToken = window.TT_CONFIG.MAPBOX_TOKEN; this.map = L.map('pop-map').setView([51.1657, 10.4515], 6); const standardLayer = L.tileLayer('https://mapsneu.wien.gv.at/basemap/{id}/normal/google3857/{z}/{y}/{x}.{imgtype}', { maxZoom: 19, id: "geolandbasemap", imgtype: "png", attribution: 'Basemap.at' }); const satelliteLayer = L.tileLayer('https://mapsneu.wien.gv.at/basemap/{id}/normal/google3857/{z}/{y}/{x}.{imgtype}', { maxZoom: 19, id: "bmaporthofoto30cm", imgtype: "jpeg", attribution: 'Basemap.at' }); standardLayer.addTo(this.map); const baseMaps = { "Karte": standardLayer, "Satellit": satelliteLayer }; L.control.layers(baseMaps).addTo(this.map); this.popLayer = L.featureGroup().addTo(this.map); this.updateMap(); }, updateMap(shouldFit = true) { if (!this.map) return; this.popLayer.clearLayers(); this.markers = []; const bounds = L.latLngBounds(); let hasMarkers = false; this.allPops.forEach(pop => { const category = pop.category || 99; if (!this.visibleCategories[category]) return; const gps = pop.gps; if (!gps) return; const parts = gps.split(','); if (parts.length !== 2) return; const lat = parseFloat(parts[0]); const lng = parseFloat(parts[1]); if (isNaN(lat) || isNaN(lng) || (lat === 0 && lng === 0)) return; let iconUrl = this.categoryImages[category] || this.categoryImages[99]; let color = this.categoryColors[category] || '#808080'; const marker = L.marker([lat, lng], { icon: L.MakiMarkers.icon({ icon: 'village', color: color, size: 'l' }) }); let categoryName = this.categories[category] || 'Unbekannt'; let stateText = this.states[pop.state] || pop.state || '-'; let addressHtml = (pop.street || pop.city) ? `
Adresse: ${pop.street || ''} ${pop.number || ''}, ${pop.zip || ''} ${pop.city || ''}
` : ''; const popupContent = `
${pop.name}

${addressHtml}
Kategorie: ${categoryName}
Status: ${stateText}
Info: ${pop.location || '-'}
GPS: ${lat.toFixed(6)}, ${lng.toFixed(6)} Google Maps
Details
`; marker.bindPopup(popupContent); marker.popData = pop; this.popLayer.addLayer(marker); this.markers.push(marker); bounds.extend([lat, lng]); hasMarkers = true; }); if (shouldFit === true && hasMarkers && !this.searchQuery) { this.map.fitBounds(bounds, {padding: [50, 50]}); } }, filterPops() { const query = this.searchQuery.toLowerCase().trim(); this.selectedIndex = -1; if (query.length < 1) { this.filteredPops = []; this.showSuggestions = false; return; } this.filteredPops = this.allPops.filter(pop => pop.name.toLowerCase().includes(query) || (pop.location && pop.location.toLowerCase().includes(query)) || (pop.street && pop.street.toLowerCase().includes(query)) || (pop.city && pop.city.toLowerCase().includes(query)) || (pop.zip && pop.zip.toLowerCase().includes(query)) ).slice(0, 10); this.showSuggestions = true; }, moveSelection(step) { if (!this.showSuggestions || this.filteredPops.length === 0) return; this.selectedIndex += step; if (this.selectedIndex < 0) { this.selectedIndex = this.filteredPops.length - 1; } else if (this.selectedIndex >= this.filteredPops.length) { this.selectedIndex = 0; } }, handleEnter() { if (this.showSuggestions && this.selectedIndex >= 0 && this.selectedIndex < this.filteredPops.length) { this.selectPop(this.filteredPops[this.selectedIndex]); } else { this.searchPop(); } }, selectPop(pop) { this.searchQuery = pop.name; this.showSuggestions = false; this.selectedIndex = -1; this.searchPop(); }, handleClickOutside(event) { if (!event.target.closest('.input-group')) { this.showSuggestions = false; this.selectedIndex = -1; } }, searchPop() { const query = this.searchQuery.toLowerCase().trim(); if (!query) { this.clearSearch(); return; } this.showSuggestions = false; this.selectedIndex = -1; let found = this.markers.find(m => m.popData.name.toLowerCase().includes(query) || (m.popData.street && m.popData.street.toLowerCase().includes(query)) || (m.popData.city && m.popData.city.toLowerCase().includes(query)) || (m.popData.zip && m.popData.zip.toLowerCase().includes(query)) ); if (!found) { const hiddenPop = this.allPops.find(p => p.name.toLowerCase().includes(query) || (p.street && p.street.toLowerCase().includes(query)) || (p.city && p.city.toLowerCase().includes(query)) || (p.zip && p.zip.toLowerCase().includes(query)) ); if (hiddenPop) { const category = hiddenPop.category || 99; if (!this.visibleCategories[category]) { this.visibleCategories[category] = true; this.updateMap(false); found = this.markers.find(m => m.popData.id === hiddenPop.id); } } } if (found) { this.map.flyTo(found.getLatLng(), 15); setTimeout(() => { found.openPopup(); }, 500); } else { alert('Kein POP gefunden (oder keine GPS Koordinaten).'); } }, clearSearch() { this.searchQuery = ''; this.filteredPops = []; this.showSuggestions = false; this.selectedIndex = -1; const bounds = L.latLngBounds(); this.markers.forEach(m => bounds.extend(m.getLatLng())); if (this.markers.length > 0) { this.map.fitBounds(bounds, {padding: [50, 50]}); } } } });