Vkladani mista na konkretni pozici
This commit is contained in:
@@ -22,19 +22,22 @@ const props = defineProps({
|
||||
pointsOfInterest: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
insertPosition: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
const emits = defineEmits(["markers-changed"]);
|
||||
const emits = defineEmits(["markers-changed", "change-insert-position"]);
|
||||
|
||||
const {center} = useGeocode();
|
||||
|
||||
const {markerObject, googleMapsCustomMarkerObject, googleMapsMarkerObject, infoWindowObject, editableNameTypes} = useFlightPlanObjects();
|
||||
const {getIcon, getMarkersFrom} = useFlightPlanUtils();
|
||||
const {markerObject, googleMapsMarkerObject, infoWindowObject, editableNameTypes} = useFlightPlanObjects();
|
||||
const {getMarkersFrom} = useFlightPlanUtils();
|
||||
|
||||
const infoWindow = ref(infoWindowObject({}));
|
||||
|
||||
const handleMapClick = ({clickCoordinates, airspaces, airport}) => {
|
||||
console.log(clickCoordinates, airspaces, airport);
|
||||
infoWindow.value = infoWindowObject({active: true, airspaces, position: clickCoordinates, airport})
|
||||
}
|
||||
|
||||
@@ -47,19 +50,23 @@ const handlePoiClick = (poi) => {
|
||||
}
|
||||
|
||||
const markers = ref([]);
|
||||
|
||||
watch(() => props.flightPlan.track, (newVal) => {
|
||||
markers.value = getMarkersFrom(props.flightPlan);
|
||||
}, {immediate: true, deep: true});
|
||||
|
||||
const track = computed(() => markers.value.map(m => ({lat: m.gpsLatitude, lng: m.gpsLongitude})));
|
||||
|
||||
|
||||
const addMarker = async (point) => {
|
||||
if (!point) return;
|
||||
markers.value.push(markerObject({...point}));
|
||||
|
||||
const insertAt = Math.min(markers.value.length, props.insertPosition);
|
||||
|
||||
markers.value.splice(insertAt, 0, markerObject({...point}));
|
||||
infoWindow.value = infoWindowObject({active: false});
|
||||
|
||||
emits("markers-changed", markers.value);
|
||||
infoWindow.value = infoWindowObject({active: false});
|
||||
emits("change-insert-position",insertAt + 1);
|
||||
}
|
||||
|
||||
const {searchPlaceName} = useGeocode();
|
||||
@@ -74,12 +81,14 @@ const handleMarkerMove = async (idx, event) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
vkladam na pozici {{ insertPosition }}
|
||||
<MapWrapper
|
||||
style="width: 100%; height: 100%; min-height: 500px"
|
||||
:center="center"
|
||||
:zoom="8"
|
||||
:airspaces-data="airspaceData"
|
||||
:airports="airports"
|
||||
v-bind="$attrs"
|
||||
@map-click="handleMapClick"
|
||||
>
|
||||
<AirspaceInfoWindow
|
||||
@@ -89,7 +98,7 @@ const handleMarkerMove = async (idx, event) => {
|
||||
@add-to-route="addMarker"
|
||||
/>
|
||||
|
||||
<template v-for="poi in pointsOfInterest" :key="poi">
|
||||
<template v-for="poi in pointsOfInterest" :key="poi.name">
|
||||
<CustomMarker
|
||||
v-if="poi.gpsLatitude && poi.gpsLongitude"
|
||||
:options="{position: {lat: poi.gpsLatitude, lng: poi.gpsLongitude}, anchorPoint: 'BOTTOM_CENTER'}"
|
||||
@@ -100,20 +109,13 @@ const handleMarkerMove = async (idx, event) => {
|
||||
</template>
|
||||
|
||||
|
||||
<template v-for="(marker, i) in markers" :key="marker">
|
||||
<template v-for="(marker, i) in markers" :key="marker.name">
|
||||
<Marker
|
||||
v-if="editableNameTypes.includes(marker.type)"
|
||||
:options="googleMapsMarkerObject(marker)"
|
||||
@click="handleMarkerClick(marker)"
|
||||
@dragend="handleMarkerMove(i, $event.latLng)"
|
||||
/>
|
||||
<!-- <CustomMarker-->
|
||||
<!-- v-else-if="['poi', 'airport']marker.type !== 'poi'"-->
|
||||
<!-- :options="googleMapsCustomMarkerObject(marker)"-->
|
||||
<!-- @click="handleMarkerClick(marker)"-->
|
||||
<!-- >-->
|
||||
<!-- <q-icon :name="getIcon(marker.type)" style="font-size: 30px;color: #810000"/>-->
|
||||
<!-- </CustomMarker>-->
|
||||
</template>
|
||||
<Polyline :options="{path: track, geodesic: true, strokeColor: '#ff0202', strokeOpacity: 0.5, strokeWeight: 5}"/>
|
||||
</MapWrapper>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import {computed} from "vue";
|
||||
import {computed, ref} from "vue";
|
||||
import {minutesToHumanReadable} from "src/composables/datetimeUtils";
|
||||
import {useFlightPlanUtils} from "src/composables/flightPlan";
|
||||
|
||||
@@ -12,12 +12,15 @@ const props = defineProps({
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 150
|
||||
},
|
||||
insertPosition: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["open"])
|
||||
const emits = defineEmits(["open", "change-insert-position"])
|
||||
|
||||
const {getIcon} = useFlightPlanUtils();
|
||||
|
||||
const getDuration = (distance, speed) => Math.round(distance / speed * 60)
|
||||
|
||||
@@ -31,30 +34,73 @@ const totalTime = computed(() => {
|
||||
|
||||
return props.flightPlan.track.map(t => getDuration(t.distance, props.plannedSpeed)).reduce((a, b) => a + b)
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-list bordered class="q-ml-md-md q-pt-md">
|
||||
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<div>
|
||||
<q-btn
|
||||
@click="emits('change-insert-position', 0)"
|
||||
icon="add"
|
||||
:color="insertPosition === 0 ? 'primary' : 'grey'"
|
||||
size="sm"
|
||||
>
|
||||
<template v-if="insertPosition === 0">Přidávám na začátek</template>
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<template v-for="(segment, i) in props.flightPlan.track" :key="segment">
|
||||
<q-item dense>
|
||||
<q-item-section>
|
||||
<q-item-label class="text-h6">
|
||||
<q-icon :name="getIcon(segment.from.type)"/>
|
||||
{{ segment.from.name }}
|
||||
</q-item-label>
|
||||
<q-item-section class="q-py-lg text-grey-8" v-if="segment.distance">
|
||||
<q-item-label>{{ segment.from.name }}</q-item-label>
|
||||
<q-item-label caption class="q-py-sm" v-if="segment.distance">
|
||||
{{ segment.bearing }}°,
|
||||
{{ segment.distance }} km,
|
||||
{{ minutesToHumanReadable(getDuration(segment.distance, props.plannedSpeed)) }}
|
||||
</q-item-section>
|
||||
<q-item-label class="text-h6" v-if="segment.to && i === props.flightPlan.track.length - 1">
|
||||
<q-icon :name="getIcon(segment.to.type)"/>
|
||||
</q-item-label>
|
||||
<q-item-label>
|
||||
<q-btn
|
||||
@click="emits('change-insert-position', i+1)"
|
||||
icon="add"
|
||||
size="sm"
|
||||
class="q-ml-lg q-mb-sm"
|
||||
:round="insertPosition !== i+1"
|
||||
:color="insertPosition === i+1 ? 'primary' : 'grey'"
|
||||
>
|
||||
<template v-if="insertPosition === i+1">Přidávám sem</template>
|
||||
</q-btn>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item dense v-if="segment.to && i === props.flightPlan.track.length - 1">
|
||||
<q-item-section>
|
||||
<q-item-label>
|
||||
{{ segment.to.name }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<div>
|
||||
<q-btn
|
||||
@click="emits('change-insert-position', flightPlan.track.length + 1)"
|
||||
icon="add"
|
||||
size="sm"
|
||||
:color="insertPosition === flightPlan.track.length + 1? 'primary' : 'grey'"
|
||||
>
|
||||
<template v-if="insertPosition === flightPlan.track.length + 1">Přidávám na konec</template>
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<template v-if="totalDistance">
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
|
||||
@@ -17,14 +17,19 @@ const props = defineProps({
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => []
|
||||
},
|
||||
showLayerControls: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["map-click"]);
|
||||
|
||||
|
||||
const key = process.env.GOOGLE_MAPS_API_KEY;
|
||||
|
||||
const zoomLevel = ref(null);
|
||||
const mapRef = ref(null);
|
||||
watch(
|
||||
() => mapRef.value?.ready,
|
||||
@@ -38,6 +43,12 @@ watch(
|
||||
}
|
||||
mapRef.value.map.fitBounds(bounds);
|
||||
}
|
||||
zoomLevel.value = mapRef.value.map.getZoom();
|
||||
|
||||
mapRef.value.map.addListener("zoom_changed", () => {
|
||||
console.log("zoom changed");
|
||||
zoomLevel.value = mapRef.value.map.getZoom();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
@@ -45,14 +56,14 @@ watch(
|
||||
const displayAirspaceLayers = ref({
|
||||
CTR: true,
|
||||
TMA: true,
|
||||
RMZ: true,
|
||||
RMZ: false,
|
||||
ATZ: true,
|
||||
DANGER: true,
|
||||
DANGER: false,
|
||||
PROHIBIT: true,
|
||||
RESTRICT: true,
|
||||
TRA: true,
|
||||
TRAGA: true,
|
||||
AIRPORTS: true
|
||||
AIRPORTS: true,
|
||||
FIELDSTRIP: false,
|
||||
});
|
||||
|
||||
const airspaces = computed(() => {
|
||||
@@ -66,7 +77,8 @@ const airspaces = computed(() => {
|
||||
Q: "#FFA500",
|
||||
PGZ: "#008000",
|
||||
GSEC: "#008000",
|
||||
ATZ: "#4e7cfc"
|
||||
ATZ: "#4e7cfc",
|
||||
FIR: '#ffffff'
|
||||
}
|
||||
|
||||
return props.airspacesData
|
||||
@@ -79,6 +91,7 @@ const airspaces = computed(() => {
|
||||
if (airspace.type === 'Q') return displayAirspaceLayers.value.DANGER;
|
||||
if (airspace.type === 'P') return displayAirspaceLayers.value.PROHIBIT;
|
||||
if (airspace.type === 'R') return displayAirspaceLayers.value.RESTRICT;
|
||||
if (airspace.type === 'ATZ') return displayAirspaceLayers.value.ATZ;
|
||||
return true;
|
||||
})
|
||||
.map(airspace => {
|
||||
@@ -103,9 +116,9 @@ const airspaces = computed(() => {
|
||||
});
|
||||
|
||||
const airportsOnMap = computed(() => {
|
||||
if (!displayAirspaceLayers.value.AIRPORTS) return [];
|
||||
if (!displayAirspaceLayers.value.AIRPORTS && !displayAirspaceLayers.value.FIELDSTRIP) return [];
|
||||
|
||||
return props.airports.filter(a => a.gpsLatitude && a.gpsLongitude);
|
||||
return props.airports.filter(a => a.gpsLatitude && a.gpsLongitude).filter(a => a.icaoCode.length === 6 ? displayAirspaceLayers.value.FIELDSTRIP : displayAirspaceLayers.value.AIRPORTS);
|
||||
});
|
||||
|
||||
const {isPointInPolygon, vectorDistanceToKm} = useVectorUtilities();
|
||||
@@ -137,8 +150,6 @@ const handleAirportClick = (airport) => {
|
||||
const position = {lat: airport.gpsLatitude, lng: airport.gpsLongitude};
|
||||
emits("map-click", {clickCoordinates: position, airport})
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -147,27 +158,13 @@ const handleAirportClick = (airport) => {
|
||||
v-bind="$attrs"
|
||||
:street-view-control="false"
|
||||
@click="handleMapClick"
|
||||
map-type-id="terrain"
|
||||
map-type-id="roadmap"
|
||||
: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">
|
||||
<template v-for="airspace in airspaces" :key="airspace.name">
|
||||
<Polygon :options="airspace" @click=handleMapClick v-if="airspace.path"/>
|
||||
<Circle :options="airspace" @click=handleMapClick v-if="airspace.center && airspace.radius"/>
|
||||
<Circle :options="airspace" @click=handleMapClick v-if="airspace.center && airspace.radius"/>
|
||||
</template>
|
||||
|
||||
<template v-for="airport in airportsOnMap" :key="airport.icaoCode">
|
||||
@@ -175,15 +172,26 @@ const handleAirportClick = (airport) => {
|
||||
: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>
|
||||
<q-chip size="xs">{{ airport.icaoCode }}</q-chip>
|
||||
</CustomMarker>
|
||||
</template>
|
||||
|
||||
<slot/>
|
||||
|
||||
<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-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="TRA"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.TRAGA" label="TRAGA"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.AIRPORTS" label="Letiště"/>
|
||||
<q-checkbox v-model="displayAirspaceLayers.FIELDSTRIP" label="SLZ plochy"/>
|
||||
</q-card>
|
||||
</CustomControl>
|
||||
|
||||
</GoogleMap>
|
||||
</template>
|
||||
|
||||
@@ -29,6 +29,7 @@ import PublishButton from "components/inputs/PublishButton.vue";
|
||||
import CopyLinkButton from "components/inputs/CopyLinkButton.vue";
|
||||
import {TOGGLE_FLIGHT_PUBLISH} from "src/graphql/mutations/flight";
|
||||
import {useAirspacesStore} from "stores/Airspaces";
|
||||
import {useAirportsStore} from "stores/Airports";
|
||||
|
||||
const flightId = parseInt(useRoute().params.id);
|
||||
const loggedUser = storeToRefs(useLoggedUserStore()).user;
|
||||
@@ -53,9 +54,11 @@ const handleDeleteAndRedirect = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const {airspaces: airspacesData} = storeToRefs(useAirspacesStore());
|
||||
const {airspaces} = storeToRefs(useAirspacesStore());
|
||||
const {airports} = storeToRefs(useAirportsStore());
|
||||
onMounted(() => {
|
||||
useAirspacesStore().fetch();
|
||||
useAirportsStore().fetch();
|
||||
});
|
||||
|
||||
const togglePublicVisibility = (variables) => toggleVisibility({
|
||||
@@ -147,7 +150,8 @@ const togglePublicVisibility = (variables) => toggleVisibility({
|
||||
|
||||
<q-no-ssr v-else>
|
||||
<FlightTrackMap
|
||||
:airspaces-data="airspacesData"
|
||||
:airspaces-data="airspaces"
|
||||
:airports="airports"
|
||||
:flight="flight"
|
||||
:photos="flight.photos"
|
||||
/>
|
||||
|
||||
@@ -77,7 +77,7 @@ const handleMarkersChanges = (markers) => {
|
||||
};
|
||||
|
||||
const handleFlightPlanInfoSave = () => useFlightPlansStore().update(flightPlan.value.id, formData.value);
|
||||
|
||||
const insertAtPosition = ref(flightPlanMarkers.value.length);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -98,16 +98,20 @@ const handleFlightPlanInfoSave = () => useFlightPlansStore().update(flightPlan.v
|
||||
<div class="row">
|
||||
<div class="col" style="min-width: 1px">
|
||||
<FlightPlanMap
|
||||
:insert-position="insertAtPosition"
|
||||
:airspace-data="airspacesData"
|
||||
:airports="airports"
|
||||
:points-of-interest="pointsOfInterest"
|
||||
:flight-plan="flightPlan"
|
||||
@change-insert-position="insertAtPosition = $event"
|
||||
@markers-changed="handleMarkersChanges"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-5 col-lg-3">
|
||||
<FlightPlanMarkersList
|
||||
:insert-position="insertAtPosition"
|
||||
:flight-plan="flightPlan"
|
||||
@change-insert-position="insertAtPosition = $event"
|
||||
@open="flightPlannerDialogOpen=true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -77,7 +77,11 @@ useMeta(() => metaData({
|
||||
<q-no-ssr>
|
||||
<q-inner-loading v-if="arePhotosLoading"/>
|
||||
<PhotoGallery :photos="flightPhotos" v-else-if="!arePhotosLoading && flightPhotos.length > 0"/>
|
||||
<FlightTrackMap :key="flight.id" :flight="flight" :photos="flightPhotos"/>
|
||||
<FlightTrackMap
|
||||
:key="flight.id"
|
||||
:flight="flight"
|
||||
:showLayerControls="false"
|
||||
:photos="flightPhotos"/>
|
||||
</q-no-ssr>
|
||||
</q-card-section>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user