forked from MapComplete/MapComplete
		
	The overpassfeaturesource now only fetches layers that must be updated, fix #599
This commit is contained in:
		
							parent
							
								
									9b88478804
								
							
						
					
					
						commit
						00e5ce0b02
					
				
					 7 changed files with 56 additions and 10 deletions
				
			
		| 
						 | 
					@ -11,6 +11,8 @@ import {BBox} from "../BBox";
 | 
				
			||||||
import Loc from "../../Models/Loc";
 | 
					import Loc from "../../Models/Loc";
 | 
				
			||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
 | 
					import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
 | 
				
			||||||
import Constants from "../../Models/Constants";
 | 
					import Constants from "../../Models/Constants";
 | 
				
			||||||
 | 
					import TileFreshnessCalculator from "../FeatureSource/TileFreshnessCalculator";
 | 
				
			||||||
 | 
					import {Tiles} from "../../Models/TileRange";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class OverpassFeatureSource implements FeatureSource {
 | 
					export default class OverpassFeatureSource implements FeatureSource {
 | 
				
			||||||
| 
						 | 
					@ -38,9 +40,18 @@ export default class OverpassFeatureSource implements FeatureSource {
 | 
				
			||||||
        readonly overpassTimeout: UIEventSource<number>;
 | 
					        readonly overpassTimeout: UIEventSource<number>;
 | 
				
			||||||
        readonly currentBounds: UIEventSource<BBox>
 | 
					        readonly currentBounds: UIEventSource<BBox>
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private readonly _isActive: UIEventSource<boolean>;
 | 
					    private readonly _isActive: UIEventSource<boolean>
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Callback to handle all the data
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private readonly onBboxLoaded: (bbox: BBox, date: Date, layers: LayerConfig[], zoomlevel: number) => void;
 | 
					    private readonly onBboxLoaded: (bbox: BBox, date: Date, layers: LayerConfig[], zoomlevel: number) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Keeps track of how fresh the data is
 | 
				
			||||||
 | 
					     * @private
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private readonly freshnesses: Map<string, TileFreshnessCalculator>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(
 | 
					    constructor(
 | 
				
			||||||
        state: {
 | 
					        state: {
 | 
				
			||||||
            readonly locationControl: UIEventSource<Loc>,
 | 
					            readonly locationControl: UIEventSource<Loc>,
 | 
				
			||||||
| 
						 | 
					@ -54,13 +65,15 @@ export default class OverpassFeatureSource implements FeatureSource {
 | 
				
			||||||
            padToTiles: UIEventSource<number>,
 | 
					            padToTiles: UIEventSource<number>,
 | 
				
			||||||
            isActive?: UIEventSource<boolean>,
 | 
					            isActive?: UIEventSource<boolean>,
 | 
				
			||||||
            relationTracker: RelationsTracker,
 | 
					            relationTracker: RelationsTracker,
 | 
				
			||||||
            onBboxLoaded?: (bbox: BBox, date: Date, layers: LayerConfig[], zoomlevel: number) => void
 | 
					            onBboxLoaded?: (bbox: BBox, date: Date, layers: LayerConfig[], zoomlevel: number) => void,
 | 
				
			||||||
 | 
					            freshnesses?: Map<string, TileFreshnessCalculator>
 | 
				
			||||||
        }) {
 | 
					        }) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.state = state
 | 
					        this.state = state
 | 
				
			||||||
        this._isActive = options.isActive;
 | 
					        this._isActive = options.isActive;
 | 
				
			||||||
        this.onBboxLoaded = options.onBboxLoaded
 | 
					        this.onBboxLoaded = options.onBboxLoaded
 | 
				
			||||||
        this.relationsTracker = options.relationTracker
 | 
					        this.relationsTracker = options.relationTracker
 | 
				
			||||||
 | 
					        this.freshnesses = options.freshnesses
 | 
				
			||||||
        const self = this;
 | 
					        const self = this;
 | 
				
			||||||
        state.currentBounds.addCallback(_ => {
 | 
					        state.currentBounds.addCallback(_ => {
 | 
				
			||||||
            self.update(options.padToTiles.data)
 | 
					            self.update(options.padToTiles.data)
 | 
				
			||||||
| 
						 | 
					@ -117,6 +130,7 @@ export default class OverpassFeatureSource implements FeatureSource {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const layersToDownload = []
 | 
					        const layersToDownload = []
 | 
				
			||||||
 | 
					        const neededTiles = this.state.currentBounds.data.expandToTileBounds(padToZoomLevel).containingTileRange(padToZoomLevel)
 | 
				
			||||||
        for (const layer of this.state.layoutToUse.layers) {
 | 
					        for (const layer of this.state.layoutToUse.layers) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (typeof (layer) === "string") {
 | 
					            if (typeof (layer) === "string") {
 | 
				
			||||||
| 
						 | 
					@ -135,9 +149,32 @@ export default class OverpassFeatureSource implements FeatureSource {
 | 
				
			||||||
                // Not our responsibility to download this layer!
 | 
					                // Not our responsibility to download this layer!
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            const freshness = this.freshnesses?.get(layer.id)
 | 
				
			||||||
 | 
					            if (freshness !== undefined) {
 | 
				
			||||||
 | 
					                const oldestDataDate = Math.min(...Tiles.MapRange(neededTiles, (x, y) => {
 | 
				
			||||||
 | 
					                    const date = freshness.freshnessFor(padToZoomLevel, x, y);
 | 
				
			||||||
 | 
					                    if (date === undefined) {
 | 
				
			||||||
 | 
					                        return 0
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    return date.getTime()
 | 
				
			||||||
 | 
					                })) / 1000;
 | 
				
			||||||
 | 
					                const now = new Date().getTime()
 | 
				
			||||||
 | 
					                const minRequiredAge = (now / 1000) - layer.maxAgeOfCache
 | 
				
			||||||
 | 
					                if (oldestDataDate >= minRequiredAge) {
 | 
				
			||||||
 | 
					                    // still fresh enough - not updating
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            layersToDownload.push(layer)
 | 
					            layersToDownload.push(layer)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (layersToDownload.length == 0) {
 | 
				
			||||||
 | 
					            console.debug("Not updating - no layers needed")
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const self = this;
 | 
					        const self = this;
 | 
				
			||||||
        const overpassUrls = self.state.overpassUrl.data
 | 
					        const overpassUrls = self.state.overpassUrl.data
 | 
				
			||||||
        let bounds: BBox
 | 
					        let bounds: BBox
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,10 @@
 | 
				
			||||||
import FeatureSource from "../FeatureSource";
 | 
					import FeatureSource from "../FeatureSource";
 | 
				
			||||||
import {UIEventSource} from "../../UIEventSource";
 | 
					import {UIEventSource} from "../../UIEventSource";
 | 
				
			||||||
import State from "../../../State";
 | 
					 | 
				
			||||||
import ElementsState from "../../State/ElementsState";
 | 
					 | 
				
			||||||
import {ElementStorage} from "../../ElementStorage";
 | 
					import {ElementStorage} from "../../ElementStorage";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Makes sure that every feature is added to the ElementsStorage, so that the tags-eventsource can be retrieved
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
export default class RegisteringAllFromFeatureSourceActor {
 | 
					export default class RegisteringAllFromFeatureSourceActor {
 | 
				
			||||||
    public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
 | 
					    public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
 | 
				
			||||||
    public readonly name;
 | 
					    public readonly name;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,18 +40,23 @@ import {ElementStorage} from "../ElementStorage";
 | 
				
			||||||
export default class FeaturePipeline {
 | 
					export default class FeaturePipeline {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public readonly sufficientlyZoomed: UIEventSource<boolean>;
 | 
					    public readonly sufficientlyZoomed: UIEventSource<boolean>;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public readonly runningQuery: UIEventSource<boolean>;
 | 
					    public readonly runningQuery: UIEventSource<boolean>;
 | 
				
			||||||
    public readonly timeout: UIEventSource<number>;
 | 
					    public readonly timeout: UIEventSource<number>;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public readonly somethingLoaded: UIEventSource<boolean> = new UIEventSource<boolean>(false)
 | 
					    public readonly somethingLoaded: UIEventSource<boolean> = new UIEventSource<boolean>(false)
 | 
				
			||||||
    public readonly newDataLoadedSignal: UIEventSource<FeatureSource> = new UIEventSource<FeatureSource>(undefined)
 | 
					    public readonly newDataLoadedSignal: UIEventSource<FeatureSource> = new UIEventSource<FeatureSource>(undefined)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    private readonly overpassUpdater: OverpassFeatureSource
 | 
					    private readonly overpassUpdater: OverpassFeatureSource
 | 
				
			||||||
    private state: MapState;
 | 
					    private state: MapState;
 | 
				
			||||||
    private readonly relationTracker: RelationsTracker
 | 
					    private readonly relationTracker: RelationsTracker
 | 
				
			||||||
    private readonly perLayerHierarchy: Map<string, TileHierarchyMerger>;
 | 
					    private readonly perLayerHierarchy: Map<string, TileHierarchyMerger>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Keeps track of the age of the loaded data.
 | 
				
			||||||
 | 
					     * Has one freshness-Calculator for every layer
 | 
				
			||||||
 | 
					     * @private
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private readonly freshnesses = new Map<string, TileFreshnessCalculator>();
 | 
					    private readonly freshnesses = new Map<string, TileFreshnessCalculator>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private readonly oldestAllowedDate: Date;
 | 
					    private readonly oldestAllowedDate: Date;
 | 
				
			||||||
| 
						 | 
					@ -468,6 +473,7 @@ export default class FeaturePipeline {
 | 
				
			||||||
                padToTiles: state.locationControl.map(l => Math.min(15, l.zoom + 1)),
 | 
					                padToTiles: state.locationControl.map(l => Math.min(15, l.zoom + 1)),
 | 
				
			||||||
                relationTracker: this.relationTracker,
 | 
					                relationTracker: this.relationTracker,
 | 
				
			||||||
                isActive: useOsmApi.map(b => !b && overpassIsActive.data, [overpassIsActive]),
 | 
					                isActive: useOsmApi.map(b => !b && overpassIsActive.data, [overpassIsActive]),
 | 
				
			||||||
 | 
					                freshnesses: this.freshnesses,
 | 
				
			||||||
                onBboxLoaded: (bbox, date, downloadedLayers, paddedToZoomLevel) => {
 | 
					                onBboxLoaded: (bbox, date, downloadedLayers, paddedToZoomLevel) => {
 | 
				
			||||||
                    Tiles.MapRange(bbox.containingTileRange(paddedToZoomLevel), (x, y) => {
 | 
					                    Tiles.MapRange(bbox.containingTileRange(paddedToZoomLevel), (x, y) => {
 | 
				
			||||||
                        const tileIndex = Tiles.tile_index(paddedToZoomLevel, x, y)
 | 
					                        const tileIndex = Tiles.tile_index(paddedToZoomLevel, x, y)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,9 @@ import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig";
 | 
				
			||||||
import {Or} from "../../Tags/Or";
 | 
					import {Or} from "../../Tags/Or";
 | 
				
			||||||
import {TagsFilter} from "../../Tags/TagsFilter";
 | 
					import {TagsFilter} from "../../Tags/TagsFilter";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * If a tile is needed (requested via the UIEventSource in the constructor), will download the appropriate tile and pass it via 'handleTile'
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
export default class OsmFeatureSource {
 | 
					export default class OsmFeatureSource {
 | 
				
			||||||
    public readonly isRunning: UIEventSource<boolean> = new UIEventSource<boolean>(false)
 | 
					    public readonly isRunning: UIEventSource<boolean> = new UIEventSource<boolean>(false)
 | 
				
			||||||
    public readonly downloadedTiles = new Set<number>()
 | 
					    public readonly downloadedTiles = new Set<number>()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,6 @@ export class Overpass {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._relationTracker.RegisterRelations(json)
 | 
					        self._relationTracker.RegisterRelations(json)
 | 
				
			||||||
        console.warn("OSMTOGEOJSON:", osmtogeojson)
 | 
					 | 
				
			||||||
        const geojson = osmtogeojson.default(json);
 | 
					        const geojson = osmtogeojson.default(json);
 | 
				
			||||||
        const osmTime = new Date(json.osm3s.timestamp_osm_base);
 | 
					        const osmTime = new Date(json.osm3s.timestamp_osm_base);
 | 
				
			||||||
        return [geojson, osmTime];
 | 
					        return [geojson, osmTime];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ import {Utils} from "../Utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class Constants {
 | 
					export default class Constants {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static vNumber = "0.14.0-alpha-4";
 | 
					    public static vNumber = "0.14.0-alpha-5";
 | 
				
			||||||
    public static ImgurApiKey = '7070e7167f0a25a'
 | 
					    public static ImgurApiKey = '7070e7167f0a25a'
 | 
				
			||||||
    public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
 | 
					    public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -153,7 +153,7 @@ export default class LayoutConfig {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.overpassTimeout = json.overpassTimeout ?? 30
 | 
					        this.overpassTimeout = json.overpassTimeout ?? 30
 | 
				
			||||||
        this.overpassMaxZoom = json.overpassMaxZoom ?? 17
 | 
					        this.overpassMaxZoom = json.overpassMaxZoom ?? 16
 | 
				
			||||||
        this.osmApiTileSize = json.osmApiTileSize ?? this.overpassMaxZoom + 1
 | 
					        this.osmApiTileSize = json.osmApiTileSize ?? this.overpassMaxZoom + 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue