diff --git a/Customizations/JSON/LayerConfig.ts b/Customizations/JSON/LayerConfig.ts index f94ed2fa17..fb63d3951e 100644 --- a/Customizations/JSON/LayerConfig.ts +++ b/Customizations/JSON/LayerConfig.ts @@ -81,7 +81,10 @@ 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, geojsonSource: json.source["geoJson"], @@ -107,7 +110,7 @@ export default class LayerConfig { const index = kv.indexOf("=") const key = kv.substring(0, index); const code = kv.substring(index + 1); - + this.calculatedTags.push([key, code]) } } @@ -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}]`); }); diff --git a/Logic/ElementStorage.ts b/Logic/ElementStorage.ts index a37813d518..9b569ed92b 100644 --- a/Logic/ElementStorage.ts +++ b/Logic/ElementStorage.ts @@ -6,6 +6,7 @@ import {UIEventSource} from "./UIEventSource"; export class ElementStorage { private _elements = new Map>(); + public ContainingFeatures = new Map(); constructor() { @@ -24,11 +25,16 @@ export class ElementStorage { addOrGetElement(feature: any): UIEventSource { const elementId = feature.properties.id; const newProperties = feature.properties; - + const es = this.addOrGetById(elementId, newProperties) // 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; } diff --git a/Logic/ExtraFunction.ts b/Logic/ExtraFunction.ts index 59c8e909ce..e53f34bda9 100644 --- a/Logic/ExtraFunction.ts +++ b/Logic/ExtraFunction.ts @@ -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 feat 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 { - // arg0 is probably a feature - return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0), [feature._lon, feature._lat]) } + 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 feat 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) { @@ -120,7 +143,7 @@ Some advanced functions are available on feat as well: "For example: _part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')", [], (params, _) => { - return () => params.relations ?? []; + return () => params.relations ?? []; } ) @@ -128,9 +151,9 @@ Some advanced functions are available on feat as well: private readonly _name: string; private readonly _args: string[]; private readonly _doc: string; - private readonly _f: (params: {featuresPerLayer: Map, relations: {role: string, relation: Relation}[]}, feat: any) => any; + private readonly _f: (params: { featuresPerLayer: Map, relations: { role: string, relation: Relation }[] }, feat: any) => any; - constructor(name: string, doc: string, args: string[], f: ((params: {featuresPerLayer: Map, relations: {role: string, relation: Relation}[]}, feat: any) => any)) { + constructor(name: string, doc: string, args: string[], f: ((params: { featuresPerLayer: Map, 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 feat as well: } - public static FullPatchFeature(featuresPerLayer: Map,relations: {role: string, relation: Relation}[], feature) { + public static FullPatchFeature(featuresPerLayer: Map, relations: { role: string, relation: Relation }[], feature) { for (const func of ExtraFunction.allFuncs) { func.PatchFeature(featuresPerLayer, relations, feature); } @@ -166,8 +189,8 @@ Some advanced functions are available on feat as well: ]); } - public PatchFeature(featuresPerLayer: Map, relations: {role: string, relation: Relation}[], feature: any) { - + public PatchFeature(featuresPerLayer: Map, relations: { role: string, relation: Relation }[], feature: any) { + feature[this._name] = this._f({featuresPerLayer: featuresPerLayer, relations: relations}, feature); } } diff --git a/Logic/FeatureSource/DummyFeatureSource.ts b/Logic/FeatureSource/DummyFeatureSource.ts new file mode 100644 index 0000000000..298f9e2c23 --- /dev/null +++ b/Logic/FeatureSource/DummyFeatureSource.ts @@ -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; + } + +} \ No newline at end of file diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index ba78907870..0878975f34 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -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)))); diff --git a/Logic/FeatureSource/GeoJsonSource.ts b/Logic/FeatureSource/GeoJsonSource.ts index beff2c801c..4e32f2bc36 100644 --- a/Logic/FeatureSource/GeoJsonSource.ts +++ b/Logic/FeatureSource/GeoJsonSource.ts @@ -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 = new Set() + public readonly isOsmCache: boolean private constructor(locationControl: UIEventSource, flayer: { isDisplayed: UIEventSource, layerDef: LayerConfig }, @@ -27,6 +28,8 @@ export default class GeoJsonSource implements FeatureSource { let url = flayer.layerDef.source.geojsonSource.replace("{layer}", flayer.layerDef.id); 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 }[]>([]) diff --git a/Logic/FeatureSource/MetaTaggingFeatureSource.ts b/Logic/FeatureSource/MetaTaggingFeatureSource.ts index 5beefa9339..e269977ab3 100644 --- a/Logic/FeatureSource/MetaTaggingFeatureSource.ts +++ b/Logic/FeatureSource/MetaTaggingFeatureSource.ts @@ -6,28 +6,38 @@ 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 name; - - constructor(source: FeatureSource) { - const self = this; - this.name = "MetaTagging of "+source.name - source.features.addCallbackAndRun((featuresFreshness: { feature: any, freshness: Date }[]) => { - if (featuresFreshness === undefined) { - return; - } - featuresFreshness.forEach(featureFresh => { - const feature = featureFresh.feature; - - if (Hash.hash.data === feature.properties.id) { - State.state.selectedElement.setData(feature); - } - }) + public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>(undefined); - MetaTagging.addMetatags(featuresFreshness, State.state.knownRelations.data, State.state.layoutToUse.data.layers); - self.features.setData(featuresFreshness); - }); + public readonly name; + + constructor(allFeaturesSource: FeatureSource, source: FeatureSource, updateTrigger?: UIEventSource) { + const self = this; + this.name = "MetaTagging of " + source.name + + function update() { + const featuresFreshness = source.features.data + if (featuresFreshness === undefined) { + return; + } + featuresFreshness.forEach(featureFresh => { + const feature = featureFresh.feature; + + if (Hash.hash.data === feature.properties.id) { + State.state.selectedElement.setData(feature); + } + }) + + 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(); + }) } - + } \ No newline at end of file diff --git a/Logic/MetaTagging.ts b/Logic/MetaTagging.ts index df4076ef45..659118f3c6 100644 --- a/Logic/MetaTagging.ts +++ b/Logic/MetaTagging.ts @@ -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, 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); diff --git a/Models/Constants.ts b/Models/Constants.ts index 82df83bd80..9191a0e95b 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -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 = { diff --git a/assets/layers/defibrillator/defibrillator.json b/assets/layers/defibrillator/defibrillator.json new file mode 100644 index 0000000000..50cbdf03b6 --- /dev/null +++ b/assets/layers/defibrillator/defibrillator.json @@ -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": "Meer informatie over de locatie:
{defibrillator:location}", + "en": "Extra information about the location:
{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" + } + } + ] +} \ No newline at end of file diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index a7fd654509..2e5ad956c6 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -82,5 +82,9 @@ "#": "Gives some metainfo about the last edit and who did edit it - rendering only", "condition": "_last_edit:contributor~*", "render": "" + }, + "all_tags": { + "#": "Prints all the tags", + "render": "{all_tags()}" } } \ No newline at end of file diff --git a/assets/themes/aed/aed.json b/assets/themes/aed/aed.json index 9a64c8f837..bc63c68d13 100644 --- a/assets/themes/aed/aed.json +++ b/assets/themes/aed/aed.json @@ -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": "Meer informatie over de locatie:
{defibrillator:location}", - "en": "Extra information about the location:
{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" ] } diff --git a/assets/themes/aed/aed_brugge.json b/assets/themes/aed/aed_brugge.json new file mode 100644 index 0000000000..65276b4f4f --- /dev/null +++ b/assets/themes/aed/aed_brugge.json @@ -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 +} diff --git a/scripts/generateCache.ts b/scripts/generateCache.ts index 7d862858d1..8a91d709ac 100644 --- a/scripts/generateCache.ts +++ b/scripts/generateCache.ts @@ -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) { @@ -142,7 +144,7 @@ async function postProcess(targetdir: string, r: TileRange, theme: LayoutConfig, // We read the raw OSM-file and convert it to a geojson const rawOsm = JSON.parse(readFileSync(filename, "UTF8")) - + // Create and save the geojson file - which is the main chunk of the data const geojson = OsmToGeoJson.default(rawOsm); const osmTime = new Date(rawOsm.osm3s.timestamp_osm_base); @@ -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) {