enhanced preorder map
This commit is contained in:
@@ -27,6 +27,12 @@ Vue.component('tt-map', {
|
||||
internalLoading: true,
|
||||
scriptsLoaded: false,
|
||||
showSettings: false,
|
||||
searchQuery: '',
|
||||
searchResults: [],
|
||||
isSearchLoading: false,
|
||||
showSearchResults: false,
|
||||
searchDebounce: null,
|
||||
selectedMarker: null, // To hold the temporary marker
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -248,6 +254,80 @@ Vue.component('tt-map', {
|
||||
if (this.map) {
|
||||
this.map.invalidateSize();
|
||||
}
|
||||
},
|
||||
searchLocations() {
|
||||
if (this.searchDebounce) clearTimeout(this.searchDebounce);
|
||||
if (this.searchQuery.length < 3) {
|
||||
this.searchResults = [];
|
||||
this.showSearchResults = true;
|
||||
return;
|
||||
}
|
||||
this.isSearchLoading = true;
|
||||
this.searchDebounce = setTimeout(async () => {
|
||||
try {
|
||||
const response = await axios.get('/Geocoding/autocomplete', {
|
||||
params: { q: this.searchQuery }
|
||||
});
|
||||
this.searchResults = response.data;
|
||||
} catch (error) {
|
||||
console.error("Geocoding search failed:", error);
|
||||
this.searchResults = [];
|
||||
} finally {
|
||||
this.isSearchLoading = false;
|
||||
}
|
||||
}, 350);
|
||||
},
|
||||
selectLocation(location) {
|
||||
this.searchQuery = location.text;
|
||||
this.showSearchResults = false;
|
||||
const [lat, lng] = location.value.split(',').map(Number);
|
||||
|
||||
if (this.map && !isNaN(lat) && !isNaN(lng)) {
|
||||
this.map.flyTo([lat, lng], 17, { duration: 0.5 });
|
||||
|
||||
if (this.selectedMarker) {
|
||||
this.selectedMarker.remove();
|
||||
}
|
||||
|
||||
const customIcon = L.divIcon({
|
||||
html: `<div class="custom-map-marker"><i class="fas fa-map-marker-alt"></i></div>`,
|
||||
className: '', // Important to keep it empty
|
||||
iconSize: [24, 24],
|
||||
iconAnchor: [12, 12],
|
||||
popupAnchor: [0, -14]
|
||||
});
|
||||
|
||||
this.selectedMarker = L.marker([lat, lng], { icon: customIcon }).addTo(this.map)
|
||||
.bindPopup(`<b>${location.text}</b>`)
|
||||
.openPopup();
|
||||
|
||||
this.searchQuery = '';
|
||||
this.searchResults = [];
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.selectedMarker) {
|
||||
this.selectedMarker.remove();
|
||||
this.selectedMarker = null;
|
||||
}
|
||||
}, 10000);
|
||||
}
|
||||
},
|
||||
clearSearch() {
|
||||
this.searchQuery = '';
|
||||
this.searchResults = [];
|
||||
this.showSearchResults = false;
|
||||
if (this.selectedMarker) {
|
||||
this.selectedMarker.remove();
|
||||
this.selectedMarker = null;
|
||||
}
|
||||
},
|
||||
handleSearchFocus() {
|
||||
this.showSearchResults = true;
|
||||
},
|
||||
handleSearchBlur() {
|
||||
setTimeout(() => {
|
||||
this.showSearchResults = false;
|
||||
}, 200);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -273,6 +353,47 @@ Vue.component('tt-map', {
|
||||
</div>
|
||||
<div ref="mapContainer" class="tt-map-container" :style="{ visibility: internalLoading ? 'hidden' : 'visible' }"></div>
|
||||
|
||||
<div class="tt-map-search-wrapper">
|
||||
<div class="tt-map-search-input-container">
|
||||
<i class="fas fa-search search-icon"></i>
|
||||
<input
|
||||
type="text"
|
||||
class="tt-map-search-input"
|
||||
placeholder="Adresse suchen..."
|
||||
v-model="searchQuery"
|
||||
@input="searchLocations"
|
||||
@focus="handleSearchFocus"
|
||||
@blur="handleSearchBlur"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button v-if="searchQuery" @click="clearSearch" class="clear-icon">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<ul v-if="showSearchResults" class="tt-map-search-results">
|
||||
<li v-if="isSearchLoading" class="result-item-info">
|
||||
<i class="fas fa-spinner fa-spin"></i> Suche läuft...
|
||||
</li>
|
||||
<li v-else-if="searchQuery.length < 3" class="result-item-info">
|
||||
Bitte mind. 3 Zeichen eingeben
|
||||
</li>
|
||||
<li v-else-if="searchResults.length === 0" class="result-item-info">
|
||||
Keine Ergebnisse gefunden
|
||||
</li>
|
||||
<li
|
||||
v-for="result in searchResults"
|
||||
:key="result.value"
|
||||
class="result-item"
|
||||
@mousedown="selectLocation(result)"
|
||||
>
|
||||
<i class="fas fa-map-marker-alt"></i>
|
||||
<span>{{ result.text }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
<div class="tt-map-top-controls">
|
||||
<slot name="tools"></slot>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user