Dalsi iterace planovace, snad jiz kompletni vrstvy mapy
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import {Circle, GoogleMap, CustomMarker, Polygon} from "vue3-google-map";
|
||||
import {Circle, GoogleMap, CustomControl, CustomMarker, Polygon} from "vue3-google-map";
|
||||
import {computed, ref, watch} from "vue";
|
||||
import {useBasicVectorOperations, useVectorUtities} from "src/graphql/fragments/vectorUtilities";
|
||||
import {useBasicVectorOperations, useVectorUtilities} from "src/graphql/fragments/vectorUtilities";
|
||||
|
||||
const props = defineProps({
|
||||
bounds: {
|
||||
@@ -13,8 +13,16 @@ const props = defineProps({
|
||||
required: false,
|
||||
default: () => []
|
||||
},
|
||||
airports: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["map-click"]);
|
||||
|
||||
|
||||
const key = process.env.GOOGLE_MAPS_API_KEY;
|
||||
|
||||
const mapRef = ref(null);
|
||||
@@ -34,6 +42,19 @@ watch(
|
||||
);
|
||||
|
||||
|
||||
const displayAirspaceLayers = ref({
|
||||
CTR: true,
|
||||
TMA: true,
|
||||
RMZ: true,
|
||||
ATZ: true,
|
||||
DANGER: true,
|
||||
PROHIBIT: true,
|
||||
RESTRICT: true,
|
||||
TRA: true,
|
||||
TRAGA: true,
|
||||
AIRPORTS: true
|
||||
});
|
||||
|
||||
const airspaces = computed(() => {
|
||||
const colorsMap = {
|
||||
C: "#800080",
|
||||
@@ -44,19 +65,30 @@ const airspaces = computed(() => {
|
||||
R: "#ff6a00",
|
||||
Q: "#FFA500",
|
||||
PGZ: "#008000",
|
||||
GSEC: "#008000"
|
||||
GSEC: "#008000",
|
||||
ATZ: "#4e7cfc"
|
||||
}
|
||||
|
||||
return props.airspacesData
|
||||
.filter(airspace => !!colorsMap[airspace.type])
|
||||
.filter(airspace => {
|
||||
if (['C', 'D'].includes(airspace.type)) return displayAirspaceLayers.value.TMA;
|
||||
if (['PGZ', 'GSEC'].includes(airspace.type)) return displayAirspaceLayers.value.TRAGA;
|
||||
if (airspace.type === 'CTR') return displayAirspaceLayers.value.CTR;
|
||||
if (airspace.type === 'RMZ') return displayAirspaceLayers.value.RMZ;
|
||||
if (airspace.type === 'Q') return displayAirspaceLayers.value.DANGER;
|
||||
if (airspace.type === 'P') return displayAirspaceLayers.value.PROHIBIT;
|
||||
if (airspace.type === 'R') return displayAirspaceLayers.value.RESTRICT;
|
||||
return true;
|
||||
})
|
||||
.map(airspace => {
|
||||
const data = {
|
||||
name: airspace.name,
|
||||
strokeColor: colorsMap[airspace.type],
|
||||
strokeOpacity: 0.2,
|
||||
strokeOpacity: 0.3,
|
||||
strokeWeight: 3,
|
||||
fillColor: colorsMap[airspace.type],
|
||||
fillOpacity: 0.1,
|
||||
fillOpacity: 0,
|
||||
};
|
||||
|
||||
if (airspace.mapBounds.length > 0) {
|
||||
@@ -70,74 +102,88 @@ const airspaces = computed(() => {
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
}))
|
||||
const airportsOnMap = computed(() => {
|
||||
if (!displayAirspaceLayers.value.AIRPORTS) return [];
|
||||
|
||||
return props.airports.filter(a => a.gpsLatitude && a.gpsLongitude);
|
||||
});
|
||||
|
||||
// TODO: pridat letiste
|
||||
|
||||
const {isPointInPolygon} = useVectorUtities();
|
||||
const {isPointInPolygon, vectorDistanceToKm} = useVectorUtilities();
|
||||
const {vectorDistance} = useBasicVectorOperations();
|
||||
|
||||
const handleLayerClick = (e) => {
|
||||
const clickCoordinates = {lat: e.latLng.lat(), lng: e.latLng.lng()}
|
||||
|
||||
const getAirspacesAtCoordinates = (clickCoordinates) => {
|
||||
const airspacesUnderClick = []
|
||||
|
||||
for (const atz of atzs.value) {
|
||||
const distance = vectorDistance(
|
||||
{gpsLatitude: e.latLng.lat(), gpsLongitude: e.latLng.lng()},
|
||||
{gpsLatitude: atz.center.lat, gpsLongitude: atz.center.lng},
|
||||
);
|
||||
|
||||
if (distance < 0.079) { // tohle je nejaka bulharska konstanta, +- 5km od stredu letiste
|
||||
airspacesUnderClick.push(atz);
|
||||
}
|
||||
}
|
||||
|
||||
for (const airspace of airspaces.value) {
|
||||
if (airspace.path && isPointInPolygon(clickCoordinates, airspace.path)) {
|
||||
for (const airspace of props.airspacesData) {
|
||||
if (airspace.mapBounds && isPointInPolygon(clickCoordinates, airspace.mapBounds)) {
|
||||
airspacesUnderClick.push(airspace);
|
||||
} else if (airspace.mapCenter && airspace.radius) {
|
||||
const radDistance = vectorDistance(clickCoordinates, airspace.mapCenter);
|
||||
const distanceKm = vectorDistanceToKm(radDistance)
|
||||
|
||||
if (distanceKm * 1000 <= airspace.radius) {
|
||||
airspacesUnderClick.push(airspace)
|
||||
}
|
||||
}
|
||||
}
|
||||
emits("map-click", {airspaces: airspacesUnderClick, clickCoordinates});
|
||||
return airspacesUnderClick;
|
||||
}
|
||||
|
||||
const emits = defineEmits(["map-click"]);
|
||||
|
||||
const handleMapClick = (e) => {
|
||||
const clickCoordinates = {lat: e.latLng.lat(), lng: e.latLng.lng()}
|
||||
emits("map-click", {clickCoordinates});
|
||||
};
|
||||
emits("map-click", {airspaces: getAirspacesAtCoordinates(clickCoordinates), clickCoordinates});
|
||||
}
|
||||
|
||||
const handleAirportClick = (airport) => {
|
||||
const position = {lat: airport.gpsLatitude, lng: airport.gpsLongitude};
|
||||
emits("map-click", {clickCoordinates: position, airport})
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<GoogleMap :api-key="key" v-bind="$attrs" @click="handleMapClick" map-type-id="terrain" :max-zoom="13" ref="mapRef">
|
||||
<slot/>
|
||||
<GoogleMap
|
||||
:api-key="key"
|
||||
v-bind="$attrs"
|
||||
:street-view-control="false"
|
||||
@click="handleMapClick"
|
||||
map-type-id="terrain"
|
||||
:max-zoom="13"
|
||||
ref="mapRef"
|
||||
>
|
||||
<CustomControl position="BOTTOM_CENTER" class="text-center">
|
||||
<q-card class="q-my-lg q-px-lg">
|
||||
<q-checkbox v-model="displayAirspaceLayers.CTR" label="M/CTR"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.TMA" label="TMA"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.RMZ" label="RMZ"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.ATZ" label="ATZ"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.DANGER" label="Nebezpečné prostory"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.PROHIBIT" label="Zakázané prostory"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.RESTRICT" label="Omezené prostory (TRA)"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.TRAGA" label="TRAGA"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.AIRPORTS" label="Letiště"/>
|
||||
</q-card>
|
||||
</CustomControl>
|
||||
|
||||
<template v-for="airspace in airspaces" :key="airspace">
|
||||
<Polygon :options="airspace" @click=handleLayerClick v-if="airspace.path"/>
|
||||
<Circle :options="airspace" @click=handleLayerClick v-if="airspace.center && airspace.radius"/>
|
||||
<Polygon :options="airspace" @click=handleMapClick v-if="airspace.path"/>
|
||||
<Circle :options="airspace" @click=handleMapClick v-if="airspace.center && airspace.radius"/>
|
||||
</template>
|
||||
|
||||
<template v-for="atz in atzs" :key="atz">
|
||||
<Circle :options="atz" @click=handleLayerClick />
|
||||
<CustomMarker :options="{position: atz.center, anchorPoint: 'CENTER'}" @click="handleLayerClick">
|
||||
<q-icon name="local_airport" style="font-size: 24px" class="text-primary"/>
|
||||
<template v-for="airport in airportsOnMap" :key="airport.icaoCode">
|
||||
<CustomMarker
|
||||
:options="{position: {lat: airport.gpsLatitude, lng: airport.gpsLongitude}, anchorPoint: 'CENTER'}"
|
||||
@click.stop="handleAirportClick(airport)"
|
||||
>
|
||||
<div class="text-center">
|
||||
<q-icon name="local_airport" style="font-size: 24px" class="text-primary"/>
|
||||
<br>
|
||||
{{ airport.icaoCode }}
|
||||
</div>
|
||||
</CustomMarker>
|
||||
</template>
|
||||
|
||||
<slot/>
|
||||
|
||||
</GoogleMap>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user