Lepsi podpora elevace terenu
This commit is contained in:
@@ -16,11 +16,13 @@
|
|||||||
"@vue/apollo-option": "^4.0.0-beta.5",
|
"@vue/apollo-option": "^4.0.0-beta.5",
|
||||||
"apollo-upload-client": "^17.0.0",
|
"apollo-upload-client": "^17.0.0",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
|
"chart.js": "^4.4.0",
|
||||||
"graphql": "16.6.0",
|
"graphql": "16.6.0",
|
||||||
"graphql-tag": "2.12.6",
|
"graphql-tag": "2.12.6",
|
||||||
"pinia": "^2.0.33",
|
"pinia": "^2.0.33",
|
||||||
"quasar": "^2.12.0",
|
"quasar": "^2.12.0",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47",
|
||||||
|
"vue-chartjs": "^5.2.0",
|
||||||
"vue-inner-image-zoom": "^2.0.0",
|
"vue-inner-image-zoom": "^2.0.0",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.1.6",
|
||||||
"vue3-google-map": "^0.15.0"
|
"vue3-google-map": "^0.15.0"
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
@@ -31,6 +31,7 @@ module.exports = configure(function (ctx) {
|
|||||||
boot: [
|
boot: [
|
||||||
"axios",
|
"axios",
|
||||||
"vueInnerImageZoom",
|
"vueInnerImageZoom",
|
||||||
|
"chartJs",
|
||||||
],
|
],
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import {boot} from "quasar/wrappers";
|
||||||
|
import {BarElement, CategoryScale, Chart as ChartJS, Filler, Legend, LinearScale, LineElement, PointElement, Title, Tooltip} from "chart.js";
|
||||||
|
|
||||||
|
export default boot(({app}) => {
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, PointElement, LineElement, Filler, BarElement, CategoryScale, LinearScale)
|
||||||
|
})
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
import {flight} from "src/composables/objects/flight";
|
import {flight} from "src/composables/objects/flight";
|
||||||
import MapWithMarkers from "components/map/MapWithMarkers.vue";
|
import MapWithMarkers from "components/map/MapWithMarkers.vue";
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
|
import {Line} from "vue-chartjs"
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
flight: {
|
flight: {
|
||||||
@@ -11,24 +12,22 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const trackWithGPS = computed(() => {
|
const mapPhotos = computed(() => flight.value.photos.filter(photo => photo.gpsLatitude && photo.gpsLongitude));
|
||||||
|
const poisWithGPS = computed(() => {
|
||||||
return flight.value.track.filter(poi => poi.pointOfInterest.gpsLatitude && poi.pointOfInterest.gpsLongitude)
|
return flight.value.track.filter(poi => poi.pointOfInterest.gpsLatitude && poi.pointOfInterest.gpsLongitude)
|
||||||
});
|
});
|
||||||
|
|
||||||
const slider = ref(0);
|
|
||||||
|
|
||||||
|
|
||||||
const pointsOfInterests = computed(() => {
|
const pointsOfInterests = computed(() => {
|
||||||
const path = [{
|
const path = [{
|
||||||
label: flight.value.takeoffAirport.name,
|
label: flight.value.takeoffAirport.name,
|
||||||
position:
|
position:
|
||||||
{
|
{
|
||||||
lat: flight.value.takeoffAirport.gpsLatitude + (slider.value / 1000),
|
lat: flight.value.takeoffAirport.gpsLatitude,
|
||||||
lng: flight.value.takeoffAirport.gpsLongitude + (slider.value / 1000)
|
lng: flight.value.takeoffAirport.gpsLongitude
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
for (const poi of trackWithGPS.value) {
|
for (const poi of poisWithGPS.value) {
|
||||||
path.push({
|
path.push({
|
||||||
label: poi.pointOfInterest.name,
|
label: poi.pointOfInterest.name,
|
||||||
position: {lat: poi.pointOfInterest.gpsLatitude, lng: poi.pointOfInterest.gpsLongitude}
|
position: {lat: poi.pointOfInterest.gpsLatitude, lng: poi.pointOfInterest.gpsLongitude}
|
||||||
@@ -47,33 +46,93 @@ const pointsOfInterests = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const mapPhotos = computed(() => {
|
const gpxTrack = flight.value.gpxTrack;
|
||||||
return flight.value.photos.filter(photo => photo.gpsLatitude && photo.gpsLongitude)
|
|
||||||
});
|
|
||||||
|
|
||||||
const displayMap = computed(() => {
|
const displayMap = computed(() => {
|
||||||
return (
|
return (
|
||||||
!!flight.value.gpxTrackUrl ||
|
!!gpxTrack ||
|
||||||
mapPhotos.value.length > 0 ||
|
mapPhotos.value.length > 0 ||
|
||||||
trackWithGPS.value.length > 0 ||
|
poisWithGPS.value.length > 0 ||
|
||||||
flight.value.landingAirport.id !== flight.value.takeoffAirport.id
|
flight.value.landingAirport.id !== flight.value.takeoffAirport.id
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let chartSpeedData, chartAltitudeData = null;
|
||||||
|
if (gpxTrack) {
|
||||||
|
const chartLabels = gpxTrack.time.map(t => {
|
||||||
|
const datetime = new Date(t);
|
||||||
|
return datetime.getHours() + ":" + datetime.getMinutes();
|
||||||
|
});
|
||||||
|
chartSpeedData = {
|
||||||
|
labels: chartLabels,
|
||||||
|
datasets: [{
|
||||||
|
backgroundColor: "#38bd3e",
|
||||||
|
borderColor: "#38bd3e",
|
||||||
|
label: "Rychlost (km/h)",
|
||||||
|
data: gpxTrack.speed,
|
||||||
|
pointRadius: 1,
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
chartAltitudeData = {
|
||||||
|
labels: chartLabels,
|
||||||
|
datasets: [{
|
||||||
|
backgroundColor: "#9ae3ff",
|
||||||
|
borderColor: "#9ae3ff",
|
||||||
|
label: "Nadmořská výška letu (m)",
|
||||||
|
data: gpxTrack.altitude,
|
||||||
|
pointRadius: 1,
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (gpxTrack.terrainElevation.length > 0) {
|
||||||
|
chartAltitudeData.datasets.push(
|
||||||
|
{
|
||||||
|
backgroundColor: "rgba(148,94,40,0.7)",
|
||||||
|
borderColor: "#945e28",
|
||||||
|
label: "Nadmořská výška země (m)",
|
||||||
|
data: gpxTrack.terrainElevation,
|
||||||
|
fill: true,
|
||||||
|
pointRadius: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const currentPositionMarker = ref(null);
|
||||||
|
const drawCurrentPositionMarker = (e) => {
|
||||||
|
const res = e.chart.getElementsAtEventForMode(e, 'nearest', {intersect: false},);
|
||||||
|
if (res.length === 0) {
|
||||||
|
currentPositionMarker.value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const idx = res[0].index;
|
||||||
|
currentPositionMarker.value = flight.value.gpxTrack.coordinates[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartOptions = {
|
||||||
|
plugins: {
|
||||||
|
tooltip: {
|
||||||
|
mode: 'index',
|
||||||
|
intersect: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onClick: drawCurrentPositionMarker,
|
||||||
|
onHover: drawCurrentPositionMarker,
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MapWithMarkers
|
<MapWithMarkers
|
||||||
v-if="displayMap"
|
v-if="displayMap"
|
||||||
style="width: 100%; height: 500px;"
|
style="width: 100%; height: 500px;"
|
||||||
:gpx-track-url="flight.gpxTrackUrl"
|
:gpx-track="flight.gpxTrack?.coordinates || []"
|
||||||
:markers="pointsOfInterests"
|
:markers="pointsOfInterests"
|
||||||
|
:highlight-position="currentPositionMarker"
|
||||||
:photos="mapPhotos"
|
:photos="mapPhotos"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{{ pointsOfInterests }}
|
<Line v-if="gpxTrack" :data="chartSpeedData" :options="chartOptions"/>
|
||||||
|
<Line v-if="gpxTrack" :data="chartAltitudeData" :options="chartOptions"/>
|
||||||
|
|
||||||
{{ slider }}
|
|
||||||
|
|
||||||
<q-slider v-model.number="slider" :min="-100" :max="100" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import {axios} from "boot/axios";
|
|||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
gpxTrackUrl: {
|
gpxTrack: {
|
||||||
type: String,
|
type: Object,
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
markers: {
|
markers: {
|
||||||
@@ -15,6 +15,10 @@ const props = defineProps({
|
|||||||
required: false,
|
required: false,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
|
highlightPosition: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
photos: {
|
photos: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -23,35 +27,8 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const track = ref([]);
|
const track = ref([]);
|
||||||
const gpxLoading = ref(!!props.gpxTrackUrl);
|
|
||||||
const speed = ref([]);
|
const speed = ref([]);
|
||||||
const elevation = ref([]);
|
const elevation = ref([]);
|
||||||
onMounted(() => {
|
|
||||||
if (!props.gpxTrackUrl) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gpxLoading.value = true;
|
|
||||||
axios.get(props.gpxTrackUrl)
|
|
||||||
.then(({data}) => (new window.DOMParser()).parseFromString(data, "text/xml"))
|
|
||||||
.then(doc => {
|
|
||||||
const points = [];
|
|
||||||
const nodes = [...doc.getElementsByTagName('trkpt')];
|
|
||||||
nodes.forEach(node => {
|
|
||||||
const lat = parseFloat(node.getAttribute("lat"));
|
|
||||||
const lng = parseFloat(node.getAttribute("lon"));
|
|
||||||
|
|
||||||
console.log(node.childNodes);
|
|
||||||
|
|
||||||
points.push({lat, lng});
|
|
||||||
// speed.value.push(node.getElementsByTagName("extensions").getElementsByTagName("speed"));
|
|
||||||
// elevation.value.push(node.getElementsByTagName("ele").innerText);
|
|
||||||
})
|
|
||||||
|
|
||||||
track.value = points; // puvodne se bounds bralo z tohodle
|
|
||||||
})
|
|
||||||
.finally(() => gpxLoading.value = false);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const bounds = computed(() => {
|
const bounds = computed(() => {
|
||||||
const photosTransformed = props.photos.map(p => ({position: {lat: p.gpsLatitude, lng: p.gpsLongitude}}));
|
const photosTransformed = props.photos.map(p => ({position: {lat: p.gpsLatitude, lng: p.gpsLongitude}}));
|
||||||
@@ -61,22 +38,19 @@ const bounds = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-spinner v-if="gpxLoading" v-bind="$attrs" />
|
<MapWrapper v-bind="$attrs" :bounds="bounds">
|
||||||
|
|
||||||
speed: {{ speed }}
|
|
||||||
elevation: {{ elevation }}
|
|
||||||
|
|
||||||
<MapWrapper v-bind="$attrs" :bounds="bounds" v-if="!gpxLoading">
|
|
||||||
<Marker v-for="(marker, idx) in markers" :key="idx" :options="marker"/>
|
<Marker v-for="(marker, idx) in markers" :key="idx" :options="marker"/>
|
||||||
|
|
||||||
<Marker v-for="(photo, idx) in photos" :key="idx" :options="{icon: '/mapIcons/photo-16x16.png', position: {lat: photo.gpsLatitude, lng: photo.gpsLongitude}}">
|
<Marker v-for="(photo, idx) in photos" :key="idx" :options="{icon: '/mapIcons/photo-16x16.png', position: {lat: photo.gpsLatitude, lng: photo.gpsLongitude}}">
|
||||||
<InfoWindow :options="{position: {lat: photo.gpsLatitude, lng: photo.gpsLongitude}}">
|
<InfoWindow :options="{position: {lat: photo.gpsLatitude, lng: photo.gpsLongitude}}">
|
||||||
<img :src="photo.thumbnailUrl" />
|
<img :src="photo.thumbnailUrl"/>
|
||||||
</InfoWindow>
|
</InfoWindow>
|
||||||
</Marker>
|
</Marker>
|
||||||
|
|
||||||
<template v-if="track.length > 0">
|
<template v-if="gpxTrack && gpxTrack.length > 0">
|
||||||
<Polyline :options="{path: track, geodesic: true, strokeColor: '#ff0000', strokeOpacity: 0.3, strokeWeight: 5}"/>
|
<Polyline :options="{path: gpxTrack, geodesic: true, strokeColor: '#ff0000', strokeOpacity: 0.3, strokeWeight: 5}"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<Marker v-if="highlightPosition" :options="{position: highlightPosition, icon: '/mapIcons/currentPosition32x32.png'}"/>
|
||||||
|
|
||||||
</MapWrapper>
|
</MapWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import EmbeddedMap from "components/map/EmbeddedMap.vue";
|
import EmbeddedMap from "components/map/EmbeddedMap.vue";
|
||||||
import {computed, onMounted, ref, watch} from "vue";
|
import {computed, onMounted, ref} from "vue";
|
||||||
import {formatDatetime} from "src/composables/datetimeUtils";
|
import {formatDatetime} from "src/composables/datetimeUtils";
|
||||||
import 'vue-inner-image-zoom/lib/vue-inner-image-zoom.css'
|
import 'vue-inner-image-zoom/lib/vue-inner-image-zoom.css'
|
||||||
import {useQuasar} from "quasar";
|
import {useQuasar} from "quasar";
|
||||||
@@ -28,8 +28,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(["update:modelValue"])
|
const emit = defineEmits(["update:modelValue"])
|
||||||
|
|
||||||
|
const isDetailOpened = computed({
|
||||||
const open = computed({
|
|
||||||
get() {
|
get() {
|
||||||
return props.modelValue;
|
return props.modelValue;
|
||||||
},
|
},
|
||||||
@@ -61,16 +60,6 @@ const showDetail = (idx) => {
|
|||||||
photoIndex.value = idx;
|
photoIndex.value = idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
const thumbnailsRef = ref(null);
|
|
||||||
watch(photoIndex, (newVal) => {
|
|
||||||
if (!thumbnailsRef.value) return;
|
|
||||||
const thumbnailWidth = 200;
|
|
||||||
const thumbnailBarWidth = thumbnailsRef.value.$el.clientWidth;
|
|
||||||
const thumbnailPosition = newVal * thumbnailWidth;
|
|
||||||
const scrollTo = Math.max(0, thumbnailPosition - thumbnailBarWidth/2);
|
|
||||||
thumbnailsRef.value.setScrollPosition("horizontal", scrollTo, 500)
|
|
||||||
});
|
|
||||||
|
|
||||||
const showExtra = ref(false);
|
const showExtra = ref(false);
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
@@ -80,94 +69,91 @@ const imageFullscreen = ref(false);
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-dialog
|
<q-dialog
|
||||||
v-model="open"
|
v-model="isDetailOpened"
|
||||||
full-width
|
full-width
|
||||||
:maximized="isMaximized"
|
:maximized="isMaximized"
|
||||||
>
|
>
|
||||||
<q-card
|
<q-card>
|
||||||
v-touch-swipe.mouse.left="prevPhoto"
|
|
||||||
v-touch-swipe.mouse.right="nextPhoto"
|
|
||||||
@keyup.left="prevPhoto"
|
|
||||||
@keyup.right="nextPhoto"
|
|
||||||
>
|
|
||||||
<q-card-section class="bg-black text-white" v-if="isMaximized">
|
<q-card-section class="bg-black text-white" v-if="isMaximized">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<strong>{{ photo.name || defaultTitle }}</strong>
|
<strong>{{ photo.name || defaultTitle }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="col text-right">
|
<div class="col-1 text-right">
|
||||||
<q-btn round text-color="white" size="sm" icon="close" @click="open = false"/>
|
<q-btn round text-color="white" size="sm" icon="close" @click="isDetailOpened = false"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<q-card-section :class="{'q-pa-none': isMaximized}">
|
<q-card-section :class="{'q-pa-none': isMaximized}">
|
||||||
<div :class="{'relative-position': true, 'image-full-height': imageFullscreen}">
|
<div :class="{'relative-position': true, 'image-full-height': imageFullscreen}">
|
||||||
<div class="text-center">
|
<div
|
||||||
|
class="text-center"
|
||||||
|
v-touch-swipe.mouse.right="prevPhoto"
|
||||||
|
v-touch-swipe.mouse.left="nextPhoto"
|
||||||
|
@keyup.left="prevPhoto"
|
||||||
|
@keyup.right="nextPhoto">
|
||||||
<inner-image-zoom
|
<inner-image-zoom
|
||||||
:move-type="isMaximized ? 'drag' : 'pan'"
|
:move-type="isMaximized ? 'drag' : 'pan'"
|
||||||
:zoomScale="0.75"
|
:zoomScale="0.75"
|
||||||
:hide-hint="true"
|
:hide-hint="true"
|
||||||
:after-zoom-in="() => imageFullscreen = true"
|
:after-zoom-in="() => imageFullscreen = true"
|
||||||
:after-zoom-out="() => imageFullscreen = false"
|
:after-zoom-out="() => imageFullscreen = false"
|
||||||
:src="photo.url"
|
:src="photo.url"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="!imageFullscreen">
|
<template v-if="!imageFullscreen">
|
||||||
<q-btn
|
<q-btn
|
||||||
class="absolute all-pointer-events"
|
class="absolute all-pointer-events"
|
||||||
round
|
round
|
||||||
flat
|
flat
|
||||||
icon="info"
|
icon="info"
|
||||||
:text-color="showExtra ? 'primary' : 'white'"
|
:text-color="showExtra ? 'primary' : 'white'"
|
||||||
style="background: rgba(0, 0, 0, 0.25); bottom: 16px; left: 8px"
|
style="background: rgba(0, 0, 0, 0.25); bottom: 16px; left: 8px"
|
||||||
@click="showExtra = !showExtra"
|
@click="showExtra = !showExtra"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
class="absolute all-pointer-events"
|
class="absolute all-pointer-events"
|
||||||
style="background: rgba(0, 0, 0, 0.25); top: 50%; left: 8px;"
|
style="background: rgba(0, 0, 0, 0.25); top: 50%; left: 8px;"
|
||||||
@click="prevPhoto"
|
@click="prevPhoto"
|
||||||
v-if="photoIndex > 0 && !isMaximized"
|
v-if="photoIndex > 0 && !isMaximized"
|
||||||
icon="chevron_left"
|
icon="chevron_left"
|
||||||
text-color="white"
|
text-color="white"
|
||||||
flat
|
flat
|
||||||
rounded
|
rounded
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
class="absolute all-pointer-events"
|
class="absolute all-pointer-events"
|
||||||
style="background: rgba(0, 0, 0, 0.25); top: 50%; right: 8px;"
|
style="background: rgba(0, 0, 0, 0.25); top: 50%; right: 8px;"
|
||||||
@click="nextPhoto"
|
@click="nextPhoto"
|
||||||
v-if="photoIndex < photos.length - 1 && !isMaximized"
|
v-if="photoIndex < photos.length - 1 && !isMaximized"
|
||||||
icon-right="chevron_right"
|
icon-right="chevron_right"
|
||||||
text-color="white"
|
text-color="white"
|
||||||
flat
|
flat
|
||||||
rounded
|
rounded
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-scroll-area ref="thumbnailsRef" style="height: 170px; width: 100%;" v-show="!imageFullscreen">
|
<div class="row" v-show="!imageFullscreen">
|
||||||
<div class="row no-wrap flex-center">
|
<div class="col-4 col-md-1 q-pa-sm" v-for="(thumb, idx) in photos" :key="thumb.thumbnailUrl">
|
||||||
<q-img
|
<q-img
|
||||||
v-for="(thumb, idx) in photos"
|
:src="thumb.thumbnailUrl"
|
||||||
:key="thumb.thumbnailUrl"
|
@click="showDetail(idx)"
|
||||||
:src="thumb.thumbnailUrl"
|
:class='{"shadow-5": true, "active-thumbnail": idx === photoIndex}'
|
||||||
@click="showDetail(idx)"
|
|
||||||
:style="`width: 150px; ${idx === photoIndex ? 'outline: solid 2px' : ''}`"
|
|
||||||
class="q-ma-sm shadow-5"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</q-scroll-area>
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 q-my-md" v-if="showExtra">
|
<div class="col-12 q-my-md" v-if="showExtra">
|
||||||
<EmbeddedMap
|
<EmbeddedMap
|
||||||
v-if="photo.gpsLatitude && photo.gpsLongitude"
|
v-if="photo.gpsLatitude && photo.gpsLongitude"
|
||||||
class="q-mx-sm"
|
class="q-mx-sm"
|
||||||
:gps-latitude="photo.gpsLatitude"
|
:gps-latitude="photo.gpsLatitude"
|
||||||
:gps-longitude="photo.gpsLongitude"
|
:gps-longitude="photo.gpsLongitude"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<strong v-if="photo.name !== '' && !isMaximized">{{ photo.name }}</strong>
|
<strong v-if="photo.name !== '' && !isMaximized">{{ photo.name }}</strong>
|
||||||
@@ -179,7 +165,7 @@ const imageFullscreen = ref(false);
|
|||||||
<q-avatar icon="marker"></q-avatar>
|
<q-avatar icon="marker"></q-avatar>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
{{ formatDatetime(photo.exposedAt) }}
|
{{ photo.pointOfInterest.name }}
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item v-if="photo.exposedAt">
|
<q-item v-if="photo.exposedAt">
|
||||||
@@ -196,7 +182,13 @@ const imageFullscreen = ref(false);
|
|||||||
<q-avatar icon="height"/>
|
<q-avatar icon="height"/>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
{{ photo.gpsAltitude }} m
|
Nadmořská výška: {{ photo.gpsAltitude }} m
|
||||||
|
<br>
|
||||||
|
<template v-if="photo.terrainElevation">
|
||||||
|
Výška terénu: {{ photo.terrainElevation }} m
|
||||||
|
<br>
|
||||||
|
Výška nad zemí: {{ photo.gpsAltitude - photo.terrainElevation }} m
|
||||||
|
</template>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
@@ -208,6 +200,10 @@ const imageFullscreen = ref(false);
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.active-thumbnail {
|
||||||
|
outline: solid 2px
|
||||||
|
}
|
||||||
|
|
||||||
.iiz {
|
.iiz {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ const setup = (() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DialogWrapper :formData="formData" :object-id="photoId" @show="setup">
|
<DialogWrapper :formData="formData" :object-id="photoId" @show="setup">
|
||||||
{{ formData }}
|
|
||||||
<q-img :src="photo.thumbnailUrl"/>
|
<q-img :src="photo.thumbnailUrl"/>
|
||||||
|
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<FormWrapper :save-button="false">
|
<FormWrapper :save-button="false">
|
||||||
<q-input v-model="formData.name" label="Název" v-bind="commonProps"/>
|
<q-input v-model="formData.name" label="Název" v-bind="commonProps"/>
|
||||||
|
|||||||
@@ -41,8 +41,23 @@ fragment flightFullInfo on Flight {
|
|||||||
id
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
|
||||||
gpxTrackUrl
|
gpxTrackUrl
|
||||||
|
gpxTrack {
|
||||||
|
coordinates {
|
||||||
|
lat
|
||||||
|
lng
|
||||||
|
}
|
||||||
|
time
|
||||||
|
magneticVariation
|
||||||
|
speed
|
||||||
|
maxSpeed
|
||||||
|
avgSpeed
|
||||||
|
altitude
|
||||||
|
terrainElevation
|
||||||
|
maxAltitude
|
||||||
|
avgAltitude
|
||||||
|
}
|
||||||
|
|
||||||
track {
|
track {
|
||||||
pointOfInterest {
|
pointOfInterest {
|
||||||
...pointOfInterestFullInfo
|
...pointOfInterestFullInfo
|
||||||
|
|||||||
@@ -102,6 +102,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
|
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
|
||||||
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
|
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
|
||||||
|
|
||||||
|
"@kurkle/color@^0.3.0":
|
||||||
|
version "0.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@kurkle/color/-/color-0.3.2.tgz#5acd38242e8bde4f9986e7913c8fdf49d3aa199f"
|
||||||
|
integrity sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==
|
||||||
|
|
||||||
"@nodelib/fs.scandir@2.1.5":
|
"@nodelib/fs.scandir@2.1.5":
|
||||||
version "2.1.5"
|
version "2.1.5"
|
||||||
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
|
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
|
||||||
@@ -718,6 +723,13 @@ chardet@^0.7.0:
|
|||||||
resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
|
resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
|
||||||
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
||||||
|
|
||||||
|
chart.js@^4.4.0:
|
||||||
|
version "4.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.4.0.tgz#df843fdd9ec6bd88d7f07e2b95348d221bd2698c"
|
||||||
|
integrity sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==
|
||||||
|
dependencies:
|
||||||
|
"@kurkle/color" "^0.3.0"
|
||||||
|
|
||||||
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3:
|
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3:
|
||||||
version "3.5.3"
|
version "3.5.3"
|
||||||
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
|
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
|
||||||
@@ -2948,6 +2960,11 @@ vite@^2.9.13:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
vue-chartjs@^5.2.0:
|
||||||
|
version "5.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-chartjs/-/vue-chartjs-5.2.0.tgz#3d0076ccf8016d1bf8fab5ccd837e7fb81005ded"
|
||||||
|
integrity sha512-d3zpKmGZr2OWHQ1xmxBcAn5ShTG917+/UCLaSpaCDDqT0U7DBsvFzTs69ZnHCgKoXT55GZDW8YEj9Av+dlONLA==
|
||||||
|
|
||||||
vue-demi@*, vue-demi@^0.13.1:
|
vue-demi@*, vue-demi@^0.13.1:
|
||||||
version "0.13.11"
|
version "0.13.11"
|
||||||
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz"
|
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user