First working version of the notes-layer, add filtering

This commit is contained in:
Pieter Vander Vennet 2022-01-07 17:31:39 +01:00
parent ebb510da04
commit 91d2272861
19 changed files with 282 additions and 109 deletions

View file

@ -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)
}

View file

@ -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()
}

View file

@ -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;
}

View file

@ -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)) {

View file

@ -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

View file

@ -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,

View file

@ -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