refactoring

This commit is contained in:
Pieter Vander Vennet 2023-03-28 05:13:48 +02:00
parent b94a8f5745
commit 5d0fe31c41
114 changed files with 2412 additions and 2958 deletions

View file

@ -1,10 +1,5 @@
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
import FeaturePipeline from "../FeatureSource/FeaturePipeline"
import { Tiles } from "../../Models/TileRange"
import SelectedFeatureHandler from "../Actors/SelectedFeatureHandler"
import Hash from "../Web/Hash"
import { BBox } from "../BBox"
import { FeatureSourceForLayer, Tiled } from "../FeatureSource/FeatureSource"
import MetaTagRecalculator from "../FeatureSource/Actors/MetaTagRecalculator"
export default class FeaturePipelineState {
@ -14,101 +9,9 @@ export default class FeaturePipelineState {
public readonly featurePipeline: FeaturePipeline
private readonly metatagRecalculator: MetaTagRecalculator
constructor(layoutToUse: LayoutConfig) {
const clustering = layoutToUse?.clustering
const clusterCounter = this.featureAggregator
const self = this
/**
* We are a bit in a bind:
* There is the featurePipeline, which creates some sources during construction
* THere is the metatagger, which needs to have these sources registered AND which takes a FeaturePipeline as argument
*
* This is a bit of a catch-22 (except that it isn't)
* The sources that are registered in the constructor are saved into 'registeredSources' temporary
*
*/
const sourcesToRegister = []
function registerRaw(source: FeatureSourceForLayer & Tiled) {
if (self.metatagRecalculator === undefined) {
sourcesToRegister.push(source)
} else {
self.metatagRecalculator.registerSource(source)
}
}
function registerSource(source: FeatureSourceForLayer & Tiled) {
clusterCounter.addTile(source)
const sourceBBox = source.features.map((allFeatures) =>
BBox.bboxAroundAll(allFeatures.map(BBox.get))
)
// Do show features indicates if the respective 'showDataLayer' should be shown. It can be hidden by e.g. clustering
source.features.map(
(f) => {
const z = self.locationControl.data.zoom
if (!source.layer.isDisplayed.data) {
return false
}
const bounds = self.currentBounds.data
if (bounds === undefined) {
// Map is not yet displayed
return false
}
if (!sourceBBox.data.overlapsWith(bounds)) {
// Not within range -> features are hidden
return false
}
if (z < source.layer.layerDef.minzoom) {
// Layer is always hidden for this zoom level
return false
}
if (z > clustering.maxZoom) {
return true
}
if (f.length > clustering.minNeededElements) {
// This tile alone already has too much features
return false
}
let [tileZ, tileX, tileY] = Tiles.tile_from_index(source.tileIndex)
if (tileZ >= z) {
while (tileZ > z) {
tileZ--
tileX = Math.floor(tileX / 2)
tileY = Math.floor(tileY / 2)
}
if (
clusterCounter.getTile(Tiles.tile_index(tileZ, tileX, tileY))
?.totalValue > clustering.minNeededElements
) {
// To much elements
return false
}
}
return true
},
[self.currentBounds, source.layer.isDisplayed, sourceBBox]
)
}
this.featurePipeline = new FeaturePipeline(registerSource, this, {
handleRawFeatureSource: registerRaw,
})
constructor() {
this.metatagRecalculator = new MetaTagRecalculator(this, this.featurePipeline)
this.metatagRecalculator.registerSource(this.currentView)
sourcesToRegister.forEach((source) => self.metatagRecalculator.registerSource(source))
new SelectedFeatureHandler(Hash.hash, this)
}
}

View file

@ -1,10 +1,8 @@
import { UIEventSource } from "../UIEventSource"
import { GlobalFilter } from "../../Models/GlobalFilter"
import FilteredLayer, { FilterState } from "../../Models/FilteredLayer"
import FilteredLayer from "../../Models/FilteredLayer"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import { OsmConnection } from "../Osm/OsmConnection"
import { LocalStorageSource } from "../Web/LocalStorageSource"
import { QueryParameters } from "../Web/QueryParameters"
/**
* The layer state keeps track of:
@ -36,83 +34,14 @@ export default class LayerState {
this.osmConnection = osmConnection
this.filteredLayers = new Map()
for (const layer of layers) {
this.filteredLayers.set(layer.id, this.initFilteredLayer(layer, context))
this.filteredLayers.set(
layer.id,
FilteredLayer.initLinkedState(layer, context, this.osmConnection)
)
}
layers.forEach((l) => this.linkFilterStates(l))
}
private static getPref(
osmConnection: OsmConnection,
key: string,
layer: LayerConfig
): UIEventSource<boolean> {
return osmConnection.GetPreference(key, layer.shownByDefault + "").sync(
(v) => {
if (v === undefined) {
return undefined
}
return v === "true"
},
[],
(b) => {
if (b === undefined) {
return undefined
}
return "" + b
}
)
}
/**
* INitializes a filtered layer for the given layer.
* @param layer
* @param context: probably the theme-name. This is used to disambiguate the user settings; e.g. when using the same layer in different contexts
* @private
*/
private initFilteredLayer(layer: LayerConfig, context: string): FilteredLayer | undefined {
let isDisplayed: UIEventSource<boolean>
const osmConnection = this.osmConnection
if (layer.syncSelection === "local") {
isDisplayed = LocalStorageSource.GetParsed(
context + "-layer-" + layer.id + "-enabled",
layer.shownByDefault
)
} else if (layer.syncSelection === "theme-only") {
isDisplayed = LayerState.getPref(
osmConnection,
context + "-layer-" + layer.id + "-enabled",
layer
)
} else if (layer.syncSelection === "global") {
isDisplayed = LayerState.getPref(osmConnection, "layer-" + layer.id + "-enabled", layer)
} else {
isDisplayed = QueryParameters.GetBooleanQueryParameter(
"layer-" + layer.id,
layer.shownByDefault,
"Wether or not layer " + layer.id + " is shown"
)
}
const flayer: FilteredLayer = {
isDisplayed,
layerDef: layer,
appliedFilters: new UIEventSource<Map<string, FilterState>>(
new Map<string, FilterState>()
),
}
layer.filters?.forEach((filterConfig) => {
const stateSrc = filterConfig.initState()
stateSrc.addCallbackAndRun((state) =>
flayer.appliedFilters.data.set(filterConfig.id, state)
)
flayer.appliedFilters
.map((dict) => dict.get(filterConfig.id))
.addCallback((state) => stateSrc.setData(state))
})
return flayer
}
/**
* Some layers copy the filter state of another layer - this is quite often the case for 'sibling'-layers,
* (where two variations of the same layer are used, e.g. a specific type of shop on all zoom levels and all shops on high zoom).
@ -136,10 +65,6 @@ export default class LayerState {
console.warn(
"Linking filter and isDisplayed-states of " + layer.id + " and " + layer.filterIsSameAs
)
this.filteredLayers.set(layer.id, {
isDisplayed: toReuse.isDisplayed,
layerDef: layer,
appliedFilters: toReuse.appliedFilters,
})
this.filteredLayers.set(layer.id, toReuse)
}
}

View file

@ -17,14 +17,10 @@ export default class UserRelatedState {
The user credentials
*/
public osmConnection: OsmConnection
/**
THe change handler
*/
public changes: Changes
/**
* The key for mangrove
*/
public mangroveIdentity: MangroveIdentity
public readonly mangroveIdentity: MangroveIdentity
public readonly installedUserThemes: Store<string[]>