forked from MapComplete/MapComplete
Better handling of GPX-state
This commit is contained in:
parent
519feaa54b
commit
a37a7462a2
17 changed files with 585 additions and 412 deletions
|
@ -10,7 +10,7 @@ import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
|||
* Makes sure the hash shows the selected element and vice-versa.
|
||||
*/
|
||||
export default class SelectedFeatureHandler {
|
||||
private static readonly _no_trigger_on = new Set(["welcome", "copyright", "layers", "new", "filters", "", undefined])
|
||||
private static readonly _no_trigger_on = new Set(["welcome", "copyright", "layers", "new", "filters", "location_track", "", undefined])
|
||||
private readonly hash: UIEventSource<string>;
|
||||
private readonly state: {
|
||||
selectedElement: UIEventSource<any>,
|
||||
|
|
|
@ -5,11 +5,9 @@ import FeatureSource, {FeatureSourceForLayer, IndexedFeatureSource, Tiled} from
|
|||
import TiledFeatureSource from "./TiledFeatureSource/TiledFeatureSource";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import {TileHierarchyTools} from "./TiledFeatureSource/TileHierarchy";
|
||||
import FilteredLayer from "../../Models/FilteredLayer";
|
||||
import MetaTagging from "../MetaTagging";
|
||||
import RememberingSource from "./Sources/RememberingSource";
|
||||
import OverpassFeatureSource from "../Actors/OverpassFeatureSource";
|
||||
import {Changes} from "../Osm/Changes";
|
||||
import GeoJsonSource from "./Sources/GeoJsonSource";
|
||||
import Loc from "../../Models/Loc";
|
||||
import RegisteringAllFromFeatureSourceActor from "./Actors/RegisteringAllFromFeatureSourceActor";
|
||||
|
@ -22,11 +20,10 @@ import {NewGeometryFromChangesFeatureSource} from "./Sources/NewGeometryFromChan
|
|||
import ChangeGeometryApplicator from "./Sources/ChangeGeometryApplicator";
|
||||
import {BBox} from "../BBox";
|
||||
import OsmFeatureSource from "./TiledFeatureSource/OsmFeatureSource";
|
||||
import {OsmConnection} from "../Osm/OsmConnection";
|
||||
import {Tiles} from "../../Models/TileRange";
|
||||
import TileFreshnessCalculator from "./TileFreshnessCalculator";
|
||||
import {ElementStorage} from "../ElementStorage";
|
||||
import FullNodeDatabaseSource from "./TiledFeatureSource/FullNodeDatabaseSource";
|
||||
import MapState from "../State/MapState";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -51,19 +48,7 @@ export default class FeaturePipeline {
|
|||
public readonly newDataLoadedSignal: UIEventSource<FeatureSource> = new UIEventSource<FeatureSource>(undefined)
|
||||
|
||||
private readonly overpassUpdater: OverpassFeatureSource
|
||||
private state: {
|
||||
readonly filteredLayers: UIEventSource<FilteredLayer[]>,
|
||||
readonly locationControl: UIEventSource<Loc>,
|
||||
readonly selectedElement: UIEventSource<any>,
|
||||
readonly changes: Changes,
|
||||
readonly layoutToUse: LayoutConfig,
|
||||
readonly leafletMap: any,
|
||||
readonly overpassUrl: UIEventSource<string[]>;
|
||||
readonly overpassTimeout: UIEventSource<number>;
|
||||
readonly overpassMaxZoom: UIEventSource<number>;
|
||||
readonly osmConnection: OsmConnection
|
||||
readonly currentBounds: UIEventSource<BBox>
|
||||
};
|
||||
private state: MapState;
|
||||
private readonly relationTracker: RelationsTracker
|
||||
private readonly perLayerHierarchy: Map<string, TileHierarchyMerger>;
|
||||
|
||||
|
@ -74,24 +59,7 @@ export default class FeaturePipeline {
|
|||
|
||||
constructor(
|
||||
handleFeatureSource: (source: FeatureSourceForLayer & Tiled) => void,
|
||||
state: {
|
||||
readonly historicalUserLocations: FeatureSourceForLayer & Tiled;
|
||||
readonly homeLocation: FeatureSourceForLayer & Tiled;
|
||||
readonly currentUserLocation: FeatureSourceForLayer & Tiled;
|
||||
readonly filteredLayers: UIEventSource<FilteredLayer[]>,
|
||||
readonly locationControl: UIEventSource<Loc>,
|
||||
readonly selectedElement: UIEventSource<any>,
|
||||
readonly changes: Changes,
|
||||
readonly layoutToUse: LayoutConfig,
|
||||
readonly leafletMap: any,
|
||||
readonly overpassUrl: UIEventSource<string[]>;
|
||||
readonly overpassTimeout: UIEventSource<number>;
|
||||
readonly overpassMaxZoom: UIEventSource<number>;
|
||||
readonly osmConnection: OsmConnection
|
||||
readonly currentBounds: UIEventSource<BBox>,
|
||||
readonly osmApiTileSize: UIEventSource<number>,
|
||||
readonly allElements: ElementStorage
|
||||
}) {
|
||||
state: MapState) {
|
||||
this.state = state;
|
||||
|
||||
const self = this
|
||||
|
@ -138,7 +106,7 @@ export default class FeaturePipeline {
|
|||
handleFeatureSource(srcFiltered)
|
||||
self.somethingLoaded.setData(true)
|
||||
// We do not mark as visited here, this is the responsability of the code near the actual loader (e.g. overpassLoader and OSMApiFeatureLoader)
|
||||
};
|
||||
}
|
||||
|
||||
function handlePriviligedFeatureSource(src: FeatureSourceForLayer & Tiled){
|
||||
// Passthrough to passed function, except that it registers as well
|
||||
|
@ -168,11 +136,16 @@ export default class FeaturePipeline {
|
|||
continue
|
||||
}
|
||||
|
||||
if (id === "gps_track") {
|
||||
if (id === "gps_location_history") {
|
||||
handlePriviligedFeatureSource(state.historicalUserLocations)
|
||||
continue
|
||||
}
|
||||
|
||||
if (id === "gps_track") {
|
||||
handlePriviligedFeatureSource(state.historicalUserLocationsTrack)
|
||||
continue
|
||||
}
|
||||
|
||||
if (id === "home_location") {
|
||||
handlePriviligedFeatureSource(state.homeLocation)
|
||||
continue
|
||||
|
|
|
@ -16,6 +16,8 @@ import FilterConfig from "../../Models/ThemeConfig/FilterConfig";
|
|||
import ShowOverlayLayer from "../../UI/ShowDataLayer/ShowOverlayLayer";
|
||||
import {FeatureSourceForLayer, Tiled} from "../FeatureSource/FeatureSource";
|
||||
import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource";
|
||||
import {LocalStorageSource} from "../Web/LocalStorageSource";
|
||||
import {GeoOperations} from "../GeoOperations";
|
||||
|
||||
/**
|
||||
* Contains all the leaflet-map related state
|
||||
|
@ -52,6 +54,11 @@ export default class MapState extends UserRelatedState {
|
|||
* All previously visited points
|
||||
*/
|
||||
public historicalUserLocations: FeatureSourceForLayer & Tiled;
|
||||
/**
|
||||
* The number of seconds that the GPS-locations are stored in memory
|
||||
*/
|
||||
public gpsLocationHistoryRetentionTime = new UIEventSource(7 * 24 * 60 * 60, "gps_location_retention" )
|
||||
public historicalUserLocationsTrack: FeatureSourceForLayer & Tiled;
|
||||
|
||||
/**
|
||||
* A feature source containing the current home location of the user
|
||||
|
@ -70,7 +77,7 @@ export default class MapState extends UserRelatedState {
|
|||
*/
|
||||
public overlayToggles: { config: TilesourceConfig, isDisplayed: UIEventSource<boolean> }[]
|
||||
|
||||
|
||||
|
||||
constructor(layoutToUse: LayoutConfig) {
|
||||
super(layoutToUse);
|
||||
|
||||
|
@ -188,42 +195,75 @@ export default class MapState extends UserRelatedState {
|
|||
}
|
||||
|
||||
private initUserLocationTrail(){
|
||||
const histCoordinates = []
|
||||
let lineFeature = {
|
||||
type:"Feature",
|
||||
geometry:{
|
||||
type: "LineString",
|
||||
coordinates: histCoordinates
|
||||
},
|
||||
properties:{
|
||||
"user:location":"yes",
|
||||
"id":"gps_track"
|
||||
}
|
||||
}
|
||||
const features = new UIEventSource<{feature: any, freshness: Date}[]>([], "gps_track")
|
||||
const features = LocalStorageSource.GetParsed<{feature: any, freshness: Date}[]>("gps_location_history", [])
|
||||
const now = new Date().getTime()
|
||||
features.data = features.data
|
||||
.map(ff => ({feature: ff.feature, freshness: new Date(ff.freshness)}))
|
||||
.filter(ff => (now - ff.freshness.getTime()) < this.gpsLocationHistoryRetentionTime.data)
|
||||
features.ping()
|
||||
const self = this;
|
||||
let i = 0
|
||||
this.currentUserLocation.features.addCallbackAndRunD(([location]) => {
|
||||
if(location === undefined){
|
||||
return;
|
||||
}
|
||||
const feature = JSON.parse(JSON.stringify(location.feature))
|
||||
feature.properties.id = "gps/"+i
|
||||
i++
|
||||
features.data.push({feature, freshness: new Date()})
|
||||
histCoordinates.push(feature.geometry.coordinates)
|
||||
|
||||
if(lineFeature !== undefined && lineFeature.geometry.coordinates.length >= 2){
|
||||
features.data.push({feature: lineFeature, freshness: new Date()})
|
||||
lineFeature = undefined
|
||||
const previousLocation = features.data[features.data.length - 1]
|
||||
if(previousLocation !== undefined){
|
||||
const d = GeoOperations.distanceBetween(
|
||||
previousLocation.feature.geometry.coordinates,
|
||||
location.feature.geometry.coordinates
|
||||
|
||||
)
|
||||
if(d < 20){
|
||||
// Do not append changes less then 20m - it's probably noise anyway
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const feature = JSON.parse(JSON.stringify(location.feature))
|
||||
feature.properties.id = "gps/"+features.data.length
|
||||
i++
|
||||
features.data.push({feature, freshness: new Date()})
|
||||
features.ping()
|
||||
})
|
||||
|
||||
|
||||
let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_track")[0]
|
||||
let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location_history")[0]
|
||||
this.historicalUserLocations = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0), features);
|
||||
this.changes.useLocationHistory(this)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const asLine = features.map(allPoints => {
|
||||
if(allPoints === undefined || allPoints.length < 2){
|
||||
return []
|
||||
}
|
||||
|
||||
const feature = {
|
||||
type: "Feature",
|
||||
properties:{
|
||||
"id":"location_track",
|
||||
"_date:now": new Date().toISOString(),
|
||||
},
|
||||
geometry:{
|
||||
type: "LineString",
|
||||
coordinates: allPoints.map(ff => ff.feature.geometry.coordinates)
|
||||
}
|
||||
}
|
||||
|
||||
self.allElements.ContainingFeatures.set(feature.properties.id, feature)
|
||||
|
||||
return [{
|
||||
feature,
|
||||
freshness: new Date()
|
||||
}]
|
||||
})
|
||||
let gpsLineLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_track")[0]
|
||||
this.historicalUserLocationsTrack = new SimpleFeatureSource(gpsLineLayerDef, Tiles.tile_index(0, 0, 0), asLine);
|
||||
}
|
||||
|
||||
private initHomeLocation() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue