Pridani linku na planovac do menu, drobny bugfixing
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<script setup>
|
||||
import {computed} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
lowerLimit: {
|
||||
type: [String, Number],
|
||||
required: true,
|
||||
},
|
||||
lowerLimitUnit: {
|
||||
type: String,
|
||||
required: false // GND nema jednotky
|
||||
},
|
||||
upperLimit: {
|
||||
type: [String, Number],
|
||||
required: true,
|
||||
},
|
||||
upperLimitUnit: {
|
||||
type: String,
|
||||
required: false // GND nema jednotky
|
||||
}
|
||||
})
|
||||
|
||||
const getLimitFormatted = (limit, unit) => {
|
||||
return `${limit} ${unit}`
|
||||
}
|
||||
|
||||
const upper = computed(() => getLimitFormatted(props.upperLimit, props.upperLimitUnit));
|
||||
const lower = computed(() => getLimitFormatted(props.lowerLimit, props.lowerLimitUnit));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="altitude-limit">
|
||||
<span class="upper">
|
||||
{{ upper}}
|
||||
</span>
|
||||
<span class="lower">
|
||||
{{ lower }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.altitude-limit {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-size: 12px;
|
||||
|
||||
.upper, .lower {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upper {
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,9 +2,9 @@
|
||||
import {computed, ref, watch} from "vue";
|
||||
import {Marker, CustomMarker, Polyline} from "vue3-google-map";
|
||||
import MapWrapper from "components/map/MapWrapper.vue";
|
||||
import AirspaceInfoWindow from "components/map/AirspaceInfoWindow.vue";
|
||||
import {useFlightPlanObjects, useFlightPlanUtils} from "src/composables/flightPlan";
|
||||
import {useGeocode} from "src/composables/geocoding";
|
||||
import AltitudeLimit from "components/AltitudeLimit.vue";
|
||||
|
||||
const props = defineProps({
|
||||
flightPlan: {
|
||||
@@ -35,24 +35,14 @@ const {center} = useGeocode();
|
||||
const {markerObject, googleMapsMarkerObject, infoWindowObject, editableNameTypes} = useFlightPlanObjects();
|
||||
const {getMarkersFrom} = useFlightPlanUtils();
|
||||
|
||||
const infoWindow = ref(infoWindowObject({}));
|
||||
|
||||
const handleMapClick = ({clickCoordinates, airspaces, airport, reportingPoint}) => {
|
||||
infoWindow.value = infoWindowObject({
|
||||
active: true,
|
||||
position: clickCoordinates,
|
||||
airspaces,
|
||||
airport,
|
||||
reportingPoint,
|
||||
})
|
||||
}
|
||||
const mapWrap = ref(null);
|
||||
|
||||
const handleMarkerClick = (marker) => {
|
||||
infoWindow.value = infoWindowObject({active: true, marker})
|
||||
mapWrap.value.openInfoWindow({marker});
|
||||
}
|
||||
|
||||
const handlePoiClick = (poi) => {
|
||||
infoWindow.value = infoWindowObject({active: true, poi})
|
||||
mapWrap.value.openInfoWindow({poi});
|
||||
}
|
||||
|
||||
const markers = ref([]);
|
||||
@@ -69,10 +59,10 @@ const addMarker = async (point) => {
|
||||
const insertAt = Math.min(markers.value.length, props.insertPosition);
|
||||
|
||||
markers.value.splice(insertAt, 0, markerObject({...point}));
|
||||
infoWindow.value = infoWindowObject({active: false});
|
||||
// infoWindow.value = infoWindowObject({active: false});
|
||||
|
||||
emits("markers-changed", markers.value);
|
||||
emits("change-insert-position",insertAt + 1);
|
||||
emits("change-insert-position", insertAt + 1);
|
||||
}
|
||||
|
||||
const {searchPlaceName} = useGeocode();
|
||||
@@ -88,6 +78,7 @@ const handleMarkerMove = async (idx, event) => {
|
||||
|
||||
<template>
|
||||
<MapWrapper
|
||||
ref="mapWrap"
|
||||
style="width: 100%; height: 100%; min-height: 500px"
|
||||
:center="center"
|
||||
:zoom="8"
|
||||
@@ -95,15 +86,9 @@ const handleMarkerMove = async (idx, event) => {
|
||||
:airports="airports"
|
||||
v-bind="$attrs"
|
||||
:fullscreen-control="false"
|
||||
@map-click="handleMapClick"
|
||||
>
|
||||
<AirspaceInfoWindow
|
||||
v-if="infoWindow.active"
|
||||
:info-window="infoWindow"
|
||||
@close="infoWindow.active=false"
|
||||
@add-to-route="addMarker"
|
||||
/>
|
||||
@add-to-route="addMarker"
|
||||
|
||||
>
|
||||
<template v-for="poi in pointsOfInterest" :key="poi.name">
|
||||
<CustomMarker
|
||||
v-if="poi.gpsLatitude && poi.gpsLongitude"
|
||||
|
||||
@@ -19,7 +19,7 @@ const props = defineProps({
|
||||
v-ripple
|
||||
v-for="flightPlan of items" :key="flightPlan">
|
||||
<q-item-section avatar>
|
||||
<q-avatar icon="person" color="primary" text-color="white"/>
|
||||
<q-avatar icon="flight" color="primary" text-color="white"/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>
|
||||
|
||||
@@ -20,7 +20,7 @@ const props = defineProps({
|
||||
});
|
||||
const emits = defineEmits(["update:gpsLatitude", "update:gpsLongitude", "notFound"]);
|
||||
|
||||
const {emitModels, setCoordinatesFromGeocode, center, zoom} = useGeocode(emits);
|
||||
const {emitModels, setCoordinatesFromGeocode, searchGeocode, center, zoom} = useGeocode(emits);
|
||||
const markerDropped = (position) => {
|
||||
emitModels(position.latLng.lat(), position.latLng.lng());
|
||||
}
|
||||
@@ -30,6 +30,9 @@ onMounted(() => {
|
||||
center.value.lng = props.gpsLongitude;
|
||||
center.value.lat = props.gpsLatitude
|
||||
} else if (props.label) {
|
||||
searchGeocode(props.label).then(result => {
|
||||
|
||||
});
|
||||
setCoordinatesFromGeocode(props.label);
|
||||
} else {
|
||||
console.error("Set either label or gps coordinates.");
|
||||
|
||||
@@ -2,16 +2,28 @@
|
||||
import {InfoWindow} from "vue3-google-map";
|
||||
import {useFlightPlanUtils} from "src/composables/flightPlan";
|
||||
import {useGeocode} from "src/composables/geocoding";
|
||||
import {onMounted, ref, watch} from "vue";
|
||||
import {ref, watch} from "vue";
|
||||
import {useAirspaceColors} from "src/composables/airspaces";
|
||||
import AltitudeLimit from "components/AltitudeLimit.vue";
|
||||
|
||||
const props = defineProps({
|
||||
infoWindow: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
highlightedAirspaces: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => []
|
||||
},
|
||||
showActions: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["add-to-route", "close"])
|
||||
const emits = defineEmits(["add-to-route", "highlight-airspace", "close"])
|
||||
|
||||
const {getIcon} = useFlightPlanUtils();
|
||||
const {searchPlaceName} = useGeocode()
|
||||
@@ -41,6 +53,11 @@ const addPoint = async () => {
|
||||
}
|
||||
emits("add-to-route", point)
|
||||
}
|
||||
|
||||
const {getColorByType} = useAirspaceColors();
|
||||
const highlightAirspace = (airspace) => {
|
||||
emits('highlight-airspace', airspace.name)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -52,25 +69,54 @@ const addPoint = async () => {
|
||||
<div class="text-h5">{{ title }}</div>
|
||||
|
||||
<div v-if="infoWindow.marker">
|
||||
<span class="text-h6">
|
||||
<q-icon :name="getIcon(infoWindow.marker.type)"/>
|
||||
{{ infoWindow.marker.name }}
|
||||
</span>
|
||||
<span class="text-h6">
|
||||
<q-icon :name="getIcon(infoWindow.marker.type)"/>
|
||||
{{ infoWindow.marker.name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="infoWindow.poi">
|
||||
<q-img :src="infoWindow.poi.titlePhoto.thumbnailUrl" v-if="infoWindow.poi.titlePhoto"/>
|
||||
{{ infoWindow.poi.name }}
|
||||
|
||||
{{ infoWindow.poi }}
|
||||
</div>
|
||||
|
||||
<template v-if="infoWindow.airspaces?.length">
|
||||
<span class="text-h6">Prostory</span>
|
||||
<div v-for="airspace in infoWindow.airspaces" :key="airspace">
|
||||
{{ airspace.name }}
|
||||
</div>
|
||||
<q-list>
|
||||
<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)}`"/>
|
||||
|
||||
<strong>
|
||||
{{ airspace.name }}
|
||||
</strong>
|
||||
|
||||
<AltitudeLimit
|
||||
class="q-mx-md"
|
||||
:upper-limit="airspace.upperLimit"
|
||||
:upper-limit-unit="airspace.upperAltUnit"
|
||||
:lower-limit="airspace.lowerLimit"
|
||||
:lower-limit-unit="airspace.lowerAltUnit"
|
||||
/>
|
||||
|
||||
<q-btn
|
||||
v-if="airspace.type !== 'FIR'"
|
||||
color="white"
|
||||
:text-color="props.highlightedAirspaces.includes(airspace.name) ? 'primary' : 'grey-6'"
|
||||
size="x-small"
|
||||
round
|
||||
text
|
||||
icon="mdi-eye"
|
||||
@click="highlightAirspace(airspace)"
|
||||
/>
|
||||
</q-item-label>
|
||||
</q-list>
|
||||
</template>
|
||||
<q-btn class="q-mt-lg" color="secondary" @click="addPoint()">Přidat bod do trasy</q-btn>
|
||||
<q-btn
|
||||
v-if="showActions"
|
||||
class="q-mt-lg"
|
||||
color="secondary"
|
||||
@click="addPoint()">
|
||||
Přidat bod do trasy
|
||||
</q-btn>
|
||||
</InfoWindow>
|
||||
</template>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import {Circle, GoogleMap, CustomControl, CustomMarker, Polygon} from "vue3-google-map";
|
||||
import {computed, ref, watch} from "vue";
|
||||
import {useBasicVectorOperations, useVectorUtilities} from "src/graphql/fragments/vectorUtilities";
|
||||
import {useAirspaceColors} from "src/composables/airspaces";
|
||||
import AirspaceInfoWindow from "components/map/AirspaceInfoWindow.vue";
|
||||
import {useFlightPlanObjects} from "src/composables/flightPlan";
|
||||
|
||||
const props = defineProps({
|
||||
bounds: {
|
||||
@@ -18,6 +21,16 @@ const props = defineProps({
|
||||
required: false,
|
||||
default: () => []
|
||||
},
|
||||
showInfoWindow: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
allowAddMarker: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
showLayerControls: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
@@ -25,7 +38,7 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["map-click"]);
|
||||
const emits = defineEmits(["map-click", "add-to-route"]);
|
||||
|
||||
const key = process.env.GOOGLE_MAPS_API_KEY;
|
||||
|
||||
@@ -68,18 +81,7 @@ const displayAirspaceLayers = ref({
|
||||
});
|
||||
|
||||
const airspaces = computed(() => {
|
||||
const colorsMap = {
|
||||
TMA: "#800080",
|
||||
CTR: "#366e36",
|
||||
PROHIBIT: "#FF0000",
|
||||
RMZ: "#FFdd00",
|
||||
RESTRICT: "#ff6a00",
|
||||
DANGER: "#FFA500",
|
||||
TRAGA: "#008000",
|
||||
ATZ: "#4e7cfc",
|
||||
FIR: '#ffffff',
|
||||
PARA: "#000000"
|
||||
}
|
||||
const colorsMap = useAirspaceColors().colors;
|
||||
|
||||
return props.airspacesData
|
||||
.filter(airspace => !!colorsMap[airspace.type])
|
||||
@@ -103,9 +105,6 @@ const airspaces = computed(() => {
|
||||
|
||||
if (airspace.mapBounds.length > 0) {
|
||||
data['path'] = airspace.mapBounds;
|
||||
} else {
|
||||
data['center'] = airspace.mapCenter;
|
||||
data['radius'] = airspace.radius
|
||||
}
|
||||
|
||||
return data
|
||||
@@ -121,41 +120,61 @@ const airportsOnMap = computed(() => {
|
||||
const {isPointInPolygon, vectorDistanceToKm} = useVectorUtilities();
|
||||
const {vectorDistance} = useBasicVectorOperations();
|
||||
|
||||
const highlightedAirspaces = ref([]);
|
||||
|
||||
const getAirspacesAtCoordinates = (clickCoordinates) => {
|
||||
const airspacesUnderClick = []
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
return airspacesUnderClick;
|
||||
}
|
||||
const handleMapClick = (e) => {
|
||||
const clickCoordinates = {lat: e.latLng.lat(), lng: e.latLng.lng()}
|
||||
|
||||
const airspacesUnderClick = getAirspacesAtCoordinates(clickCoordinates);
|
||||
const {infoWindowObject} = useFlightPlanObjects();
|
||||
const infoWindow = ref(infoWindowObject({}));
|
||||
|
||||
const openInfoWindow = (data) => {
|
||||
infoWindow.value = infoWindowObject({active: true, ...data});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
openInfoWindow
|
||||
});
|
||||
|
||||
const emitMapClick = (data) => {
|
||||
openInfoWindow(data);
|
||||
emits("map-click", data);
|
||||
}
|
||||
|
||||
const highlightedAirspaces = ref([]);
|
||||
|
||||
const handleMapClick = (e) => {
|
||||
const position = {lat: e.latLng.lat(), lng: e.latLng.lng()};
|
||||
|
||||
const airspacesUnderClick = getAirspacesAtCoordinates(position);
|
||||
highlightedAirspaces.value = airspacesUnderClick.map(a => a.name);
|
||||
|
||||
emits("map-click", {airspaces: airspacesUnderClick, clickCoordinates});
|
||||
emitMapClick({position, airspaces: airspacesUnderClick});
|
||||
}
|
||||
|
||||
const handleReportingPointClick = (airport, reportingPoint) => {
|
||||
const position = {lat: reportingPoint.gpsLatitude, lng: reportingPoint.gpsLongitude};
|
||||
emits("map-click", {clickCoordinates: position, airport, reportingPoint})
|
||||
|
||||
const airspacesUnderClick = getAirspacesAtCoordinates(position);
|
||||
highlightedAirspaces.value = [];
|
||||
|
||||
|
||||
emitMapClick({position, airport, reportingPoint, airspaces: airspacesUnderClick})
|
||||
}
|
||||
|
||||
const handleAirportClick = (airport) => {
|
||||
const position = {lat: airport.gpsLatitude, lng: airport.gpsLongitude};
|
||||
emits("map-click", {clickCoordinates: position, airport})
|
||||
|
||||
const airspacesUnderClick = getAirspacesAtCoordinates(position);
|
||||
highlightedAirspaces.value = [];
|
||||
|
||||
|
||||
emitMapClick({position, airport, airspaces: airspacesUnderClick})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -169,6 +188,15 @@ const handleAirportClick = (airport) => {
|
||||
:max-zoom="13"
|
||||
ref="mapRef"
|
||||
>
|
||||
<AirspaceInfoWindow
|
||||
v-if="infoWindow.active"
|
||||
:info-window="infoWindow"
|
||||
:highlighted-airspaces="highlightedAirspaces"
|
||||
@close="infoWindow.active=false"
|
||||
@add-to-route="emits('add-to-route', $event)"
|
||||
@highlight-airspace="highlightedAirspaces = [$event]"
|
||||
/>
|
||||
|
||||
<template v-for="airspace in airspaces" :key="airspace.name">
|
||||
<Polygon :options="airspace" @click="handleMapClick"/>
|
||||
</template>
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
v-if="icon"
|
||||
avatar
|
||||
>
|
||||
<q-icon :name="icon" />
|
||||
<q-icon :name="icon"/>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label>{{ title }}</q-item-label>
|
||||
<q-item-label caption>{{ caption }}</q-item-label>
|
||||
<q-item-label caption v-if="caption">{{ caption }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
@@ -24,26 +24,21 @@ import {computed} from "vue";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
caption: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
to: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
to: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
caption: {
|
||||
type: String,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
}
|
||||
});
|
||||
|
||||
const $route = useRoute();
|
||||
const $router = useRouter();
|
||||
@@ -51,7 +46,7 @@ const isButtonActive = computed(() => {
|
||||
const btnResolvedPath = $router.resolve(props.to).path;
|
||||
|
||||
if (props.to.name === 'myFlights') {
|
||||
return $route.name.toLowerCase().includes("flight");
|
||||
return ["myFlights", "addFlight", "flightDetail", "flightEdit"].includes($route.name);
|
||||
} else {
|
||||
return $route.fullPath === btnResolvedPath || $route.fullPath.startsWith(btnResolvedPath);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,15 @@ const linksList = [
|
||||
{
|
||||
title: 'Moje lety',
|
||||
icon: "flight_takeoff",
|
||||
to: {name: "myFlights"}
|
||||
to: {name: "myFlights"},
|
||||
},
|
||||
{separator: true},
|
||||
{
|
||||
title: 'Moje plány',
|
||||
icon: "pin_drop",
|
||||
to: {name: "flightPlans"}
|
||||
},
|
||||
|
||||
{separator: true},
|
||||
|
||||
{
|
||||
title: 'Letadla',
|
||||
|
||||
Reference in New Issue
Block a user