frontend/src/views/Home.vue
2023-09-15 01:36:47 +07:00

192 lines
No EOL
4.3 KiB
Vue

<template>
<div id="app">
<router-view />
<Popup
v-if="popupData"
:nearestStructureData="popupData"
:onClose="closePopup"
/>
</div>
<!-- <searchbar/> -->
<v-layout style="height: 40px;">
<v-app-bar scroll-threshold="0"
class="mx-auto px-auto"
>
<div class="flex-grow-1">
<v-text-field
v-model="searchQuery"
@keyup.enter="performSearch"
@input="performSearch"
@click="toggleSearchBar()"
density="compact"
variant="solo"
prepend-inner-icon="mdi-magnify"
single-line
hide-details
></v-text-field>
</div>
<v-btn icon @click="showSearchBar = !showSearchBar">
<v-icon>mdi-crosshairs-gps</v-icon>
</v-btn>
</v-app-bar>
</v-layout>
<!-- <div v-if="searchResults.length > 0" class="search-results">
<ul>
<li v-for="result in searchResults" :key="result.place_id" @click="moveToLocation(result)">
{{ result.display_name }}
</li>
</ul>
</div> -->
<v-list v-if="searchResults.length > 0 && !showSearchBar" class="search-results">
<v-list-item
v-for="result in searchResults"
:key="result.place_id"
@click="moveToLocation(result),toggleSearchBar()"
>
<v-list-item-icon>
<v-icon>mdi-map-marker</v-icon>
</v-list-item-icon>
{{ result.display_name }}
</v-list-item>
</v-list>
<!-- <map/> -->
<ol-map
:loadTilesWhileAnimating="true"
:loadTilesWhileInteracting="true"
style=
"
height: 100%;
width: 100%;
position: fixed;
"
@click="handleMapClick"
>
<ol-view
ref="view"
:center="center"
:rotation="rotation"
:zoom="zoom"
:projection="projection"
/>
<ol-tile-layer>
<ol-source-osm />
</ol-tile-layer>
</ol-map>
</template>
<script setup>
import searchbar from '@/components/searchbar.vue';
import Popup from "@/components/Popup.vue"; // Import the Popup componen
import { ref } from "vue";
import axios from "axios";
const center = ref([100.538611, 13.764722]);
const projection = ref("EPSG:4326");
const zoom = ref(19);
const rotation = ref(0);
const popupData = ref(null);
//search
const searchQuery = ref("");
const searchResults = ref([]);
const showSearchBar = ref(false);
const toggleSearchBar = () => {
showSearchBar.value = !showSearchBar.value;
};
const moveToLocation = (result) => {
const lat = parseFloat(result.lat);
const lon = parseFloat(result.lon);
center.value = [lon, lat];
showSearchBar.value = false;
};
const performSearch = async () => {
try {
const response = await axios.get(
`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(searchQuery.value)}`
);
searchResults.value = response.data.slice(0, 5);
} catch (error) {
console.error("Error fetching search results:", error);
}
};
//Show API
const handleMapClick = async event => {
const clickedCoordinate = event.coordinate;
try {
const response = await axios.get(
`https://nominatim.openstreetmap.org/reverse?format=json&lat=${clickedCoordinate[1]}&lon=${clickedCoordinate[0]}`
);
const nearestStructureData = response.data;
popupData.value = nearestStructureData; // Show popup
} catch (error) {
console.error("Error fetching reverse geocoding data:", error);
}
};
const closePopup = () => {
popupData.value = null; // Hide popup
};
</script>
<style>
.ol-zoom{
top: 40px;
}
.ol-attribution ul{
padding:1px .5em;
margin-bottom: 8em;
}
.search-results {
position: absolute;
width: 100%;
max-height: 200px;
height: 300px;
overflow-y: auto;
background-color: #fff;
border: 1px solid #ccc;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
z-index: 100;
top: 4em;
}
.search-results ul {
list-style-type: none;
padding: 0;
margin: 0;
}
.search-results li {
padding: 10px;
cursor: pointer;
}
.search-results li:hover {
background-color: #f0f0f0;
}
</style>