forked from MapComplete/MapComplete
		
	Fix #287
This commit is contained in:
		
							parent
							
								
									da7c9951c0
								
							
						
					
					
						commit
						99a6321cc9
					
				
					 2 changed files with 77 additions and 27 deletions
				
			
		|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -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 + | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue