Add elevation gain / loss to distance travelled stats

Closes #51.
This commit is contained in:
Linus Groh
2021-02-18 22:05:46 +01:00
parent 5c6370090f
commit 2fcf2151fa
12 changed files with 72 additions and 20 deletions
+2
View File
@@ -499,6 +499,8 @@ header bar. `maxPointDistance` is being takein into account, if a distance betwe
subsequent points is greater than `maxPointDistance`, it will not contibute to the
calculated travelled distance.
This also includes a calculation of elevation gain / loss.
- Type: [`Boolean`]
- Default: `true`
+24 -4
View File
@@ -118,10 +118,19 @@
<nav class="header-item header-item-right">
<div
v-if="$config.showDistanceTravelled && distanceTravelled"
class="nav-item"
:title="$t('Distance travelled')"
class="nav-item distance-travelled"
>
{{ humanReadableDistance(distanceTravelled) }}
<span :title="$t('Distance travelled')">
{{ humanReadableDistance(distanceTravelled) }}
</span>
<br />
<span :title="$t('Elevation gain / loss')">
<ArrowUpIcon size="0.8x" role="img" />
{{ humanReadableDistance(elevationGain) }}
/
<ArrowDownIcon size="0.8x" role="img" />
{{ humanReadableDistance(elevationLoss) }}
</span>
</div>
<div class="nav-item">
<button
@@ -153,6 +162,8 @@
import moment from "moment";
import { mapActions, mapGetters, mapMutations, mapState } from "vuex";
import {
ArrowDownIcon,
ArrowUpIcon,
CalendarIcon,
CrosshairIcon,
DownloadIcon,
@@ -172,6 +183,8 @@ import { humanReadableDistance } from "@/util";
export default {
components: {
ArrowDownIcon,
ArrowUpIcon,
CalendarIcon,
CrosshairIcon,
DownloadIcon,
@@ -196,7 +209,14 @@ export default {
};
},
computed: {
...mapState(["users", "devices", "map", "distanceTravelled"]),
...mapState([
"users",
"devices",
"map",
"distanceTravelled",
"elevationGain",
"elevationLoss",
]),
selectedUser: {
get() {
return this.$store.state.selectedUser;
+1
View File
@@ -11,6 +11,7 @@
"Show all": "Alle anzeigen",
"Select device": "Gerät auswählen",
"Distance travelled": "Gereiste Entfernung",
"Elevation gain / loss": "Höhengewinn / -verlust",
"Download raw data": "Rohdaten herunterladen",
"Information": "Information",
"Show last known locations": "Zeige letzte bekannte Standorte",
+1
View File
@@ -11,6 +11,7 @@
"Show all": "Show all",
"Select device": "Select device",
"Distance travelled": "Distance travelled",
"Elevation gain / loss": "Elevation gain / loss",
"Download raw data": "Download raw data",
"Information": "Information",
"Show last known locations": "Show last known locations",
+1
View File
@@ -11,6 +11,7 @@
"Show all": "Show all",
"Select device": "Select device",
"Distance travelled": "Distance traveled",
"Elevation gain / loss": "Elevation gain / loss",
"Download raw data": "Download raw data",
"Information": "Information",
"Show last known locations": "Show last known locations",
+1
View File
@@ -11,6 +11,7 @@
"Show all": "Mostrar todos",
"Select device": "Seleccionar dispositivo",
"Distance travelled": "Distancia recorrida",
"Elevation gain / loss": "",
"Download raw data": "Descargar datos en crudo",
"Information": "Información",
"Show last known locations": "Mostrar última ubicación conocida",
+1
View File
@@ -11,6 +11,7 @@
"Show all": "Tout afficher",
"Select device": "Sélectionner un appareil",
"Distance travelled": "Distance parcourue",
"Elevation gain / loss": "",
"Download raw data": "Télécharger les données brutes",
"Information": "Informations",
"Show last known locations": "Afficher les dernières localisations connues",
+20 -15
View File
@@ -122,9 +122,11 @@ const getLastLocations = async ({ commit, state }) => {
commit(types.SET_LAST_LOCATIONS, lastLocations);
};
const _getDistanceTravelled = (locationHistory) => {
const _getTravelStats = (locationHistory) => {
const start = Date.now();
let distanceTravelled = 0;
let elevationGain = 0;
let elevationLoss = 0;
Object.keys(locationHistory).forEach((user) => {
Object.keys(locationHistory[user]).forEach((device) => {
let lastLatLng = null;
@@ -134,20 +136,21 @@ const _getDistanceTravelled = (locationHistory) => {
location.acc > config.filters.minAccuracy
)
return;
const latLng = L.latLng(location.lat, location.lon);
const latLng = L.latLng(location.lat, location.lon, location.alt ?? 0);
if (lastLatLng !== null) {
const distance = distanceBetweenCoordinates(lastLatLng, latLng);
const elevationChange = latLng.alt - lastLatLng.alt;
if (
typeof config.map.maxPointDistance === "number" &&
config.map.maxPointDistance > 0
? // If part of the current group, add to total
distance <= config.map.maxPointDistance
: // If grouping is disabled, always add to total
true
) {
if (distance <= config.map.maxPointDistance) {
// Part of the current group, add calculated distance to total
distanceTravelled += distance;
}
} else {
// If grouping is disabled always add calculated distance to total
distanceTravelled += distance;
if (elevationChange >= 0) elevationGain += elevationChange;
else elevationLoss += -elevationChange;
}
}
lastLatLng = latLng;
@@ -155,15 +158,15 @@ const _getDistanceTravelled = (locationHistory) => {
});
});
const end = Date.now();
log("DISTANCE", () => {
log("PERFORMANCE", () => {
const locationHistoryCount = getLocationHistoryCount(locationHistory);
const duration = (end - start) / 1000;
return (
`[_getDistanceTravelled] Took ${duration} seconds to ` +
`calculate distance of ${locationHistoryCount} locations`
`[_getTravelStats] Took ${duration} seconds to calculate distance ` +
`and elevation gain/loss of ${locationHistoryCount} locations`
);
});
return distanceTravelled;
return { distanceTravelled, elevationGain, elevationLoss };
};
/**
@@ -189,10 +192,12 @@ const getLocationHistory = async ({ commit, state }) => {
commit(types.SET_IS_LOADING, false);
commit(types.SET_LOCATION_HISTORY, locationHistory);
if (config.showDistanceTravelled) {
commit(
types.SET_DISTANCE_TRAVELLED,
_getDistanceTravelled(locationHistory)
const { distanceTravelled, elevationGain, elevationLoss } = _getTravelStats(
locationHistory
);
commit(types.SET_DISTANCE_TRAVELLED, distanceTravelled);
commit(types.SET_ELEVATION_GAIN, elevationGain);
commit(types.SET_ELEVATION_LOSS, elevationLoss);
}
};
+3 -1
View File
@@ -30,7 +30,9 @@ export default new Vuex.Store({
zoom: 19,
layers: config.map.layers,
},
distanceTravelled: null,
distanceTravelled: 0,
elevationGain: 0,
elevationLoss: 0,
},
getters,
mutations,
+2
View File
@@ -12,3 +12,5 @@ export const SET_MAP_CENTER = "SET_MAP_CENTER";
export const SET_MAP_ZOOM = "SET_MAP_ZOOM";
export const SET_MAP_LAYER_VISIBILITY = "SET_MAP_LAYER_VISIBILITY";
export const SET_DISTANCE_TRAVELLED = "SET_DISTANCE_TRAVELLED";
export const SET_ELEVATION_GAIN = "SET_ELEVATION_GAIN";
export const SET_ELEVATION_LOSS = "SET_ELEVATION_LOSS";
+6
View File
@@ -43,4 +43,10 @@ export default {
[types.SET_DISTANCE_TRAVELLED](state, distanceTravelled) {
state.distanceTravelled = distanceTravelled;
},
[types.SET_ELEVATION_GAIN](state, elevationGain) {
state.elevationGain = elevationGain;
},
[types.SET_ELEVATION_LOSS](state, elevationLoss) {
state.elevationLoss = elevationLoss;
},
};
+10
View File
@@ -151,6 +151,16 @@ pre {
.button-icon .feather {
margin: 0;
}
&.distance-travelled {
text-align: right;
line-height: 1.2;
.feather {
margin-top: 3px;
margin-right: 0;
}
}
}
&.nav-sm {