Vicemene funkcni mapova cast planovace

This commit is contained in:
Michal Kváček
2024-04-29 06:45:29 +02:00
parent bc0b5e2f15
commit 0760e6fb1c
9 changed files with 111 additions and 70 deletions
+9 -3
View File
@@ -37,8 +37,14 @@ const {getMarkersFrom} = useFlightPlanUtils();
const infoWindow = ref(infoWindowObject({})); const infoWindow = ref(infoWindowObject({}));
const handleMapClick = ({clickCoordinates, airspaces, airport}) => { const handleMapClick = ({clickCoordinates, airspaces, airport, reportingPoint}) => {
infoWindow.value = infoWindowObject({active: true, airspaces, position: clickCoordinates, airport}) infoWindow.value = infoWindowObject({
active: true,
position: clickCoordinates,
airspaces,
airport,
reportingPoint,
})
} }
const handleMarkerClick = (marker) => { const handleMarkerClick = (marker) => {
@@ -81,7 +87,6 @@ const handleMarkerMove = async (idx, event) => {
</script> </script>
<template> <template>
vkladam na pozici {{ insertPosition }}
<MapWrapper <MapWrapper
style="width: 100%; height: 100%; min-height: 500px" style="width: 100%; height: 100%; min-height: 500px"
:center="center" :center="center"
@@ -89,6 +94,7 @@ const handleMarkerMove = async (idx, event) => {
:airspaces-data="airspaceData" :airspaces-data="airspaceData"
:airports="airports" :airports="airports"
v-bind="$attrs" v-bind="$attrs"
:fullscreen-control="false"
@map-click="handleMapClick" @map-click="handleMapClick"
> >
<AirspaceInfoWindow <AirspaceInfoWindow
@@ -55,38 +55,41 @@ const totalTime = computed(() => {
</q-item-section> </q-item-section>
</q-item> </q-item>
<template v-for="(segment, i) in props.flightPlan.track" :key="segment"> <q-scroll-area style="height: 50vh">
<q-item dense> <template v-for="(segment, i) in props.flightPlan.track" :key="segment">
<q-item-section> <q-item dense>
<q-item-label>{{ segment.from.name }}</q-item-label> <q-item-section>
<q-item-label caption class="q-py-sm" v-if="segment.distance"> <q-item-label>{{ segment.from.name }}</q-item-label>
{{ segment.bearing }}°, <q-item-label caption class="q-py-sm" v-if="segment.distance">
{{ segment.distance }} km, {{ segment.bearing }}°,
{{ minutesToHumanReadable(getDuration(segment.distance, props.plannedSpeed)) }} {{ segment.distance }} km,
</q-item-label> {{ minutesToHumanReadable(getDuration(segment.distance, props.plannedSpeed)) }}
<q-item-label> </q-item-label>
<q-btn <q-item-label>
@click="emits('change-insert-position', i+1)" <q-btn
icon="add" @click="emits('change-insert-position', i+1)"
size="sm" icon="add"
class="q-ml-lg q-mb-sm" size="sm"
:round="insertPosition !== i+1" class="q-ml-lg q-mb-sm"
:color="insertPosition === i+1 ? 'primary' : 'grey'" :round="insertPosition !== i+1"
> :color="insertPosition === i+1 ? 'primary' : 'grey'"
<template v-if="insertPosition === i+1">Přidávám sem</template> >
</q-btn> <template v-if="insertPosition === i+1">Přidávám sem</template>
</q-item-label> </q-btn>
</q-item-section> </q-item-label>
</q-item> </q-item-section>
</q-item>
<q-item dense v-if="segment.to && i === props.flightPlan.track.length - 1">
<q-item-section> <q-item dense v-if="segment.to && i === props.flightPlan.track.length - 1">
<q-item-label> <q-item-section>
{{ segment.to.name }} <q-item-label>
</q-item-label> {{ segment.to.name }}
</q-item-section> </q-item-label>
</q-item> </q-item-section>
</template> </q-item>
</template>
</q-scroll-area>
<q-item> <q-item>
<q-item-section> <q-item-section>
<div> <div>
@@ -42,8 +42,15 @@ const {getIcon} = useFlightPlanUtils();
const {editableNameTypes} = useFlightPlanObjects(); const {editableNameTypes} = useFlightPlanObjects();
const allPlacesOptions = computed(() => { const allPlacesOptions = computed(() => {
const reportingPoints = props.airports.map(a => a.reportingPoints.map(r => ({...r, airport: a}))).flat()
return [ return [
...props.pointsOfInterest.map(poi => ({...poi, type: "poi"})), ...props.pointsOfInterest.map(poi => ({...poi, type: "poi"})),
...reportingPoints.map(r => ({
...r,
name: `${r.airport.icaoCode}:${r.name}`,
type: "reportingPoint"
})),
...props.airports.map(airport => ({ ...props.airports.map(airport => ({
...airport, ...airport,
name: `${airport.icaoCode} - ${airport.name}`, name: `${airport.icaoCode} - ${airport.name}`,
+38 -20
View File
@@ -58,6 +58,7 @@ const displayAirspaceLayers = ref({
TMA: true, TMA: true,
RMZ: false, RMZ: false,
ATZ: true, ATZ: true,
PARA: false,
DANGER: false, DANGER: false,
PROHIBIT: true, PROHIBIT: true,
RESTRICT: true, RESTRICT: true,
@@ -68,29 +69,29 @@ const displayAirspaceLayers = ref({
const airspaces = computed(() => { const airspaces = computed(() => {
const colorsMap = { const colorsMap = {
C: "#800080", TMA: "#800080",
D: "#800080", CTR: "#366e36",
CTR: "#00ff00", PROHIBIT: "#FF0000",
P: "#FF0000",
RMZ: "#FFdd00", RMZ: "#FFdd00",
R: "#ff6a00", RESTRICT: "#ff6a00",
Q: "#FFA500", DANGER: "#FFA500",
PGZ: "#008000", TRAGA: "#008000",
GSEC: "#008000",
ATZ: "#4e7cfc", ATZ: "#4e7cfc",
FIR: '#ffffff' FIR: '#ffffff',
PARA: "#000000"
} }
return props.airspacesData return props.airspacesData
.filter(airspace => !!colorsMap[airspace.type]) .filter(airspace => !!colorsMap[airspace.type])
.filter(airspace => { .filter(airspace => {
if (['C', 'D'].includes(airspace.type)) return displayAirspaceLayers.value.TMA; if (['TMA'].includes(airspace.type)) return displayAirspaceLayers.value.TMA;
if (['PGZ', 'GSEC'].includes(airspace.type)) return displayAirspaceLayers.value.TRAGA; if (['TRAGA'].includes(airspace.type)) return displayAirspaceLayers.value.TRAGA;
if (airspace.type === 'CTR') return displayAirspaceLayers.value.CTR; if (airspace.type === 'CTR') return displayAirspaceLayers.value.CTR;
if (airspace.type === 'RMZ') return displayAirspaceLayers.value.RMZ; if (airspace.type === 'RMZ') return displayAirspaceLayers.value.RMZ;
if (airspace.type === 'Q') return displayAirspaceLayers.value.DANGER; if (airspace.type === 'DANGER') return displayAirspaceLayers.value.DANGER;
if (airspace.type === 'P') return displayAirspaceLayers.value.PROHIBIT; if (airspace.type === 'PROHIBIT') return displayAirspaceLayers.value.PROHIBIT;
if (airspace.type === 'R') return displayAirspaceLayers.value.RESTRICT; if (airspace.type === 'RESTRICT') return displayAirspaceLayers.value.RESTRICT;
if (airspace.type === 'PARA') return displayAirspaceLayers.value.PARA;
if (airspace.type === 'ATZ') return displayAirspaceLayers.value.ATZ; if (airspace.type === 'ATZ') return displayAirspaceLayers.value.ATZ;
return true; return true;
}) })
@@ -101,7 +102,7 @@ const airspaces = computed(() => {
strokeOpacity: 0.3, strokeOpacity: 0.3,
strokeWeight: 3, strokeWeight: 3,
fillColor: colorsMap[airspace.type], fillColor: colorsMap[airspace.type],
fillOpacity: 0, fillOpacity: ["PROHIBIT", "RESTRICT"].includes(airspace.type) ? 0.1 : 0,
}; };
if (airspace.mapBounds.length > 0) { if (airspace.mapBounds.length > 0) {
@@ -146,6 +147,11 @@ const handleMapClick = (e) => {
emits("map-click", {airspaces: getAirspacesAtCoordinates(clickCoordinates), clickCoordinates}); emits("map-click", {airspaces: getAirspacesAtCoordinates(clickCoordinates), clickCoordinates});
} }
const handleReportingPointClick = (airport, reportingPoint) => {
const position = {lat: reportingPoint.gpsLatitude, lng: reportingPoint.gpsLongitude};
emits("map-click", {clickCoordinates: position, airport, reportingPoint})
}
const handleAirportClick = (airport) => { const handleAirportClick = (airport) => {
const position = {lat: airport.gpsLatitude, lng: airport.gpsLongitude}; const position = {lat: airport.gpsLatitude, lng: airport.gpsLongitude};
emits("map-click", {clickCoordinates: position, airport}) emits("map-click", {clickCoordinates: position, airport})
@@ -163,24 +169,35 @@ const handleAirportClick = (airport) => {
ref="mapRef" ref="mapRef"
> >
<template v-for="airspace in airspaces" :key="airspace.name"> <template v-for="airspace in airspaces" :key="airspace.name">
<Polygon :options="airspace" @click=handleMapClick v-if="airspace.path"/> <Polygon :options="airspace" @click="handleMapClick" />
<Circle :options="airspace" @click=handleMapClick v-if="airspace.center && airspace.radius"/>
</template> </template>
<slot/>
<template v-for="airport in airportsOnMap" :key="airport.icaoCode"> <template v-for="airport in airportsOnMap" :key="airport.icaoCode">
<CustomMarker <CustomMarker
:options="{position: {lat: airport.gpsLatitude, lng: airport.gpsLongitude}, anchorPoint: 'CENTER'}" :options="{position: {lat: airport.gpsLatitude, lng: airport.gpsLongitude}, anchorPoint: 'CENTER'}"
@click.stop="handleAirportClick(airport)" @click.stop="handleAirportClick(airport)"
> >
<q-chip size="xs">{{ airport.icaoCode }}</q-chip> <q-chip size="xs">{{ airport.icaoCode }}</q-chip>
</CustomMarker> </CustomMarker>
<template v-if="displayAirspaceLayers.CTR">
<CustomMarker
v-for="reportingPoint in airport.reportingPoints" :key="reportingPoint.id"
:options="{position: {lat: reportingPoint.gpsLatitude, lng: reportingPoint.gpsLongitude, anchorPoint: 'CENTER'}}"
@click.stop="handleReportingPointClick(airport, reportingPoint)"
:title="`${airport.icaoCode}: ${reportingPoint.name}`"
>
<q-icon name="mdi-triangle"/>
</CustomMarker>
</template>
</template> </template>
<slot/>
<CustomControl position="BOTTOM_CENTER" class="text-center" v-if="showLayerControls"> <CustomControl position="BOTTOM_CENTER" class="text-center" v-if="showLayerControls">
<q-card class="q-my-md q-mx-auto q-px-lg" style="max-width: 98%;"> <q-card class="q-my-md q-mx-auto q-px-lg" style="max-width: 98%;">
<q-checkbox v-model="displayAirspaceLayers.CTR" label="M/CTR"/> <q-checkbox v-model="displayAirspaceLayers.CTR" label="CTR"/>
<q-checkbox v-model="displayAirspaceLayers.TMA" label="TMA"/> <q-checkbox v-model="displayAirspaceLayers.TMA" label="TMA"/>
<q-checkbox v-model="displayAirspaceLayers.RMZ" label="RMZ"/> <q-checkbox v-model="displayAirspaceLayers.RMZ" label="RMZ"/>
<q-checkbox v-model="displayAirspaceLayers.ATZ" label="ATZ"/> <q-checkbox v-model="displayAirspaceLayers.ATZ" label="ATZ"/>
@@ -188,6 +205,7 @@ const handleAirportClick = (airport) => {
<q-checkbox v-model="displayAirspaceLayers.PROHIBIT" label="Zakázané prostory"/> <q-checkbox v-model="displayAirspaceLayers.PROHIBIT" label="Zakázané prostory"/>
<q-checkbox v-model="displayAirspaceLayers.RESTRICT" label="TRA"/> <q-checkbox v-model="displayAirspaceLayers.RESTRICT" label="TRA"/>
<q-checkbox v-model="displayAirspaceLayers.TRAGA" label="TRAGA"/> <q-checkbox v-model="displayAirspaceLayers.TRAGA" label="TRAGA"/>
<q-checkbox v-model="displayAirspaceLayers.PARA" label="PARA"/>
<q-checkbox v-model="displayAirspaceLayers.AIRPORTS" label="Letiště"/> <q-checkbox v-model="displayAirspaceLayers.AIRPORTS" label="Letiště"/>
<q-checkbox v-model="displayAirspaceLayers.FIELDSTRIP" label="SLZ plochy"/> <q-checkbox v-model="displayAirspaceLayers.FIELDSTRIP" label="SLZ plochy"/>
</q-card> </q-card>
+11 -5
View File
@@ -52,7 +52,7 @@ export const useFlightPlanObjects = () => {
} }
} }
const infoWindowObject = ({active, position, marker, poi, airport, airspaces}) => { const infoWindowObject = ({active, position, marker, poi, airport, reportingPoint, airspaces}) => {
if (!position) position = {}; if (!position) position = {};
if (!position.lat) position.lat = 0; if (!position.lat) position.lat = 0;
if (!position.lng) position.lng = 0; if (!position.lng) position.lng = 0;
@@ -60,9 +60,15 @@ export const useFlightPlanObjects = () => {
let title = null; let title = null;
if (airport) { if (airport) {
title = `${airport.icaoCode} (${airport.name})`; if (!reportingPoint) {
position.lat = airport.gpsLatitude; title = `${airport.icaoCode} (${airport.name})`;
position.lng = airport.gpsLongitude; position.lat = airport.gpsLatitude;
position.lng = airport.gpsLongitude;
} else {
title = `${airport.icaoCode}:${reportingPoint.name}`
position.lat = reportingPoint.gpsLatitude;
position.lng = reportingPoint.gpsLongitude;
}
} }
if (marker) { if (marker) {
@@ -77,7 +83,7 @@ export const useFlightPlanObjects = () => {
position.lng = poi.gpsLongitude; position.lng = poi.gpsLongitude;
} }
return {title, active, position, airspaces, poi, marker, airport}; return {title, active, position, airspaces, poi, marker, airport, reportingPoint};
}; };
return {markerObject, googleMapsMarkerObject, googleMapsCustomMarkerObject, infoWindowObject, editableNameTypes} return {markerObject, googleMapsMarkerObject, googleMapsCustomMarkerObject, infoWindowObject, editableNameTypes}
+6
View File
@@ -7,5 +7,11 @@ export const FRAGMENT_AIRPORT_INFO = gql`
icaoCode icaoCode
gpsLatitude gpsLatitude
gpsLongitude gpsLongitude
reportingPoints {
id
gpsLatitude
gpsLongitude
name
}
} }
`; `;
+4 -5
View File
@@ -1,13 +1,12 @@
import gql from "graphql-tag"; import gql from "graphql-tag";
import {FRAGMENT_AIRPORT_INFO} from "src/graphql/fragments/airport";
export const AIRPORTS_LIST = gql` export const AIRPORTS_LIST = gql`
query AirportsList { query AirportsList {
airports { airports {
id ...airportInfo
name
icaoCode
gpsLatitude
gpsLongitude
} }
} }
${FRAGMENT_AIRPORT_INFO}
`; `;
+1 -5
View File
@@ -6,11 +6,7 @@ export const AIRSPACE_LIST = gql`
airspaces { airspaces {
name name
type type
mapCenter {
lat
lng
}
radius
mapBounds { mapBounds {
lat lat
lng lng
@@ -107,7 +107,7 @@ const insertAtPosition = ref(flightPlanMarkers.value.length);
@markers-changed="handleMarkersChanges" @markers-changed="handleMarkersChanges"
/> />
</div> </div>
<div class="col-12 col-md-5 col-lg-3"> <div class="col-12 col-md-5 col-lg-2">
<FlightPlanMarkersList <FlightPlanMarkersList
:insert-position="insertAtPosition" :insert-position="insertAtPosition"
:flight-plan="flightPlan" :flight-plan="flightPlan"