diff --git a/package.json b/package.json
index 40a6a25..6287851 100644
--- a/package.json
+++ b/package.json
@@ -16,11 +16,13 @@
"@vue/apollo-option": "^4.0.0-beta.5",
"apollo-upload-client": "^17.0.0",
"axios": "^1.4.0",
+ "chart.js": "^4.4.0",
"graphql": "16.6.0",
"graphql-tag": "2.12.6",
"pinia": "^2.0.33",
"quasar": "^2.12.0",
"vue": "^3.2.47",
+ "vue-chartjs": "^5.2.0",
"vue-inner-image-zoom": "^2.0.0",
"vue-router": "^4.1.6",
"vue3-google-map": "^0.15.0"
diff --git a/public/mapIcons/currentPosition.png b/public/mapIcons/currentPosition.png
new file mode 100644
index 0000000..1f29525
Binary files /dev/null and b/public/mapIcons/currentPosition.png differ
diff --git a/public/mapIcons/currentPosition32x32.png b/public/mapIcons/currentPosition32x32.png
new file mode 100644
index 0000000..2dac397
Binary files /dev/null and b/public/mapIcons/currentPosition32x32.png differ
diff --git a/quasar.config.js b/quasar.config.js
index b148bc9..ad05f7d 100644
--- a/quasar.config.js
+++ b/quasar.config.js
@@ -31,6 +31,7 @@ module.exports = configure(function (ctx) {
boot: [
"axios",
"vueInnerImageZoom",
+ "chartJs",
],
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
diff --git a/src/boot/chartJs.js b/src/boot/chartJs.js
new file mode 100644
index 0000000..41daa61
--- /dev/null
+++ b/src/boot/chartJs.js
@@ -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)
+})
diff --git a/src/components/flights/FlightTrackMap.vue b/src/components/flights/FlightTrackMap.vue
index c3c581c..d091aa3 100644
--- a/src/components/flights/FlightTrackMap.vue
+++ b/src/components/flights/FlightTrackMap.vue
@@ -2,6 +2,7 @@
import {flight} from "src/composables/objects/flight";
import MapWithMarkers from "components/map/MapWithMarkers.vue";
import {computed, ref} from "vue";
+import {Line} from "vue-chartjs"
const props = defineProps({
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)
});
-const slider = ref(0);
-
-
const pointsOfInterests = computed(() => {
const path = [{
label: flight.value.takeoffAirport.name,
position:
{
- lat: flight.value.takeoffAirport.gpsLatitude + (slider.value / 1000),
- lng: flight.value.takeoffAirport.gpsLongitude + (slider.value / 1000)
+ lat: flight.value.takeoffAirport.gpsLatitude,
+ lng: flight.value.takeoffAirport.gpsLongitude
}
}];
- for (const poi of trackWithGPS.value) {
+ for (const poi of poisWithGPS.value) {
path.push({
label: poi.pointOfInterest.name,
position: {lat: poi.pointOfInterest.gpsLatitude, lng: poi.pointOfInterest.gpsLongitude}
@@ -47,33 +46,93 @@ const pointsOfInterests = computed(() => {
});
-const mapPhotos = computed(() => {
- return flight.value.photos.filter(photo => photo.gpsLatitude && photo.gpsLongitude)
-});
+const gpxTrack = flight.value.gpxTrack;
const displayMap = computed(() => {
return (
- !!flight.value.gpxTrackUrl ||
+ !!gpxTrack ||
mapPhotos.value.length > 0 ||
- trackWithGPS.value.length > 0 ||
+ poisWithGPS.value.length > 0 ||
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,
+}
- {{ pointsOfInterests }}
+
+
- {{ slider }}
-
-
diff --git a/src/components/map/MapWithMarkers.vue b/src/components/map/MapWithMarkers.vue
index c9783ce..bd1a431 100644
--- a/src/components/map/MapWithMarkers.vue
+++ b/src/components/map/MapWithMarkers.vue
@@ -6,8 +6,8 @@ import {axios} from "boot/axios";
const props = defineProps({
- gpxTrackUrl: {
- type: String,
+ gpxTrack: {
+ type: Object,
required: false,
},
markers: {
@@ -15,6 +15,10 @@ const props = defineProps({
required: false,
default: () => []
},
+ highlightPosition: {
+ type: Object,
+ required: false,
+ },
photos: {
type: Array,
required: false,
@@ -23,35 +27,8 @@ const props = defineProps({
})
const track = ref([]);
-const gpxLoading = ref(!!props.gpxTrackUrl);
const speed = 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 photosTransformed = props.photos.map(p => ({position: {lat: p.gpsLatitude, lng: p.gpsLongitude}}));
@@ -61,22 +38,19 @@ const bounds = computed(() => {
-
-
- speed: {{ speed }}
- elevation: {{ elevation }}
-
-
+
-
-
+
-
-
+
+
+
+
+
diff --git a/src/components/photos/PhotoDetail.vue b/src/components/photos/PhotoDetail.vue
index 584ed7f..aa0b79c 100644
--- a/src/components/photos/PhotoDetail.vue
+++ b/src/components/photos/PhotoDetail.vue
@@ -1,6 +1,6 @@