From b76cbdc2e627f7957a304bca5b454c20729181d6 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Mon, 11 May 2020 19:15:56 +0100 Subject: [PATCH] Add filters.minAccuracy config option This allows us to ignore location points which do not meet the configured accuracy requirement. Closes #35. --- docs/config.md | 22 +++++++++++++++++ src/config.js | 3 +++ src/store/actions.js | 9 +++++-- src/store/getters.js | 58 ++++++++++++++++++++++++++++++++------------ src/views/Map.vue | 22 ++++++++++------- 5 files changed, 87 insertions(+), 27 deletions(-) diff --git a/docs/config.md b/docs/config.md index 3145676..284a4ca 100644 --- a/docs/config.md +++ b/docs/config.md @@ -26,6 +26,8 @@ window.owntracks.config = {}; - [`baseUrl`](#apibaseurl) - [`fetchOptions`](#apifetchoptions) - [`endDateTime`](#enddatetime) +- `filters` + - [`minAccuracy`](#filtersminaccuracy) - [`ignorePingLocation`](#ignorepinglocation) - [`locale`](#locale) - `map` @@ -124,6 +126,26 @@ Initial end date and time (browser timezone) for fetched data. }; ``` +### `filters.minAccuracy` + +Minimum accuracy in meters for location points to be rendered & included in the travelled distance. + +This filter is disabled by default as accuracies can vary across devices an locations, but you're +encouraged to set it as it can be a simple way to remove outliers and vastly improve the travelled +distance calculation. + +- Type: [`Number`] or `null` +- Default: `null` +- Example: + ```js + // Don't include location points with an accuracy of less than 100 meters + window.owntracks.config = { + filters: { + minAccuracy: 100 + } + }; + ``` + ### `ignorePingLocation` Remove the `ping/ping` location from the fetched data. This is useful when using the diff --git a/src/config.js b/src/config.js index 2abb640..fe065df 100644 --- a/src/config.js +++ b/src/config.js @@ -13,6 +13,9 @@ const DEFAULT_CONFIG = { fetchOptions: {}, }, endDateTime, + filters: { + minAccuracy: null, + }, ignorePingLocation: true, locale: "en", map: { diff --git a/src/store/actions.js b/src/store/actions.js index b386617..227bcdf 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -128,8 +128,13 @@ const _getDistanceTravelled = locationHistory => { Object.keys(locationHistory).forEach(user => { Object.keys(locationHistory[user]).forEach(device => { let lastLatLng = null; - locationHistory[user][device].forEach(coordinate => { - const latLng = L.latLng(coordinate.lat, coordinate.lon); + locationHistory[user][device].forEach(location => { + if ( + config.minAccurac !== null && + location.acc > config.filters.minAccuracy + ) + return; + const latLng = L.latLng(location.lat, location.lon); if (lastLatLng !== null) { const distance = distanceBetweenCoordinates(lastLatLng, latLng); if ( diff --git a/src/store/getters.js b/src/store/getters.js index 914c663..d1857ce 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -4,20 +4,46 @@ import config from "@/config"; import { distanceBetweenCoordinates } from "@/util"; /** - * From the selected users' and devices' location histories, create an - * array of all coordinates. + * Apply filters to the selected users' and devices' location histories. * * @param {State} state * @param {LocationHistory} state.locationHistory * Location history of selected users and devices + * @returns {LocationHistory} Filtered location history + */ +const filteredLocationHistory = state => { + const locationHistory = {}; + Object.keys(state.locationHistory).forEach(user => { + locationHistory[user] = {}; + Object.keys(state.locationHistory[user]).forEach(device => { + locationHistory[user][device] = []; + state.locationHistory[user][device].forEach(location => { + if ( + config.minAccurac !== null && + location.acc > config.filters.minAccuracy + ) + return; + locationHistory[user][device].push(location); + }); + }); + }); + return locationHistory; +}; + +/** + * From the selected users' and devices' location histories, create an + * array of all coordinates. + * + * @param {State} state * @returns {L.LatLng[]} All coordinates */ -const locationHistoryLatLngs = state => { +const filteredLocationHistoryLatLngs = state => { const latLngs = []; - Object.keys(state.locationHistory).forEach(user => { - Object.keys(state.locationHistory[user]).forEach(device => { - state.locationHistory[user][device].forEach(coordinate => { - latLngs.push(L.latLng(coordinate.lat, coordinate.lon)); + const locationHistory = filteredLocationHistory(state); + Object.keys(locationHistory).forEach(user => { + Object.keys(locationHistory[user]).forEach(device => { + locationHistory[user][device].forEach(location => { + latLngs.push(L.latLng(location.lat, location.lon)); }); }); }); @@ -30,17 +56,16 @@ const locationHistoryLatLngs = state => { * coordinates does not exceed `config.map.maxPointDistance`. * * @param {State} state - * @param {LocationHistory} state.locationHistory - * Location history of selected users and devices * @returns {L.LatLng[][]} Groups of coherent coordinates */ -const locationHistoryLatLngGroups = state => { +const filteredLocationHistoryLatLngGroups = state => { const groups = []; - Object.keys(state.locationHistory).forEach(user => { - Object.keys(state.locationHistory[user]).forEach(device => { + const locationHistory = filteredLocationHistory(state); + Object.keys(locationHistory).forEach(user => { + Object.keys(locationHistory[user]).forEach(device => { let latLngs = []; - state.locationHistory[user][device].forEach(coordinate => { - const latLng = L.latLng(coordinate.lat, coordinate.lon); + locationHistory[user][device].forEach(location => { + const latLng = L.latLng(location.lat, location.lon); // Skip if group splitting is disabled or this is the first // coordinate in the current group if ( @@ -68,6 +93,7 @@ const locationHistoryLatLngGroups = state => { }; export default { - locationHistoryLatLngs, - locationHistoryLatLngGroups, + filteredLocationHistory, + filteredLocationHistoryLatLngs, + filteredLocationHistoryLatLngGroups, }; diff --git a/src/views/Map.vue b/src/views/Map.vue index e2d68cc..82073ac 100644 --- a/src/views/Map.vue +++ b/src/views/Map.vue @@ -56,7 +56,7 @@