Zobrazovani informaci o RWY, vylepseni zobrazeni vysek
This commit is contained in:
@@ -21,6 +21,7 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const getLimitFormatted = (limit, unit) => {
|
const getLimitFormatted = (limit, unit) => {
|
||||||
|
if (parseInt(limit) === 0) return 'GND';
|
||||||
return `${limit} ${unit}`
|
return `${limit} ${unit}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,12 +58,16 @@ const addMarker = async (point) => {
|
|||||||
const insertAt = Math.min(markers.value.length, props.insertPosition);
|
const insertAt = Math.min(markers.value.length, props.insertPosition);
|
||||||
|
|
||||||
markers.value.splice(insertAt, 0, markerObject({...point}));
|
markers.value.splice(insertAt, 0, markerObject({...point}));
|
||||||
// infoWindow.value = infoWindowObject({active: false});
|
|
||||||
|
|
||||||
emits("markers-changed", markers.value);
|
emits("markers-changed", markers.value);
|
||||||
emits("change-insert-position", insertAt + 1);
|
emits("change-insert-position", insertAt + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const removeMarker = (idx) => {
|
||||||
|
markers.value.splice(idx, 1);
|
||||||
|
emits("markers-changed", markers.value);
|
||||||
|
}
|
||||||
|
|
||||||
const {searchPlaceName} = useGeocode();
|
const {searchPlaceName} = useGeocode();
|
||||||
const handleMarkerMove = async (idx, event) => {
|
const handleMarkerMove = async (idx, event) => {
|
||||||
markers.value[idx].name = await searchPlaceName(event.lat(), event.lng());
|
markers.value[idx].name = await searchPlaceName(event.lat(), event.lng());
|
||||||
@@ -89,6 +93,7 @@ const handleMarkerMove = async (idx, event) => {
|
|||||||
:show-layer-controls="true"
|
:show-layer-controls="true"
|
||||||
:allow-add-marker="true"
|
:allow-add-marker="true"
|
||||||
@add-to-route="addMarker"
|
@add-to-route="addMarker"
|
||||||
|
@remove-from-route="removeMarker"
|
||||||
|
|
||||||
>
|
>
|
||||||
<template v-for="poi in pointsOfInterest" :key="poi.name">
|
<template v-for="poi in pointsOfInterest" :key="poi.name">
|
||||||
|
|||||||
@@ -59,12 +59,15 @@ const totalTime = computed(() => {
|
|||||||
<q-btn
|
<q-btn
|
||||||
@click='emits("fullscreen-toggle")'
|
@click='emits("fullscreen-toggle")'
|
||||||
size="sm"
|
size="sm"
|
||||||
|
round
|
||||||
:icon="isFullscreen ? 'mdi-fullscreen-exit' : 'mdi-fullscreen'"
|
:icon="isFullscreen ? 'mdi-fullscreen-exit' : 'mdi-fullscreen'"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
|
{{ insertPosition }} {{ flightPlan.track.length }}
|
||||||
|
|
||||||
<q-scroll-area style="height: 50vh">
|
<q-scroll-area style="height: 50vh">
|
||||||
<template v-for="(segment, i) in props.flightPlan.track" :key="segment">
|
<template v-for="(segment, i) in props.flightPlan.track" :key="segment">
|
||||||
<q-item dense>
|
<q-item dense>
|
||||||
@@ -81,7 +84,6 @@ const totalTime = computed(() => {
|
|||||||
icon="add"
|
icon="add"
|
||||||
size="sm"
|
size="sm"
|
||||||
class="q-ml-lg q-mb-sm"
|
class="q-ml-lg q-mb-sm"
|
||||||
:round="insertPosition !== i+1"
|
|
||||||
:color="insertPosition === i+1 ? 'primary' : 'grey'"
|
:color="insertPosition === i+1 ? 'primary' : 'grey'"
|
||||||
>
|
>
|
||||||
<template v-if="insertPosition === i+1">Přidávám sem</template>
|
<template v-if="insertPosition === i+1">Přidávám sem</template>
|
||||||
@@ -90,7 +92,6 @@ const totalTime = computed(() => {
|
|||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
|
|
||||||
<q-item dense v-if="segment.to && i === props.flightPlan.track.length - 1">
|
<q-item dense v-if="segment.to && i === props.flightPlan.track.length - 1">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>
|
<q-item-label>
|
||||||
@@ -99,9 +100,8 @@ const totalTime = computed(() => {
|
|||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
</q-scroll-area>
|
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section>
|
<q-item-section v-if="flightPlan.track.length">
|
||||||
<div>
|
<div>
|
||||||
<q-btn
|
<q-btn
|
||||||
@click="emits('change-insert-position', flightPlan.track.length + 1)"
|
@click="emits('change-insert-position', flightPlan.track.length + 1)"
|
||||||
@@ -114,6 +114,8 @@ const totalTime = computed(() => {
|
|||||||
</div>
|
</div>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
</q-scroll-area>
|
||||||
|
|
||||||
<template v-if="totalDistance">
|
<template v-if="totalDistance">
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import {InfoWindow} from "vue3-google-map";
|
import {InfoWindow} from "vue3-google-map";
|
||||||
import {useFlightPlanUtils} from "src/composables/flightPlan";
|
import {useFlightPlanUtils} from "src/composables/flightPlan";
|
||||||
import {useGeocode} from "src/composables/geocoding";
|
import {useGeocode} from "src/composables/geocoding";
|
||||||
import {ref, watch} from "vue";
|
import {computed, ref, watch} from "vue";
|
||||||
import {useAirspaceColors} from "src/composables/airspaces";
|
import {useAirspaceColors} from "src/composables/airspaces";
|
||||||
import AltitudeLimit from "components/AltitudeLimit.vue";
|
import AltitudeLimit from "components/AltitudeLimit.vue";
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(["add-to-route", "highlight-airspace", "close"])
|
const emits = defineEmits(["add-to-route", "remove-from-route", "highlight-airspace", "close"])
|
||||||
|
|
||||||
const {getIcon} = useFlightPlanUtils();
|
const {getIcon} = useFlightPlanUtils();
|
||||||
const {searchPlaceName} = useGeocode()
|
const {searchPlaceName} = useGeocode()
|
||||||
@@ -38,7 +38,7 @@ watch(() => props.infoWindow.position, async () => {
|
|||||||
}
|
}
|
||||||
}, {immediate: true, deep: true});
|
}, {immediate: true, deep: true});
|
||||||
|
|
||||||
const addPoint = async () => {
|
const addPoint = () => {
|
||||||
let type = "mapPoint";
|
let type = "mapPoint";
|
||||||
if (props.infoWindow.poi) {
|
if (props.infoWindow.poi) {
|
||||||
type = "poi";
|
type = "poi";
|
||||||
@@ -52,12 +52,39 @@ const addPoint = async () => {
|
|||||||
gpsLongitude: props.infoWindow.position.lng
|
gpsLongitude: props.infoWindow.position.lng
|
||||||
}
|
}
|
||||||
emits("add-to-route", point)
|
emits("add-to-route", point)
|
||||||
|
emits("close");
|
||||||
|
}
|
||||||
|
|
||||||
|
const removePoint = (marker) => {
|
||||||
|
emits("remove-from-route", marker);
|
||||||
|
emits("close");
|
||||||
}
|
}
|
||||||
|
|
||||||
const {getColorByType} = useAirspaceColors();
|
const {getColorByType} = useAirspaceColors();
|
||||||
const highlightAirspace = (airspace) => {
|
const highlightAirspace = (airspace) => {
|
||||||
emits('highlight-airspace', airspace.name)
|
emits('highlight-airspace', airspace.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const runways = computed(() => {
|
||||||
|
const runwayPairs = {};
|
||||||
|
|
||||||
|
for (const runway of props.infoWindow.airport.runways) {
|
||||||
|
runwayPairs[runway.designator] = runway;
|
||||||
|
}
|
||||||
|
|
||||||
|
return runwayPairs;
|
||||||
|
});
|
||||||
|
|
||||||
|
const runwaySurfaceName = (surface) => {
|
||||||
|
const surfaceMap = {
|
||||||
|
grass: "tráva",
|
||||||
|
concrete: "beton",
|
||||||
|
asphalt: "asfalt"
|
||||||
|
}
|
||||||
|
return surfaceMap[surface] || 'jiné'
|
||||||
|
}
|
||||||
|
|
||||||
|
const openedTab = ref("info");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@@ -66,7 +93,50 @@ const highlightAirspace = (airspace) => {
|
|||||||
@close="emits('close')"
|
@close="emits('close')"
|
||||||
:options="{position: infoWindow.position}"
|
:options="{position: infoWindow.position}"
|
||||||
>
|
>
|
||||||
<div class="text-h5">{{ title }}</div>
|
|
||||||
|
<q-tabs v-model="openedTab">
|
||||||
|
<q-tab name="info">{{ title }}</q-tab>
|
||||||
|
<q-tab name="airspaces" v-if="infoWindow.airspaces?.length">Prostory</q-tab>
|
||||||
|
</q-tabs>
|
||||||
|
<q-tab-panels v-model="openedTab">
|
||||||
|
<q-tab-panel name="info">
|
||||||
|
<div v-if="infoWindow.airport">
|
||||||
|
Elevace: {{ infoWindow.airport.elevation }} m
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<q-list dense>
|
||||||
|
<q-item dense v-for="runway in runways" :key="runway">
|
||||||
|
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>
|
||||||
|
<strong>{{ runway.designator }}</strong> ({{ runwaySurfaceName(runway.surface) }})
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label caption>
|
||||||
|
{{ runway.heading }}°, {{ runway.width }} × {{ runway.length }}
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<q-list>
|
||||||
|
<q-item dense v-for="frequency in infoWindow.airport.frequencies" :key="frequency">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>
|
||||||
|
<strong>{{ frequency.name }}</strong>
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label caption>
|
||||||
|
{{ frequency.frequency }}
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="infoWindow.marker">
|
<div v-if="infoWindow.marker">
|
||||||
<span class="text-h6">
|
<span class="text-h6">
|
||||||
@@ -78,9 +148,8 @@ const highlightAirspace = (airspace) => {
|
|||||||
<div v-if="infoWindow.poi">
|
<div v-if="infoWindow.poi">
|
||||||
<q-img :src="infoWindow.poi.titlePhoto.thumbnailUrl" width="300px" v-if="infoWindow.poi.titlePhoto"/>
|
<q-img :src="infoWindow.poi.titlePhoto.thumbnailUrl" width="300px" v-if="infoWindow.poi.titlePhoto"/>
|
||||||
</div>
|
</div>
|
||||||
|
</q-tab-panel>
|
||||||
<template v-if="infoWindow.airspaces?.length">
|
<q-tab-panel name="airspaces" v-if="infoWindow.airspaces?.length">
|
||||||
<span class="text-h6">Prostory</span>
|
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item-label v-for="airspace in infoWindow.airspaces" :key="airspace.name">
|
<q-item-label v-for="airspace in infoWindow.airspaces" :key="airspace.name">
|
||||||
<q-avatar size="16px" class="q-mx-sm" :style="`border: solid 1px; background: ${getColorByType(airspace.type)}`"/>
|
<q-avatar size="16px" class="q-mx-sm" :style="`border: solid 1px; background: ${getColorByType(airspace.type)}`"/>
|
||||||
@@ -109,13 +178,28 @@ const highlightAirspace = (airspace) => {
|
|||||||
/>
|
/>
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
</q-list>
|
</q-list>
|
||||||
</template>
|
</q-tab-panel>
|
||||||
|
</q-tab-panels>
|
||||||
|
|
||||||
|
<template v-if="showActions">
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="showActions"
|
v-if="infoWindow.marker"
|
||||||
class="q-mt-lg"
|
class="q-mt-lg full-width"
|
||||||
|
color="warning"
|
||||||
|
@click="removePoint(infoWindow.marker.position)"
|
||||||
|
>
|
||||||
|
Odebrat z trasy
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
v-else
|
||||||
|
class="full-width q-mt-lg"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
@click="addPoint()">
|
@click="addPoint()"
|
||||||
|
>
|
||||||
Přidat bod do trasy
|
Přidat bod do trasy
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
</InfoWindow>
|
</InfoWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(["map-click", "add-to-route"]);
|
const emits = defineEmits(["map-click", "add-to-route", "remove-from-route"]);
|
||||||
|
|
||||||
const key = process.env.GOOGLE_MAPS_API_KEY;
|
const key = process.env.GOOGLE_MAPS_API_KEY;
|
||||||
|
|
||||||
@@ -89,17 +89,20 @@ const airspaces = computed(() => {
|
|||||||
.map(airspace => {
|
.map(airspace => {
|
||||||
|
|
||||||
let fillOpacity = 0;
|
let fillOpacity = 0;
|
||||||
|
let strokeWeight = 1;
|
||||||
if (["PROHIBIT", "RESTRICT"].includes(airspace.type))
|
if (["PROHIBIT", "RESTRICT"].includes(airspace.type))
|
||||||
fillOpacity = 0.1;
|
fillOpacity = 0.1;
|
||||||
if (highlightedAirspaces.value.includes(airspace.name))
|
if (highlightedAirspaces.value.includes(airspace.name)) {
|
||||||
fillOpacity = 0.2;
|
strokeWeight = 2;
|
||||||
|
fillOpacity = 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
name: airspace.name,
|
name: airspace.name,
|
||||||
strokeColor: colorsMap[airspace.type],
|
strokeColor: colorsMap[airspace.type],
|
||||||
fillColor: colorsMap[airspace.type],
|
fillColor: colorsMap[airspace.type],
|
||||||
strokeOpacity: 0.5,
|
strokeOpacity: 0.5,
|
||||||
strokeWeight: 1,
|
strokeWeight,
|
||||||
fillOpacity,
|
fillOpacity,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -146,6 +149,14 @@ const emitMapClick = (data) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const highlightedAirspaces = ref([]);
|
const highlightedAirspaces = ref([]);
|
||||||
|
const highlightAirspace = (airspaceName) => {
|
||||||
|
const airspace = props.airspacesData.find(a => a.name === airspaceName);
|
||||||
|
|
||||||
|
if (airspace) {
|
||||||
|
highlightedAirspaces.value = [airspaceName];
|
||||||
|
displayAirspaceLayers.value[airspace.type] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleMapClick = (e) => {
|
const handleMapClick = (e) => {
|
||||||
const position = {lat: e.latLng.lat(), lng: e.latLng.lng()};
|
const position = {lat: e.latLng.lat(), lng: e.latLng.lng()};
|
||||||
@@ -192,7 +203,8 @@ const handleAirportClick = (airport) => {
|
|||||||
:highlighted-airspaces="highlightedAirspaces"
|
:highlighted-airspaces="highlightedAirspaces"
|
||||||
@close="infoWindow.active=false"
|
@close="infoWindow.active=false"
|
||||||
@add-to-route="emits('add-to-route', $event)"
|
@add-to-route="emits('add-to-route', $event)"
|
||||||
@highlight-airspace="highlightedAirspaces = [$event]"
|
@remove-from-route="emits('remove-from-route', $event)"
|
||||||
|
@highlight-airspace="highlightAirspace"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<template v-for="airspace in airspaces" :key="airspace.name">
|
<template v-for="airspace in airspaces" :key="airspace.name">
|
||||||
|
|||||||
@@ -7,11 +7,23 @@ export const FRAGMENT_AIRPORT_INFO = gql`
|
|||||||
icaoCode
|
icaoCode
|
||||||
gpsLatitude
|
gpsLatitude
|
||||||
gpsLongitude
|
gpsLongitude
|
||||||
|
elevation
|
||||||
reportingPoints {
|
reportingPoints {
|
||||||
id
|
id
|
||||||
gpsLatitude
|
gpsLatitude
|
||||||
gpsLongitude
|
gpsLongitude
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
frequencies {
|
||||||
|
frequency
|
||||||
|
name
|
||||||
|
}
|
||||||
|
runways {
|
||||||
|
designator
|
||||||
|
heading
|
||||||
|
surface
|
||||||
|
length
|
||||||
|
width
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
Reference in New Issue
Block a user