Planovac, zobrazeni vzdusnych prostoru
This commit is contained in:
@@ -110,6 +110,7 @@ const chartOptions = {
|
||||
:markers="pointsOfInterests"
|
||||
:highlight-position="currentPositionMarker"
|
||||
:photos="mapPhotos"
|
||||
v-bind="$attrs"
|
||||
/>
|
||||
|
||||
<Line v-if="gpxTrack" :data="chartSpeedData" :options="chartOptions"/>
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
<script setup>
|
||||
import {Marker} from "vue3-google-map";
|
||||
import {onMounted, ref} from "vue";
|
||||
import {defineEmits, onMounted, ref} from "vue";
|
||||
import axios from "axios";
|
||||
import MapWrapper from "components/map/MapWrapper.vue";
|
||||
|
||||
const center = ref({
|
||||
lat: 50.1314,
|
||||
lng: 14.5256
|
||||
});
|
||||
const zoom = ref(10);
|
||||
import {useGeocode} from "src/composables/geocoding";
|
||||
|
||||
const props = defineProps({
|
||||
gpsLatitude: {
|
||||
@@ -24,29 +19,13 @@ const props = defineProps({
|
||||
required: false
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:gpsLatitude", "update:gpsLongitude", "notFound"]);
|
||||
const emitModels = (lat, lng) => {
|
||||
emits("update:gpsLatitude", lat);
|
||||
emits("update:gpsLongitude", lng);
|
||||
}
|
||||
|
||||
const {emitModels, setCoordinatesFromGeocode, center, zoom} = useGeocode(emits);
|
||||
const markerDropped = (position) => {
|
||||
emitModels(position.latLng.lat(), position.latLng.lng());
|
||||
}
|
||||
|
||||
const setCoordinatesFromGeocode = (address) => {
|
||||
axios.get(`https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURI(address)}&key=${process.env.GOOGLE_MAPS_API_KEY}`).then(response => {
|
||||
if (response.data.status !== 'OK') {
|
||||
emits("notFound", props.label);
|
||||
return;
|
||||
}
|
||||
center.value = response.data.results[0].geometry.location;
|
||||
emitModels(center.value.lat, center.value.lng);
|
||||
zoom.value = 13;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
if (props.gpsLatitude && props.gpsLongitude) {
|
||||
center.value.lng = props.gpsLongitude;
|
||||
@@ -61,7 +40,7 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MapWrapper style="width: 100%; height: 500px" :center="center" :zoom="zoom">
|
||||
<MapWrapper style="width: 100%; height: 500px" :center="center" :zoom="zoom" v-bind="$attrs">
|
||||
<Marker :options="{ position: center, title: label, draggable: true }" @dragend="markerDropped"/>
|
||||
</MapWrapper>
|
||||
</template>
|
||||
|
||||
@@ -85,16 +85,15 @@ const getColor = (i) => {
|
||||
</Marker>
|
||||
|
||||
<template v-if="gpxTrack && gpxTrack.length > 0">
|
||||
<Polyline :options="{path: gpxTrack, geodesic: true, strokeColor: '#ff0000', strokeOpacity: 0.3, strokeWeight: 5}"/>
|
||||
<Polyline :options="{path: gpxTrack, geodesic: true, strokeColor: getColor(0), strokeOpacity: 0.5, strokeWeight: 5}"/>
|
||||
</template>
|
||||
|
||||
<template v-if="tracks && tracks.length > 0">
|
||||
<template v-for="(track, i) in tracks" :key="track">
|
||||
<Polyline :options="{path: track, geodesic: false, strokeColor: getColor(i), strokeOpacity: 1, strokeWeight: 3}"/>
|
||||
<Polyline :options="{path: track, geodesic: true, strokeColor: getColor(i), strokeOpacity: 0.5, strokeWeight: 5}"/>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<Marker v-if="highlightPosition" :options="{position: highlightPosition, icon: '/mapIcons/currentPosition32x32.png'}"/>
|
||||
|
||||
</MapWrapper>
|
||||
</template>
|
||||
|
||||
@@ -1,37 +1,132 @@
|
||||
<script setup>
|
||||
import {GoogleMap} from "vue3-google-map";
|
||||
import {ref, watch} from "vue";
|
||||
import {Circle, GoogleMap, Marker, Polygon} from "vue3-google-map";
|
||||
import {computed, ref, watch} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
bounds: {
|
||||
type: Array,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
airspacesData: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => []
|
||||
},
|
||||
});
|
||||
|
||||
const key = process.env.GOOGLE_MAPS_API_KEY;
|
||||
|
||||
|
||||
const mapRef = ref(null);
|
||||
watch(
|
||||
() => mapRef.value?.ready,
|
||||
(ready) => {
|
||||
if (!props.bounds || !ready) return;
|
||||
const map = mapRef.value.map;
|
||||
const api = mapRef.value.api;
|
||||
if (!ready) return;
|
||||
|
||||
const bounds = new api.LatLngBounds();
|
||||
for (let i = 0; i < props.bounds.length; i++) {
|
||||
bounds.extend(props.bounds[i]);
|
||||
if (props.bounds) {
|
||||
const bounds = new mapRef.value.api.LatLngBounds();
|
||||
for (let i = 0; i < props.bounds.length; i++) {
|
||||
bounds.extend(props.bounds[i]);
|
||||
}
|
||||
mapRef.value.map.fitBounds(bounds);
|
||||
}
|
||||
map.fitBounds(bounds);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const airspaces = computed(() => {
|
||||
const colorsMap = {
|
||||
C: "#800080",
|
||||
D: "#800080",
|
||||
CTR: "#00ff00",
|
||||
P: "#FF0000",
|
||||
RMZ: "#FFdd00",
|
||||
R: "#ff6a00",
|
||||
Q: "#FFA500",
|
||||
PGZ: "#008000",
|
||||
GSEC: "#008000"
|
||||
}
|
||||
|
||||
return props.airspacesData
|
||||
.filter(airspace => !!colorsMap[airspace.type])
|
||||
.map(airspace => {
|
||||
const data = {
|
||||
name: airspace.name,
|
||||
strokeColor: colorsMap[airspace.type],
|
||||
strokeOpacity: 0.2,
|
||||
strokeWeight: 3,
|
||||
fillColor: colorsMap[airspace.type],
|
||||
fillOpacity: 0.1,
|
||||
};
|
||||
|
||||
if (airspace.mapBounds.length > 0) {
|
||||
data['path'] = airspace.mapBounds;
|
||||
} else {
|
||||
data['center'] = airspace.mapCenter;
|
||||
data['radius'] = airspace.radius
|
||||
}
|
||||
|
||||
return data
|
||||
});
|
||||
});
|
||||
|
||||
const atzs = computed(() => {
|
||||
return props.airspacesData
|
||||
.filter(a => a.type === 'ATZ')
|
||||
.filter(a => !!a.mapCenter)
|
||||
.map(airspace => ({
|
||||
name: airspace.name,
|
||||
strokeColor: "#4e7cfc",
|
||||
strokeOpacity: 0.2,
|
||||
strokeWeight: 1,
|
||||
fillColor: "#4e7cfc",
|
||||
fillOpacity: 0.1,
|
||||
center: airspace.mapCenter,
|
||||
radius: airspace.radius,
|
||||
}))
|
||||
});
|
||||
|
||||
// TODO: pridat letiste
|
||||
|
||||
function isPointInPolygon(clickPoint, polygonCoords) {
|
||||
var count = 0;
|
||||
var x = clickPoint.lng, y = clickPoint.lat;
|
||||
|
||||
for (var i = 0; i < polygonCoords.length; i++) {
|
||||
var iNext = (i + 1) % polygonCoords.length;
|
||||
|
||||
var xi = polygonCoords[i].lng, yi = polygonCoords[i].lat;
|
||||
var xiNext = polygonCoords[iNext].lng, yiNext = polygonCoords[iNext].lat;
|
||||
|
||||
var test = ((yi > y) !== (yiNext > y)) && (x < (xiNext - xi) * (y - yi) / (yiNext - yi) + xi);
|
||||
if (test) count++;
|
||||
}
|
||||
|
||||
return count % 2 === 1; // Lichý počet průsečíků = bod uvnitř
|
||||
}
|
||||
|
||||
const showInfo = (e) => {
|
||||
for (const airspace of airspaces.value) {
|
||||
const clickCoords = {lat: e.latLng.lat(), lng: e.latLng.lng()}
|
||||
|
||||
if (airspace.path)
|
||||
console.log(airspace.name, isPointInPolygon(clickCoords, airspace.path));
|
||||
else {
|
||||
// console.log(airspace);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<GoogleMap :api-key="key" v-bind="$attrs" :max-zoom="13" ref="mapRef">
|
||||
<GoogleMap :api-key="key" v-bind="$attrs" map-type-id="terrain" :max-zoom="13" ref="mapRef">
|
||||
<slot/>
|
||||
|
||||
<template v-for="airspace in airspaces" :key="airspace">
|
||||
<Polygon :options="airspace" @click=showInfo v-if="airspace.path"/>
|
||||
<Circle :options="airspace" @click=showInfo v-if="airspace.center && airspace.radius"/>
|
||||
</template>
|
||||
<Circle :options="atz" v-for="atz in atzs" @click=showInfo :key="atz"/>
|
||||
</GoogleMap>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user