This commit is contained in:
Pieter Vander Vennet 2024-05-24 18:21:59 +02:00
parent da7c9951c0
commit 99a6321cc9
2 changed files with 77 additions and 27 deletions

View file

@ -5,7 +5,6 @@ import List from "../UI/Base/List"
import Title from "../UI/Base/Title" import Title from "../UI/Base/Title"
import { BBox } from "./BBox" import { BBox } from "./BBox"
import { Feature, Geometry, MultiPolygon, Polygon } from "geojson" import { Feature, Geometry, MultiPolygon, Polygon } from "geojson"
import { GeoJSONFeature } from "maplibre-gl"
export interface ExtraFuncParams { export interface ExtraFuncParams {
/** /**
@ -508,9 +507,9 @@ export class ExtraFunctions {
public static constructHelpers( public static constructHelpers(
params: ExtraFuncParams params: ExtraFuncParams
): Record<ExtraFuncType, (feature: Feature) => Function> { ): Record<ExtraFuncType, (feature: Feature) => Function> {
const record: Record<string, (feature: GeoJSONFeature) => Function> = {} const record: Record<string, (feature: Feature) => Function> = {}
for (const f of ExtraFunctions.allFuncs) { for (const f of ExtraFunctions.allFuncs) {
if (this.types.indexOf(<any>f._name) < 0) { if ((<readonly string[]> this.types).indexOf(f._name) < 0) {
throw "Invalid extraFunc-type: " + f._name throw "Invalid extraFunc-type: " + f._name
} }
record[f._name] = (feat) => f._f(params, feat) record[f._name] = (feat) => f._f(params, feat)

View file

@ -9,11 +9,14 @@ import { IndexedFeatureSource } from "./FeatureSource/FeatureSource"
import OsmObjectDownloader from "./Osm/OsmObjectDownloader" import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
import { Utils } from "../Utils" import { Utils } from "../Utils"
import { Store, UIEventSource } from "./UIEventSource" import { Store, UIEventSource } from "./UIEventSource"
import { selectDefault } from "../Utils/selectDefault"
/** /**
* Metatagging adds various tags to the elements, e.g. lat, lon, surface area, ... * Metatagging adds various tags to the elements, e.g. lat, lon, surface area, ...
* *
* All metatags start with an underscore * All metatags start with an underscore.
*
* Will apply the metatags as soon as they are passed in
*/ */
export default class MetaTagging { export default class MetaTagging {
private static errorPrintCount = 0 private static errorPrintCount = 0
@ -23,6 +26,18 @@ export default class MetaTagging {
string, string,
((feature: Feature, propertiesStore: UIEventSource<any>) => void)[] ((feature: Feature, propertiesStore: UIEventSource<any>) => void)[]
>() >()
private state: {
readonly selectedElement: Store<Feature>;
readonly layout: LayoutConfig;
readonly osmObjectDownloader: OsmObjectDownloader;
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>;
readonly indexedFeatures: IndexedFeatureSource;
readonly featureProperties: FeaturePropertiesStore
}
private params: {
getFeatureById: (id) => Feature;
getFeaturesWithin: (layerId, bbox) => (Feature[][] | [Feature[]])
}
constructor(state: { constructor(state: {
readonly selectedElement: Store<Feature> readonly selectedElement: Store<Feature>
@ -32,7 +47,8 @@ export default class MetaTagging {
readonly indexedFeatures: IndexedFeatureSource readonly indexedFeatures: IndexedFeatureSource
readonly featureProperties: FeaturePropertiesStore readonly featureProperties: FeaturePropertiesStore
}) { }) {
const params = MetaTagging.createExtraFuncParams(state) this.state = state
const params = this.params = MetaTagging.createExtraFuncParams(state)
for (const layer of state.layout.layers) { for (const layer of state.layout.layers) {
if (layer.source === null) { if (layer.source === null) {
continue continue
@ -61,21 +77,55 @@ export default class MetaTagging {
}) })
} }
state.selectedElement.addCallbackAndRunD((feature) => { // Force update the tags of the currently selected element
const layer = state.layout.getMatchingLayer(feature.properties) state.selectedElement.addCallbackAndRunD(feature => {
// Force update the tags of the currently selected element this.updateCurrentSelectedElement()
MetaTagging.addMetatags( let lastUpdateMoment = new Date()
[feature], const tags = state?.featureProperties?.getStore(feature.properties.id)
params, console.log("Binding an updater to", feature)
layer, tags?.addCallbackD(() => {
state.layout, console.log("Received an update!")
state.osmObjectDownloader, if(feature !== state.selectedElement.data){
state.featureProperties, return true // Unregister, we are not the selected element anymore
{
evaluateStrict: true,
} }
) if(new Date().getTime() - lastUpdateMoment.getTime() < 250){
return
}
lastUpdateMoment = new Date()
window.requestIdleCallback(() => {
this.updateCurrentSelectedElement()
lastUpdateMoment = new Date()
})
})
}) })
}
/**
* Triggers an update of the calculated tags of the selected element
* @private
*/
private updateCurrentSelectedElement() {
const feature = this.state.selectedElement.data
if (!feature) {
return
}
const state = this.state
const layer = state.layout.getMatchingLayer(feature.properties)
// Force update if the tags of the element changed
MetaTagging.addMetatags(
[feature],
this.params,
layer,
state.layout,
state.osmObjectDownloader,
state.featureProperties,
{
evaluateStrict: true
}
)
} }
// noinspection JSUnusedGlobalSymbols // noinspection JSUnusedGlobalSymbols
@ -142,7 +192,7 @@ export default class MetaTagging {
const feature = features[i] const feature = features[i]
const tags = featurePropertiesStores?.getStore(feature.properties.id) const tags = featurePropertiesStores?.getStore(feature.properties.id)
let somethingChanged = false let somethingChanged = false
let definedTags = new Set(Object.getOwnPropertyNames(feature.properties)) const definedTags = new Set(Object.getOwnPropertyNames(feature.properties))
for (const metatag of metatagsToApply) { for (const metatag of metatagsToApply) {
try { try {
@ -161,6 +211,7 @@ export default class MetaTagging {
metatag.applyMetaTagsOnFeature(feature, layer, tags, state) metatag.applyMetaTagsOnFeature(feature, layer, tags, state)
if (options?.evaluateStrict) { if (options?.evaluateStrict) {
for (const key of metatag.keys) { for (const key of metatag.keys) {
// Important: we _have_ to evaluate this as this might trigger a calculation
const evaluated = feature.properties[key] const evaluated = feature.properties[key]
if (evaluated !== undefined) { if (evaluated !== undefined) {
strictlyEvaluated++ strictlyEvaluated++
@ -211,6 +262,7 @@ export default class MetaTagging {
atLeastOneFeatureChanged = true atLeastOneFeatureChanged = true
} }
} }
console.debug("Strictly evaluated ", strictlyEvaluated, " values") // Do not remove this
return atLeastOneFeatureChanged return atLeastOneFeatureChanged
} }
@ -228,12 +280,12 @@ export default class MetaTagging {
}) })
return feats return feats
} }
if(!state.perLayer.get(layerId)){ if (!state.perLayer.get(layerId)) {
// This layer is not loaded // This layer is not loaded
return [] return []
} }
return [state.perLayer.get(layerId).GetFeaturesWithin(bbox)] return [state.perLayer.get(layerId).GetFeaturesWithin(bbox)]
}, }
} }
} }
@ -278,8 +330,8 @@ export default class MetaTagging {
if (MetaTagging.errorPrintCount < MetaTagging.stopErrorOutputAt) { if (MetaTagging.errorPrintCount < MetaTagging.stopErrorOutputAt) {
console.warn( console.warn(
"Could not calculate a " + "Could not calculate a " +
(isStrict ? "strict " : "") + (isStrict ? "strict " : "") +
"calculated tag for key", "calculated tag for key",
key, key,
"for feature", "for feature",
feat.properties.id, feat.properties.id,
@ -287,9 +339,9 @@ export default class MetaTagging {
code, code,
"(in layer", "(in layer",
layerId + layerId +
") due to \n" + ") due to \n" +
e + e +
"\n. Are you the theme creator? Doublecheck your code. Note that the metatags might not be stable on new features", "\n. Are you the theme creator? Doublecheck your code. Note that the metatags might not be stable on new features",
e, e,
e.stack, e.stack,
{ feat } { feat }
@ -328,7 +380,6 @@ export default class MetaTagging {
const funcName = "metaTaggging_for_" + id const funcName = "metaTaggging_for_" + id
if (typeof MetaTagging.metataggingObject[funcName] !== "function") { if (typeof MetaTagging.metataggingObject[funcName] !== "function") {
console.log(MetaTagging.metataggingObject)
throw ( throw (
"Error: metatagging-object for this theme does not have an entry at " + "Error: metatagging-object for this theme does not have an entry at " +
funcName + funcName +