Fix metatagging and calculated tags in heterogenous data settings

This commit is contained in:
Pieter Vander Vennet 2021-05-16 15:34:44 +02:00
parent 93296d5378
commit d547b9f968
14 changed files with 374 additions and 246 deletions

View file

@ -81,6 +81,9 @@ export default class LayerConfig {
osmTags = FromJSON.Tag(json.source["osmTags"], context + "source.osmTags");
}
if(json.source["geoJsonSource"] !== undefined){
throw context + "Use 'geoJson' instead of 'geoJsonSource'"
}
this.source = new SourceConfig({
osmTags: osmTags,
@ -172,7 +175,10 @@ export default class LayerConfig {
if (shared !== undefined) {
return shared;
}
throw `Predefined tagRendering ${renderingJson} not found in ${context}`;
const keys = Array.from(SharedTagRenderings.SharedTagRendering.keys())
throw `Predefined tagRendering ${renderingJson} not found in ${context}.\n Try one of ${(keys.join(", "))}`;
}
return new TagRenderingConfig(renderingJson, self.source.osmTags, `${context}.tagrendering[${i}]`);
});

View file

@ -6,6 +6,7 @@ import {UIEventSource} from "./UIEventSource";
export class ElementStorage {
private _elements = new Map<string, UIEventSource<any>>();
public ContainingFeatures = new Map<string, any>();
constructor() {
@ -29,6 +30,11 @@ export class ElementStorage {
// At last, we overwrite the tag of the new feature to use the tags in the already existing event source
feature.properties = es.data
if(!this.ContainingFeatures.has(elementId)){
this.ContainingFeatures.set(elementId, feature);
}
return es;
}

View file

@ -2,6 +2,8 @@ import {GeoOperations} from "./GeoOperations";
import {UIElement} from "../UI/UIElement";
import Combine from "../UI/Base/Combine";
import {Relation} from "./Osm/ExtractRelations";
import State from "../State";
import {Utils} from "../Utils";
export class ExtraFunction {
@ -59,17 +61,25 @@ Some advanced functions are available on <b>feat</b> as well:
)
private static readonly DistanceToFunc = new ExtraFunction(
"distanceTo",
"Calculates the distance between the feature and a specified point",
"Calculates the distance between the feature and a specified point in kilometer. The input should either be a pair of coordinates, a geojson feature or the ID of an object",
["longitude", "latitude"],
(featuresPerLayer, feature) => {
return (arg0, lat) => {
if (typeof arg0 === "number") {
// Feature._lon and ._lat is conveniently place by one of the other metatags
return GeoOperations.distanceBetween([arg0, lat], [feature._lon, feature._lat]);
} else {
}
if (typeof arg0 === "string") {
// This is an identifier
const feature = State.state.allElements.ContainingFeatures.get(arg0);
if(feature === undefined){
return undefined;
}
arg0 = feature;
}
// arg0 is probably a feature
return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0), [feature._lon, feature._lat])
}
}
}
@ -82,8 +92,21 @@ Some advanced functions are available on <b>feat</b> as well:
(params, feature) => {
return (features) => {
if (typeof features === "string") {
const name = features
features = params.featuresPerLayer.get(features)
if (features === undefined) {
var keys = Utils.NoNull(Array.from(params.featuresPerLayer.keys()));
if (keys.length > 0) {
throw `No features defined for ${name}. Defined layers are ${keys.join(", ")}`;
} else {
// This is the first pass over an external dataset
// Other data probably still has to load!
return undefined;
}
}
}
let closestFeature = undefined;
let closestDistance = undefined;
for (const otherFeature of features) {
@ -128,9 +151,9 @@ Some advanced functions are available on <b>feat</b> as well:
private readonly _name: string;
private readonly _args: string[];
private readonly _doc: string;
private readonly _f: (params: {featuresPerLayer: Map<string, any[]>, relations: {role: string, relation: Relation}[]}, feat: any) => any;
private readonly _f: (params: { featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[] }, feat: any) => any;
constructor(name: string, doc: string, args: string[], f: ((params: {featuresPerLayer: Map<string, any[]>, relations: {role: string, relation: Relation}[]}, feat: any) => any)) {
constructor(name: string, doc: string, args: string[], f: ((params: { featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[] }, feat: any) => any)) {
this._name = name;
this._doc = doc;
this._args = args;
@ -138,7 +161,7 @@ Some advanced functions are available on <b>feat</b> as well:
}
public static FullPatchFeature(featuresPerLayer: Map<string, any[]>,relations: {role: string, relation: Relation}[], feature) {
public static FullPatchFeature(featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[], feature) {
for (const func of ExtraFunction.allFuncs) {
func.PatchFeature(featuresPerLayer, relations, feature);
}
@ -166,7 +189,7 @@ Some advanced functions are available on <b>feat</b> as well:
]);
}
public PatchFeature(featuresPerLayer: Map<string, any[]>, relations: {role: string, relation: Relation}[], feature: any) {
public PatchFeature(featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[], feature: any) {
feature[this._name] = this._f({featuresPerLayer: featuresPerLayer, relations: relations}, feature);
}

View file

@ -0,0 +1,12 @@
import FeatureSource from "./FeatureSource";
import {UIEventSource} from "../UIEventSource";
export default class DummyFeatureSource implements FeatureSource{
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
public readonly name: string = "Dummy (static) feature source";
constructor(features: UIEventSource<{ feature: any; freshness: Date }[]>) {
this.features = features;
}
}

View file

@ -35,7 +35,7 @@ export default class FeaturePipeline implements FeatureSource {
const amendedOverpassSource =
new RememberingSource(
new LocalStorageSaver(
new MetaTaggingFeatureSource(
new MetaTaggingFeatureSource(this,
new FeatureDuplicatorPerLayer(flayers,
new RegisteringFeatureSource(
updater)
@ -43,18 +43,24 @@ export default class FeaturePipeline implements FeatureSource {
const geojsonSources: FeatureSource [] = GeoJsonSource
.ConstructMultiSource(flayers.data, locationControl)
.map(geojsonSource => new RegisteringFeatureSource(new FeatureDuplicatorPerLayer(flayers, geojsonSource)));
.map(geojsonSource => {
let source = new RegisteringFeatureSource(new FeatureDuplicatorPerLayer(flayers, geojsonSource));
if(!geojsonSource.isOsmCache){
source = new MetaTaggingFeatureSource(this, source, updater.features);
}
return source
});
const amendedLocalStorageSource =
new RememberingSource(new RegisteringFeatureSource(new FeatureDuplicatorPerLayer(flayers, new LocalStorageSource(layout))
));
newPoints = new MetaTaggingFeatureSource(
newPoints = new MetaTaggingFeatureSource(this,
new FeatureDuplicatorPerLayer(flayers,
new RegisteringFeatureSource(newPoints)));
const amendedOsmApiSource = new RememberingSource(
new MetaTaggingFeatureSource(
new MetaTaggingFeatureSource(this,
new FeatureDuplicatorPerLayer(flayers,
new RegisteringFeatureSource(fromOsmApi))));

View file

@ -19,6 +19,7 @@ export default class GeoJsonSource implements FeatureSource {
private onFail: ((errorMsg: any, url: string) => void) = undefined;
private readonly layerId: string;
private readonly seenids: Set<string> = new Set<string>()
public readonly isOsmCache: boolean
private constructor(locationControl: UIEventSource<Loc>,
flayer: { isDisplayed: UIEventSource<boolean>, layerDef: LayerConfig },
@ -28,6 +29,8 @@ export default class GeoJsonSource implements FeatureSource {
this.name = "GeoJsonSource of " + url;
const zoomLevel = flayer.layerDef.source.geojsonZoomLevel;
this.isOsmCache = flayer.layerDef.source.isOsmCacheLayer;
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([])
if (zoomLevel === undefined) {

View file

@ -6,14 +6,16 @@ import MetaTagging from "../MetaTagging";
import ExtractRelations from "../Osm/ExtractRelations";
export default class MetaTaggingFeatureSource implements FeatureSource {
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{feature: any; freshness: Date}[]>(undefined);
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>(undefined);
public readonly name;
constructor(source: FeatureSource) {
constructor(allFeaturesSource: FeatureSource, source: FeatureSource, updateTrigger?: UIEventSource<any>) {
const self = this;
this.name = "MetaTagging of "+source.name
source.features.addCallbackAndRun((featuresFreshness: { feature: any, freshness: Date }[]) => {
this.name = "MetaTagging of " + source.name
function update() {
const featuresFreshness = source.features.data
if (featuresFreshness === undefined) {
return;
}
@ -25,9 +27,17 @@ export default class MetaTaggingFeatureSource implements FeatureSource {
}
})
MetaTagging.addMetatags(featuresFreshness, State.state.knownRelations.data, State.state.layoutToUse.data.layers);
MetaTagging.addMetatags(featuresFreshness,
allFeaturesSource,
State.state.knownRelations.data, State.state.layoutToUse.data.layers);
self.features.setData(featuresFreshness);
});
}
source.features.addCallbackAndRun(_ => update());
updateTrigger?.addCallback(_ => {
console.debug("Updating because of external call")
update();
})
}
}

View file

@ -2,6 +2,7 @@ import LayerConfig from "../Customizations/JSON/LayerConfig";
import SimpleMetaTagger from "./SimpleMetaTagger";
import {ExtraFunction} from "./ExtraFunction";
import {Relation} from "./Osm/ExtractRelations";
import FeatureSource from "./FeatureSource/FeatureSource";
interface Params {
@ -22,6 +23,7 @@ export default class MetaTagging {
* The features are a list of geojson-features, with a "properties"-field and geometry
*/
static addMetatags(features: { feature: any; freshness: Date }[],
allKnownFeatures: FeatureSource,
relations: Map<string, { role: string, relation: Relation }[]>,
layers: LayerConfig[],
includeDates = true) {
@ -55,7 +57,7 @@ export default class MetaTagging {
featuresPerLayer.get(key).push(feature.feature)
}
for (const feature of features) {
for (const feature of (allKnownFeatures.features?.data ?? features ?? [])) {
// @ts-ignore
const key = feature.feature._matching_layer_id;
const f = layerFuncs.get(key);

View file

@ -2,7 +2,7 @@ import { Utils } from "../Utils";
export default class Constants {
public static vNumber = "0.7.2c";
public static vNumber = "0.7.2d";
// The user journey states thresholds when a new feature gets unlocked
public static userJourney = {

View file

@ -0,0 +1,202 @@
{
"id": "defibrillator",
"name": {
"en": "Defibrillators",
"ca": "Desfibril·ladors",
"es": "Desfibriladores",
"fr": "Défibrillateurs",
"nl": "Defibrillatoren",
"de": "Defibrillatoren"
},
"source": {
"osmTags": "emergency=defibrillator"
},
"minzoom": 12,
"title": {
"render": {
"en": "Defibrillator",
"ca": "Desfibril·lador",
"es": "Desfibrilador",
"fr": "Défibrillateur",
"nl": "Defibrillator",
"de": "Defibrillator"
}
},
"icon": "./assets/themes/aed/aed.svg",
"color": "#0000ff",
"presets": [
{
"title": {
"en": "Defibrillator",
"ca": "Desfibril·lador",
"es": "Desfibrilador",
"fr": "Défibrillateur",
"nl": "Defibrillator",
"de": "Defibrillator"
},
"tags": [
"emergency=defibrillator"
]
}
],
"tagRenderings": [
"images",
{
"question": {
"en": "Is this defibrillator located indoors?",
"ca": "Està el desfibril·lador a l'interior?",
"es": "¿Esté el desfibrilador en interior?",
"fr": "Ce défibrillateur est-il disposé en intérieur ?",
"nl": "Hangt deze defibrillator binnen of buiten?",
"de": "Befindet sich dieser Defibrillator im Gebäude?"
},
"mappings": [
{
"if": "indoor=yes",
"then": {
"en": "This defibrillator is located indoors",
"ca": "Aquest desfibril·lador està a l'interior",
"es": "Este desfibrilador está en interior",
"fr": "Ce défibrillateur est en intérieur (dans un batiment)",
"nl": "Deze defibrillator bevindt zich in een gebouw",
"de": "Dieser Defibrillator befindet sich im Gebäude"
}
},
{
"if": "indoor=no",
"then": {
"en": "This defibrillator is located outdoors",
"ca": "Aquest desfibril·lador està a l'exterior",
"es": "Este desfibrilador está en exterior",
"fr": "Ce défibrillateur est situé en extérieur",
"nl": "Deze defibrillator hangt buiten",
"de": "Dieser Defibrillator befindet sich im Freien"
}
}
]
},
{
"question": {
"en": "Is this defibrillator freely accessible?",
"ca": "Està el desfibril·lador accessible lliurement?",
"es": "¿Está el desfibrilador accesible libremente?",
"fr": "Ce défibrillateur est-il librement accessible ?",
"nl": "Is deze defibrillator vrij toegankelijk?",
"de": "Ist dieser Defibrillator frei zugänglich?"
},
"render": {
"en": "Access is {access}",
"ca": "L'accés és {access}",
"es": "El acceso es {access}",
"fr": "{access} accessible",
"nl": "Toegankelijkheid is {access}",
"de": "Zugang ist {access}"
},
"condition": {
"or": [
"indoor=yes",
"access~*"
]
},
"freeform": {
"key": "access",
"addExtraTags": [
"fixme=Freeform field used for access - doublecheck the value"
]
},
"mappings": [
{
"if": "access=yes",
"then": {
"en": "Publicly accessible",
"ca": "Accés lliure",
"es": "Acceso libre",
"fr": "Librement accessible",
"nl": "Publiek toegankelijk",
"de": "Öffentlich zugänglich"
}
},
{
"if": "access=public",
"then": {
"en": "Publicly accessible",
"ca": "Publicament accessible",
"es": "Publicament accesible",
"fr": "Librement accessible",
"nl": "Publiek toegankelijk",
"de": "Öffentlich zugänglich"
},
"hideInAnswer": true
},
{
"if": "access=customers",
"then": {
"en": "Only accessible to customers",
"ca": "Només accessible a clients",
"es": "Sólo accesible a clientes",
"fr": "Réservé aux clients du lieu",
"nl": "Enkel toegankelijk voor klanten",
"de": "Nur für Kunden zugänglich"
}
},
{
"if": "access=private",
"then": {
"en": "Not accessible to the general public (e.g. only accesible to staff, the owners, ...)",
"ca": "No accessible al públic en general (ex. només accesible a treballadors, propietaris, ...)",
"es": "No accesible al público en general (ex. sólo accesible a trabajadores, propietarios, ...)",
"fr": "Non accessible au public (par exemple réservé au personnel, au propriétaire, ...)",
"nl": "Niet toegankelijk voor het publiek (bv. enkel voor personneel, de eigenaar, ...)",
"de": "Nicht für die Öffentlichkeit zugänglich (z.B. nur für das Personal, die Eigentümer, ...)"
}
}
]
},
{
"question": {
"en": "On which floor is this defibrillator located?",
"ca": "A quina planta està el desfibril·lador localitzat?",
"es": "¿En qué planta se encuentra el defibrilador localizado?",
"fr": "À quel étage est situé ce défibrillateur ?",
"nl": "Op welke verdieping bevindt deze defibrillator zich?",
"de": "In welchem Stockwerk befindet sich dieser Defibrillator?"
},
"condition": {
"and": [
"indoor=yes",
"access!~private"
]
},
"freeform": {
"key": "level",
"type": "int"
},
"render": {
"en": "This defibrallator is on floor {level}",
"ca": "Aquest desfibril·lador és a la planta {level}",
"es": "El desfibrilador se encuentra en la planta {level}",
"fr": "Ce défibrillateur est à l'étage {level}",
"nl": "De defibrillator bevindt zicht op verdieping {level}",
"de": "Dieser Defibrallator befindet sich im {level}. Stockwerk"
}
},
{
"render": {
"nl": "<i>Meer informatie over de locatie:</i><br/>{defibrillator:location}",
"en": "<i>Extra information about the location:</i><br/>{defibrillator:location}"
},
"question": {
"en": "Please give some explanation on where the defibrillator can be found",
"ca": "Dóna detalls d'on es pot trobar el desfibril·lador",
"es": "Da detalles de dónde se puede encontrar el desfibrilador",
"fr": "Veuillez indiquez plus précisément où se situe le défibrillateur",
"nl": "Gelieve meer informatie te geven over de exacte locatie van de defibrillator",
"de": "Bitte geben Sie einige Erläuterungen dazu, wo der Defibrillator zu finden ist"
},
"freeform": {
"type": "text",
"key": "defibrillator:location"
}
}
]
}

View file

@ -82,5 +82,9 @@
"#": "Gives some metainfo about the last edit and who did edit it - rendering only",
"condition": "_last_edit:contributor~*",
"render": "<div class='subtle' style='font-size: small; margin-top: 2em; margin-bottom: 0.5em;'><a href='https://www.openStreetMap.org/changeset/{_last_edit:changeset}' target='_blank'>Last edited on {_last_edit:timestamp}</a> by <a href='https://www.openStreetMap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a></div>"
},
"all_tags": {
"#": "Prints all the tags",
"render": "{all_tags()}"
}
}

View file

@ -31,207 +31,6 @@
"startLon": 0,
"startZoom": 12,
"layers": [
{
"id": "Defibrillator",
"name": {
"en": "Defibrillators",
"ca": "Desfibril·ladors",
"es": "Desfibriladores",
"fr": "Défibrillateurs",
"nl": "Defibrillatoren",
"de": "Defibrillatoren"
},
"source": {
"osmTags": "emergency=defibrillator"
},
"minzoom": 12,
"title": {
"render": {
"en": "Defibrillator",
"ca": "Desfibril·lador",
"es": "Desfibrilador",
"fr": "Défibrillateur",
"nl": "Defibrillator",
"de": "Defibrillator"
}
},
"icon": "./assets/themes/aed/aed.svg",
"color": "#0000ff",
"presets": [
{
"title": {
"en": "Defibrillator",
"ca": "Desfibril·lador",
"es": "Desfibrilador",
"fr": "Défibrillateur",
"nl": "Defibrillator",
"de": "Defibrillator"
},
"tags": [
"emergency=defibrillator"
]
}
],
"tagRenderings": [
"images",
{
"question": {
"en": "Is this defibrillator located indoors?",
"ca": "Està el desfibril·lador a l'interior?",
"es": "¿Esté el desfibrilador en interior?",
"fr": "Ce défibrillateur est-il disposé en intérieur ?",
"nl": "Hangt deze defibrillator binnen of buiten?",
"de": "Befindet sich dieser Defibrillator im Gebäude?"
},
"mappings": [
{
"if": "indoor=yes",
"then": {
"en": "This defibrillator is located indoors",
"ca": "Aquest desfibril·lador està a l'interior",
"es": "Este desfibrilador está en interior",
"fr": "Ce défibrillateur est en intérieur (dans un batiment)",
"nl": "Deze defibrillator bevindt zich in een gebouw",
"de": "Dieser Defibrillator befindet sich im Gebäude"
}
},
{
"if": "indoor=no",
"then": {
"en": "This defibrillator is located outdoors",
"ca": "Aquest desfibril·lador està a l'exterior",
"es": "Este desfibrilador está en exterior",
"fr": "Ce défibrillateur est situé en extérieur",
"nl": "Deze defibrillator hangt buiten",
"de": "Dieser Defibrillator befindet sich im Freien"
}
}
]
},
{
"question": {
"en": "Is this defibrillator freely accessible?",
"ca": "Està el desfibril·lador accessible lliurement?",
"es": "¿Está el desfibrilador accesible libremente?",
"fr": "Ce défibrillateur est-il librement accessible ?",
"nl": "Is deze defibrillator vrij toegankelijk?",
"de": "Ist dieser Defibrillator frei zugänglich?"
},
"render": {
"en": "Access is {access}",
"ca": "L'accés és {access}",
"es": "El acceso es {access}",
"fr": "{access} accessible",
"nl": "Toegankelijkheid is {access}",
"de": "Zugang ist {access}"
},
"condition": {
"or": [
"indoor=yes",
"access~*"
]
},
"freeform": {
"key": "access",
"addExtraTags": [
"fixme=Freeform field used for access - doublecheck the value"
]
},
"mappings": [
{
"if": "access=yes",
"then": {
"en": "Publicly accessible",
"ca": "Accés lliure",
"es": "Acceso libre",
"fr": "Librement accessible",
"nl": "Publiek toegankelijk",
"de": "Öffentlich zugänglich"
}
},
{
"if": "access=public",
"then": {
"en": "Publicly accessible",
"ca": "Publicament accessible",
"es": "Publicament accesible",
"fr": "Librement accessible",
"nl": "Publiek toegankelijk",
"de": "Öffentlich zugänglich"
},
"hideInAnswer": true
},
{
"if": "access=customers",
"then": {
"en": "Only accessible to customers",
"ca": "Només accessible a clients",
"es": "Sólo accesible a clientes",
"fr": "Réservé aux clients du lieu",
"nl": "Enkel toegankelijk voor klanten",
"de": "Nur für Kunden zugänglich"
}
},
{
"if": "access=private",
"then": {
"en": "Not accessible to the general public (e.g. only accesible to staff, the owners, ...)",
"ca": "No accessible al públic en general (ex. només accesible a treballadors, propietaris, ...)",
"es": "No accesible al público en general (ex. sólo accesible a trabajadores, propietarios, ...)",
"fr": "Non accessible au public (par exemple réservé au personnel, au propriétaire, ...)",
"nl": "Niet toegankelijk voor het publiek (bv. enkel voor personneel, de eigenaar, ...)",
"de": "Nicht für die Öffentlichkeit zugänglich (z.B. nur für das Personal, die Eigentümer, ...)"
}
}
]
},
{
"question": {
"en": "On which floor is this defibrillator located?",
"ca": "A quina planta està el desfibril·lador localitzat?",
"es": "¿En qué planta se encuentra el defibrilador localizado?",
"fr": "À quel étage est situé ce défibrillateur ?",
"nl": "Op welke verdieping bevindt deze defibrillator zich?",
"de": "In welchem Stockwerk befindet sich dieser Defibrillator?"
},
"condition": {
"and": [
"indoor=yes",
"access!~private"
]
},
"freeform": {
"key": "level",
"type": "int"
},
"render": {
"en": "This defibrallator is on floor {level}",
"ca": "Aquest desfibril·lador és a la planta {level}",
"es": "El desfibrilador se encuentra en la planta {level}",
"fr": "Ce défibrillateur est à l'étage {level}",
"nl": "De defibrillator bevindt zicht op verdieping {level}",
"de": "Dieser Defibrallator befindet sich im {level}. Stockwerk"
}
},
{
"render": {
"nl": "<i>Meer informatie over de locatie:</i><br/>{defibrillator:location}",
"en": "<i>Extra information about the location:</i><br/>{defibrillator:location}"
},
"question": {
"en": "Please give some explanation on where the defibrillator can be found",
"ca": "Dóna detalls d'on es pot trobar el desfibril·lador",
"es": "Da detalles de dónde se puede encontrar el desfibrilador",
"fr": "Veuillez indiquez plus précisément où se situe le défibrillateur",
"nl": "Gelieve meer informatie te geven over de exacte locatie van de defibrillator",
"de": "Bitte geben Sie einige Erläuterungen dazu, wo der Defibrillator zu finden ist"
},
"freeform": {
"type": "text",
"key": "defibrillator:location"
}
}
]
}
"defibrillator"
]
}

View file

@ -0,0 +1,53 @@
{
"id": "aed_brugge",
"title": {
"nl": "Open AED-kaart - Brugge edition"
},
"maintainer": "MapComplete",
"icon": "./assets/themes/aed/logo.svg",
"description": {
"nl": "Op deze kaart kan je informatie over AEDs vinden en verbeteren + een export van de brugse defibrillatoren"
},
"language": [
"nl"
],
"version": "2021-05-16",
"startLat": 51.25634,
"startLon": 3.195682,
"startZoom": 12,
"layers": [
"defibrillator",
{
"id": "Brugge",
"name": "Brugse dataset",
"source": {
"osmTags": "Brugs volgnummer~*",
"geoJson": "https://raw.githubusercontent.com/pietervdvn/pietervdvn.github.io/master/aeds_brugge.json"
},
"calculatedTags": [
"_closest_osm_aed=feat.closest('defibrillator')?.properties?.id",
"_closest_osm_aed_distance=feat.distanceTo(feat.properties._closest_osm_aed) * 1000",
"_has_closeby_feature=Number(feat.properties._closest_osm_aed_distance) < 25 ? 'yes' : 'no'"
],
"title": "AED in Brugse dataset",
"icon": {
"render": "circle:green",
"mappings": [
{
"if": "_has_closeby_feature=yes",
"then": "circle:#ffff00aa"
},
{
"if": "Status=oud",
"then": "circle:red"
}
]
},
"iconSize": "20,20,center",
"tagRenderings": [
"all_tags"
]
}
],
"hideFromOverview": true
}

View file

@ -17,6 +17,8 @@ import MetaTagging from "../Logic/MetaTagging";
import LayerConfig from "../Customizations/JSON/LayerConfig";
import {GeoOperations} from "../Logic/GeoOperations";
import {fail} from "assert";
import {UIEventSource} from "../Logic/UIEventSource";
import DummyFeatureSource from "../Logic/FeatureSource/DummyFeatureSource";
function createOverpassObject(theme: LayoutConfig) {
@ -167,7 +169,7 @@ async function postProcess(targetdir: string, r: TileRange, theme: LayoutConfig,
// Extract the relationship information
const relations = ExtractRelations.BuildMembershipTable(ExtractRelations.GetRelationElements(rawOsm))
MetaTagging.addMetatags(featuresFreshness, relations, theme.layers, false);
MetaTagging.addMetatags(featuresFreshness, new DummyFeatureSource(new UIEventSource<{feature: any; freshness: Date}[]>(featuresFreshness)) , relations, theme.layers, false);
for (const feature of geojson.features) {