forked from MapComplete/MapComplete
First working version of the notes-layer, add filtering
This commit is contained in:
parent
ebb510da04
commit
91d2272861
19 changed files with 282 additions and 109 deletions
|
@ -403,6 +403,10 @@ export class ExtraFunctions {
|
|||
];
|
||||
|
||||
public static FullPatchFeature(params: ExtraFuncParams, feature) {
|
||||
if(feature._is_patched){
|
||||
return
|
||||
}
|
||||
feature._is_patched = true
|
||||
for (const func of ExtraFunctions.allFuncs) {
|
||||
feature[func._name] = func._f(params, feature)
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ export default class FeaturePipeline {
|
|||
|
||||
private readonly localStorageSavers = new Map<string, SaveTileToLocalStorageActor>()
|
||||
private readonly metataggingRecalculated = new UIEventSource<void>(undefined)
|
||||
|
||||
private readonly requestMetataggingRecalculation = new UIEventSource<Date>(undefined)
|
||||
|
||||
/**
|
||||
* Keeps track of all raw OSM-nodes.
|
||||
* Only initialized if 'type_node' is defined as layer
|
||||
|
@ -97,6 +98,10 @@ export default class FeaturePipeline {
|
|||
}
|
||||
);
|
||||
|
||||
this.requestMetataggingRecalculation.stabilized(500).addCallbackAndRunD(_ => {
|
||||
self.updateAllMetaTagging("Request stabilized")
|
||||
})
|
||||
|
||||
const neededTilesFromOsm = this.getNeededTilesFromOsm(this.sufficientlyZoomed)
|
||||
|
||||
const perLayerHierarchy = new Map<string, TileHierarchyMerger>()
|
||||
|
@ -141,7 +146,7 @@ export default class FeaturePipeline {
|
|||
tile => {
|
||||
new RegisteringAllFromFeatureSourceActor(tile, state.allElements)
|
||||
perLayerHierarchy.get(tile.layer.layerDef.id).registerTile(tile)
|
||||
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
||||
tile.features.addCallbackAndRunD(_ => self.onNewDataLoaded(tile))
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
@ -169,7 +174,10 @@ export default class FeaturePipeline {
|
|||
if (id === "current_view") {
|
||||
handlePriviligedFeatureSource(state.currentView)
|
||||
state.currentView.features.map(ffs => ffs[0]?.feature?.properties?.id).withEqualityStabilized((x,y) => x === y)
|
||||
.addCallbackAndRunD(_ => self.applyMetaTags(state.currentView, state))
|
||||
.addCallbackAndRunD(_ => {
|
||||
self.applyMetaTags(state.currentView, <any>this.state, `currentview changed`)
|
||||
}
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -187,7 +195,7 @@ export default class FeaturePipeline {
|
|||
console.debug("Loaded tile ", id, tile.tileIndex, "from local cache")
|
||||
new RegisteringAllFromFeatureSourceActor(tile, state.allElements)
|
||||
hierarchy.registerTile(tile);
|
||||
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
||||
tile.features.addCallbackAndRunD(_ => self.onNewDataLoaded(tile))
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -207,13 +215,13 @@ export default class FeaturePipeline {
|
|||
registerTile: (tile) => {
|
||||
new RegisteringAllFromFeatureSourceActor(tile, state.allElements)
|
||||
perLayerHierarchy.get(id).registerTile(tile)
|
||||
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
||||
tile.features.addCallbackAndRunD(_ => self.onNewDataLoaded(tile))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
new RegisteringAllFromFeatureSourceActor(src, state.allElements)
|
||||
perLayerHierarchy.get(id).registerTile(src)
|
||||
src.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(src))
|
||||
src.features.addCallbackAndRunD(_ => self.onNewDataLoaded(src))
|
||||
}
|
||||
} else {
|
||||
new DynamicGeoJsonTileSource(
|
||||
|
@ -221,7 +229,7 @@ export default class FeaturePipeline {
|
|||
tile => {
|
||||
new RegisteringAllFromFeatureSourceActor(tile, state.allElements)
|
||||
perLayerHierarchy.get(id).registerTile(tile)
|
||||
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
||||
tile.features.addCallbackAndRunD(_ => self.onNewDataLoaded(tile))
|
||||
},
|
||||
state
|
||||
)
|
||||
|
@ -242,7 +250,7 @@ export default class FeaturePipeline {
|
|||
saver?.addTile(tile)
|
||||
}
|
||||
perLayerHierarchy.get(tile.layer.layerDef.id).registerTile(tile)
|
||||
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
||||
tile.features.addCallbackAndRunD(_ => self.onNewDataLoaded(tile))
|
||||
|
||||
},
|
||||
state: state,
|
||||
|
@ -282,7 +290,12 @@ export default class FeaturePipeline {
|
|||
// We save the tile data for the given layer to local storage - data sourced from overpass
|
||||
self.localStorageSavers.get(tile.layer.layerDef.id)?.addTile(tile)
|
||||
perLayerHierarchy.get(source.layer.layerDef.id).registerTile(new RememberingSource(tile))
|
||||
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
||||
tile.features.addCallbackAndRunD(f => {
|
||||
if(f.length === 0){
|
||||
return
|
||||
}
|
||||
self.onNewDataLoaded(tile)
|
||||
})
|
||||
|
||||
}
|
||||
}),
|
||||
|
@ -302,9 +315,7 @@ export default class FeaturePipeline {
|
|||
// We don't bother to split them over tiles as it'll contain little features by default, so we simply add them like this
|
||||
perLayerHierarchy.get(perLayer.layer.layerDef.id).registerTile(perLayer)
|
||||
// AT last, we always apply the metatags whenever possible
|
||||
// @ts-ignore
|
||||
perLayer.features.addCallbackAndRunD(_ => self.applyMetaTags(perLayer, state))
|
||||
perLayer.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(perLayer))
|
||||
perLayer.features.addCallbackAndRunD(_ => self.onNewDataLoaded(perLayer))
|
||||
|
||||
},
|
||||
newGeometry
|
||||
|
@ -312,8 +323,8 @@ export default class FeaturePipeline {
|
|||
|
||||
|
||||
// Whenever fresh data comes in, we need to update the metatagging
|
||||
self.newDataLoadedSignal.stabilized(250).addCallback(_ => {
|
||||
self.updateAllMetaTagging()
|
||||
self.newDataLoadedSignal.stabilized(250).addCallback(src => {
|
||||
self.updateAllMetaTagging(`New data loaded by ${src.name} (and stabilized)`)
|
||||
})
|
||||
|
||||
|
||||
|
@ -325,9 +336,13 @@ export default class FeaturePipeline {
|
|||
}, [osmFeatureSource.isRunning]
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
|
||||
private onNewDataLoaded(src: FeatureSource){
|
||||
this.newDataLoadedSignal.setData(src)
|
||||
this.requestMetataggingRecalculation.setData(new Date())
|
||||
}
|
||||
|
||||
public GetAllFeaturesWithin(bbox: BBox): any[][] {
|
||||
const self = this
|
||||
const tiles = []
|
||||
|
@ -471,12 +486,16 @@ export default class FeaturePipeline {
|
|||
return updater;
|
||||
}
|
||||
|
||||
private applyMetaTags(src: FeatureSourceForLayer, state: any) {
|
||||
private applyMetaTags(src: FeatureSourceForLayer, state: any, reason: string) {
|
||||
const self = this
|
||||
if(src === undefined){
|
||||
throw "Src is undefined"
|
||||
}
|
||||
const layerDef = src.layer.layerDef;
|
||||
console.debug(`Applying metatags onto ${src.name} due to ${reason} which has ${src.features.data?.length} features`)
|
||||
if(src.features.data.length == 0){
|
||||
return
|
||||
}
|
||||
MetaTagging.addMetatags(
|
||||
src.features.data,
|
||||
{
|
||||
|
@ -494,18 +513,15 @@ export default class FeaturePipeline {
|
|||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
public updateAllMetaTagging() {
|
||||
public updateAllMetaTagging(reason: string) {
|
||||
const self = this;
|
||||
console.debug("Updating the meta tagging of all tiles as new data got loaded")
|
||||
this.perLayerHierarchy.forEach(hierarchy => {
|
||||
hierarchy.loadedTiles.forEach(tile => {
|
||||
self.applyMetaTags(tile, <any> this.state)
|
||||
self.applyMetaTags(tile, <any> this.state, `${reason} (tile ${tile.tileIndex})`)
|
||||
})
|
||||
})
|
||||
if(this.state.currentView !== undefined){
|
||||
this.applyMetaTags(this.state.currentView, <any> this.state)
|
||||
}
|
||||
self.metataggingRecalculated.ping()
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ export default class PerLayerFeatureSourceSplitter {
|
|||
if (features === undefined) {
|
||||
return;
|
||||
}
|
||||
if (layers.data === undefined) {
|
||||
if (layers.data === undefined || layers.data.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
|
|||
import Hash from "../../Web/Hash";
|
||||
import {BBox} from "../../BBox";
|
||||
import {ElementStorage} from "../../ElementStorage";
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export default class FilteringFeatureSource implements FeatureSourceForLayer, Tiled {
|
||||
public features: UIEventSource<{ feature: any; freshness: Date }[]> =
|
||||
|
@ -71,8 +70,8 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
|||
self.registerCallback(f.feature)
|
||||
|
||||
if (
|
||||
this.state.selectedElement.data?.id === f.feature.id ||
|
||||
f.feature.id === Hash.hash.data) {
|
||||
(this.state.selectedElement !== undefined && this.state.selectedElement.data?.id === f.feature.properties.id) ||
|
||||
(Hash.hash.data !== undefined && f.feature.properties.id === Hash.hash.data)) {
|
||||
// This is the selected object - it gets a free pass even if zoom is not sufficient or it is filtered away
|
||||
return true;
|
||||
}
|
||||
|
@ -89,6 +88,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
|||
}
|
||||
|
||||
const tagsFilter = layer.appliedFilters.data;
|
||||
console.log("Current filters for "+layer.layerDef.id+" are ",tagsFilter)
|
||||
for (const filter of tagsFilter ?? []) {
|
||||
const neededTags = filter.filter.options[filter.selected].osmTags
|
||||
if (!neededTags.matchesProperties(f.feature.properties)) {
|
||||
|
|
|
@ -44,7 +44,11 @@ export default class DynamicTileSource implements TileHierarchy<FeatureSourceFor
|
|||
return undefined
|
||||
}
|
||||
const tileRange = Tiles.TileRangeBetween(zoomlevel, bounds.getNorth(), bounds.getEast(), bounds.getSouth(), bounds.getWest())
|
||||
|
||||
if(tileRange.total > 10000){
|
||||
console.error("Got a really big tilerange, bounds and location might be out of sync")
|
||||
return undefined
|
||||
}
|
||||
|
||||
const needed = Tiles.MapRange(tileRange, (x, y) => Tiles.tile_index(zoomlevel, x, y)).filter(i => !self._loadedTiles.has(i))
|
||||
if (needed.length === 0) {
|
||||
return undefined
|
||||
|
|
|
@ -28,7 +28,6 @@ export default class MetaTagging {
|
|||
includeDates?: true | boolean,
|
||||
includeNonDates?: true | boolean
|
||||
}): boolean {
|
||||
|
||||
if (features === undefined || features.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -106,7 +105,6 @@ export default class MetaTagging {
|
|||
}
|
||||
public static createFunctionsForFeature(layerId: string, calculatedTags: [string, string, boolean][]): ((feature: any) => void)[] {
|
||||
const functions: ((feature: any) => any)[] = [];
|
||||
|
||||
for (const entry of calculatedTags) {
|
||||
const key = entry[0]
|
||||
const code = entry[1];
|
||||
|
@ -148,6 +146,7 @@ export default class MetaTagging {
|
|||
|
||||
// Lazy function
|
||||
const f = (feature: any) => {
|
||||
const oldValue = feature.properties[key]
|
||||
delete feature.properties[key]
|
||||
Object.defineProperty(feature.properties, key, {
|
||||
configurable: true,
|
||||
|
|
|
@ -9,7 +9,6 @@ import MapState from "./MapState";
|
|||
import SelectedFeatureHandler from "../Actors/SelectedFeatureHandler";
|
||||
import Hash from "../Web/Hash";
|
||||
import {BBox} from "../BBox";
|
||||
import {FeatureSourceForLayer} from "../FeatureSource/FeatureSource";
|
||||
|
||||
export default class FeaturePipelineState extends MapState {
|
||||
|
||||
|
@ -33,7 +32,7 @@ export default class FeaturePipelineState extends MapState {
|
|||
|
||||
const sourceBBox = source.features.map(allFeatures => BBox.bboxAroundAll(allFeatures.map(f => BBox.get(f.feature))))
|
||||
|
||||
// Do show features indicates if the 'showDataLayer' should be shown
|
||||
// Do show features indicates if the respective 'showDataLayer' should be shown. It can be hidden by e.g. clustering
|
||||
const doShowFeatures = source.features.map(
|
||||
f => {
|
||||
const z = self.locationControl.data.zoom
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue