forked from MapComplete/MapComplete
		
	Reformat all files with prettier
This commit is contained in:
		
							parent
							
								
									e22d189376
								
							
						
					
					
						commit
						b541d3eab4
					
				
					 382 changed files with 50893 additions and 35566 deletions
				
			
		|  | @ -1,11 +1,11 @@ | |||
| import {GeoOperations} from "./GeoOperations"; | ||||
| import Combine from "../UI/Base/Combine"; | ||||
| import RelationsTracker from "./Osm/RelationsTracker"; | ||||
| import BaseUIElement from "../UI/BaseUIElement"; | ||||
| import List from "../UI/Base/List"; | ||||
| import Title from "../UI/Base/Title"; | ||||
| import {BBox} from "./BBox"; | ||||
| import {Feature, Geometry, MultiPolygon, Polygon} from "@turf/turf"; | ||||
| import { GeoOperations } from "./GeoOperations" | ||||
| import Combine from "../UI/Base/Combine" | ||||
| import RelationsTracker from "./Osm/RelationsTracker" | ||||
| import BaseUIElement from "../UI/BaseUIElement" | ||||
| import List from "../UI/Base/List" | ||||
| import Title from "../UI/Base/Title" | ||||
| import { BBox } from "./BBox" | ||||
| import { Feature, Geometry, MultiPolygon, Polygon } from "@turf/turf" | ||||
| 
 | ||||
| export interface ExtraFuncParams { | ||||
|     /** | ||||
|  | @ -13,7 +13,7 @@ export interface ExtraFuncParams { | |||
|      * Note that more features then requested can be given back. | ||||
|      * Format: [ [ geojson, geojson, geojson, ... ], [geojson, ...], ...] | ||||
|      */ | ||||
|     getFeaturesWithin: (layerId: string, bbox: BBox) => Feature<Geometry, { id: string }>[][], | ||||
|     getFeaturesWithin: (layerId: string, bbox: BBox) => Feature<Geometry, { id: string }>[][] | ||||
|     memberships: RelationsTracker | ||||
|     getFeatureById: (id: string) => Feature<Geometry, { id: string }> | ||||
| } | ||||
|  | @ -22,19 +22,23 @@ export interface ExtraFuncParams { | |||
|  * Describes a function that is added to a geojson object in order to calculate calculated tags | ||||
|  */ | ||||
| interface ExtraFunction { | ||||
|     readonly _name: string; | ||||
|     readonly _args: string[]; | ||||
|     readonly _doc: string; | ||||
|     readonly _f: (params: ExtraFuncParams, feat: Feature<Geometry, any>) => any; | ||||
| 
 | ||||
|     readonly _name: string | ||||
|     readonly _args: string[] | ||||
|     readonly _doc: string | ||||
|     readonly _f: (params: ExtraFuncParams, feat: Feature<Geometry, any>) => any | ||||
| } | ||||
| 
 | ||||
| class EnclosingFunc implements ExtraFunction { | ||||
|     _name = "enclosingFeatures" | ||||
|     _doc = ["Gives a list of all features in the specified layers which fully contain this object. Returned features will always be (multi)polygons. (LineStrings and Points from the other layers are ignored)", "", | ||||
|     _doc = [ | ||||
|         "Gives a list of all features in the specified layers which fully contain this object. Returned features will always be (multi)polygons. (LineStrings and Points from the other layers are ignored)", | ||||
|         "", | ||||
|         "The result is a list of features: `{feat: Polygon}[]`", | ||||
|         "This function will never return the feature itself."].join("\n") | ||||
|     _args = ["...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)"] | ||||
|         "This function will never return the feature itself.", | ||||
|     ].join("\n") | ||||
|     _args = [ | ||||
|         "...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)", | ||||
|     ] | ||||
| 
 | ||||
|     _f(params: ExtraFuncParams, feat: Feature<Geometry, any>) { | ||||
|         return (...layerIds: string[]) => { | ||||
|  | @ -45,10 +49,10 @@ class EnclosingFunc implements ExtraFunction { | |||
|             for (const layerId of layerIds) { | ||||
|                 const otherFeaturess = params.getFeaturesWithin(layerId, bbox) | ||||
|                 if (otherFeaturess === undefined) { | ||||
|                     continue; | ||||
|                     continue | ||||
|                 } | ||||
|                 if (otherFeaturess.length === 0) { | ||||
|                     continue; | ||||
|                     continue | ||||
|                 } | ||||
|                 for (const otherFeatures of otherFeaturess) { | ||||
|                     for (const otherFeature of otherFeatures) { | ||||
|  | @ -56,26 +60,33 @@ class EnclosingFunc implements ExtraFunction { | |||
|                             continue | ||||
|                         } | ||||
|                         seenIds.add(otherFeature.properties.id) | ||||
|                         if (otherFeature.geometry.type !== "Polygon" && otherFeature.geometry.type !== "MultiPolygon") { | ||||
|                             continue; | ||||
|                         if ( | ||||
|                             otherFeature.geometry.type !== "Polygon" && | ||||
|                             otherFeature.geometry.type !== "MultiPolygon" | ||||
|                         ) { | ||||
|                             continue | ||||
|                         } | ||||
|                         if (GeoOperations.completelyWithin(feat, <Feature<Polygon | MultiPolygon, any>>otherFeature)) { | ||||
|                             result.push({feat: otherFeature}) | ||||
|                         if ( | ||||
|                             GeoOperations.completelyWithin( | ||||
|                                 feat, | ||||
|                                 <Feature<Polygon | MultiPolygon, any>>otherFeature | ||||
|                             ) | ||||
|                         ) { | ||||
|                             result.push({ feat: otherFeature }) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return result; | ||||
|             return result | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| class OverlapFunc implements ExtraFunction { | ||||
| 
 | ||||
| 
 | ||||
|     _name = "overlapWith"; | ||||
|     _doc = ["Gives a list of features from the specified layer which this feature (partly) overlaps with. A point which is embedded in the feature is detected as well.", | ||||
|     _name = "overlapWith" | ||||
|     _doc = [ | ||||
|         "Gives a list of features from the specified layer which this feature (partly) overlaps with. A point which is embedded in the feature is detected as well.", | ||||
|         "If the current feature is a point, all features that this point is embeded in are given.", | ||||
|         "", | ||||
|         "The returned value is `{ feat: GeoJSONFeature, overlap: number}[]` where `overlap` is the overlapping surface are (in m²) for areas, the overlapping length (in meter) if the current feature is a line or `undefined` if the current feature is a point.", | ||||
|  | @ -83,27 +94,29 @@ class OverlapFunc implements ExtraFunction { | |||
|         "", | ||||
|         "For example to get all objects which overlap or embed from a layer, use `_contained_climbing_routes_properties=feat.overlapWith('climbing_route')`", | ||||
|         "", | ||||
|         "Also see [enclosingFeatures](#enclosingFeatures) which can be used to get all objects which fully contain this feature" | ||||
|         "Also see [enclosingFeatures](#enclosingFeatures) which can be used to get all objects which fully contain this feature", | ||||
|     ].join("\n") | ||||
|     _args = ["...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)"] | ||||
|     _args = [ | ||||
|         "...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)", | ||||
|     ] | ||||
| 
 | ||||
|     _f(params, feat) { | ||||
|         return (...layerIds: string[]) => { | ||||
|             const result: { feat: any, overlap: number }[] = [] | ||||
|             const result: { feat: any; overlap: number }[] = [] | ||||
|             const seenIds = new Set<string>() | ||||
|             const bbox = BBox.get(feat) | ||||
|             for (const layerId of layerIds) { | ||||
|                 const otherFeaturess = params.getFeaturesWithin(layerId, bbox) | ||||
|                 if (otherFeaturess === undefined) { | ||||
|                     continue; | ||||
|                     continue | ||||
|                 } | ||||
|                 if (otherFeaturess.length === 0) { | ||||
|                     continue; | ||||
|                     continue | ||||
|                 } | ||||
|                 for (const otherFeatures of otherFeaturess) { | ||||
|                     const overlap = GeoOperations.calculateOverlap(feat, otherFeatures) | ||||
|                     for (const overlappingFeature of overlap) { | ||||
|                         if(seenIds.has(overlappingFeature.feat.properties.id)){ | ||||
|                         if (seenIds.has(overlappingFeature.feat.properties.id)) { | ||||
|                             continue | ||||
|                         } | ||||
|                         seenIds.add(overlappingFeature.feat.properties.id) | ||||
|  | @ -113,105 +126,113 @@ class OverlapFunc implements ExtraFunction { | |||
|             } | ||||
| 
 | ||||
|             result.sort((a, b) => b.overlap - a.overlap) | ||||
|             return result; | ||||
|             return result | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class IntersectionFunc implements ExtraFunction { | ||||
| 
 | ||||
| 
 | ||||
|     _name = "intersectionsWith"; | ||||
|     _doc = "Gives the intersection points with selected features. Only works with (Multi)Polygons and LineStrings.\n\n" + | ||||
|     _name = "intersectionsWith" | ||||
|     _doc = | ||||
|         "Gives the intersection points with selected features. Only works with (Multi)Polygons and LineStrings.\n\n" + | ||||
|         "Returns a `{feat: GeoJson, intersections: [number,number][]}` where `feat` is the full, original feature. This list is in random order.\n\n" + | ||||
|         "If the current feature is a point, this function will return an empty list.\n" + | ||||
|         "Points from other layers are ignored - even if the points are parts of the current linestring." | ||||
|     _args = ["...layerIds - one or more layer ids of the layer from which every feature is checked for intersection)"] | ||||
|     _args = [ | ||||
|         "...layerIds - one or more layer ids of the layer from which every feature is checked for intersection)", | ||||
|     ] | ||||
| 
 | ||||
|     _f(params: ExtraFuncParams, feat) { | ||||
|         return (...layerIds: string[]) => { | ||||
|             const result: { feat: any, intersections: [number, number][] }[] = [] | ||||
|             const result: { feat: any; intersections: [number, number][] }[] = [] | ||||
| 
 | ||||
|             const bbox = BBox.get(feat) | ||||
| 
 | ||||
|             for (const layerId of layerIds) { | ||||
|                 const otherLayers = params.getFeaturesWithin(layerId, bbox) | ||||
|                 if (otherLayers === undefined) { | ||||
|                     continue; | ||||
|                     continue | ||||
|                 } | ||||
|                 if (otherLayers.length === 0) { | ||||
|                     continue; | ||||
|                     continue | ||||
|                 } | ||||
|                 for (const tile of otherLayers) { | ||||
|                     for (const otherFeature of tile) { | ||||
| 
 | ||||
|                         const intersections = GeoOperations.LineIntersections(feat, otherFeature) | ||||
|                         if (intersections.length === 0) { | ||||
|                             continue | ||||
|                         } | ||||
|                         result.push({feat: otherFeature, intersections}) | ||||
|                         result.push({ feat: otherFeature, intersections }) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return result; | ||||
|             return result | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class DistanceToFunc implements ExtraFunction { | ||||
| 
 | ||||
|     _name = "distanceTo"; | ||||
|     _doc = "Calculates the distance between the feature and a specified point in meter. The input should either be a pair of coordinates, a geojson feature or the ID of an object"; | ||||
|     _name = "distanceTo" | ||||
|     _doc = | ||||
|         "Calculates the distance between the feature and a specified point in meter. The input should either be a pair of coordinates, a geojson feature or the ID of an object" | ||||
|     _args = ["feature OR featureID OR longitude", "undefined OR latitude"] | ||||
| 
 | ||||
|     _f(featuresPerLayer, feature) { | ||||
|         return (arg0, lat) => { | ||||
|             if (arg0 === undefined) { | ||||
|                 return undefined; | ||||
|                 return undefined | ||||
|             } | ||||
|             if (typeof arg0 === "number") { | ||||
|                 // Feature._lon and ._lat is conveniently place by one of the other metatags
 | ||||
|                 return GeoOperations.distanceBetween([arg0, lat], GeoOperations.centerpointCoordinates(feature)); | ||||
|                 return GeoOperations.distanceBetween( | ||||
|                     [arg0, lat], | ||||
|                     GeoOperations.centerpointCoordinates(feature) | ||||
|                 ) | ||||
|             } | ||||
|             if (typeof arg0 === "string") { | ||||
|                 // This is an identifier
 | ||||
|                 const feature = featuresPerLayer.getFeatureById(arg0) | ||||
|                 if (feature === undefined) { | ||||
|                     return undefined; | ||||
|                     return undefined | ||||
|                 } | ||||
|                 arg0 = feature; | ||||
|                 arg0 = feature | ||||
|             } | ||||
| 
 | ||||
|             // arg0 is probably a geojsonfeature
 | ||||
|             return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0), GeoOperations.centerpointCoordinates(feature)) | ||||
| 
 | ||||
|             return GeoOperations.distanceBetween( | ||||
|                 GeoOperations.centerpointCoordinates(arg0), | ||||
|                 GeoOperations.centerpointCoordinates(feature) | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class ClosestObjectFunc implements ExtraFunction { | ||||
|     _name = "closest" | ||||
|     _doc = "Given either a list of geojson features or a single layer name, gives the single object which is nearest to the feature. In the case of ways/polygons, only the centerpoint is considered. Returns a single geojson feature or undefined if nothing is found (or not yet loaded)" | ||||
|     _doc = | ||||
|         "Given either a list of geojson features or a single layer name, gives the single object which is nearest to the feature. In the case of ways/polygons, only the centerpoint is considered. Returns a single geojson feature or undefined if nothing is found (or not yet loaded)" | ||||
| 
 | ||||
|     _args = ["list of features or a layer name or '*' to get all features"] | ||||
| 
 | ||||
|     _f(params, feature) { | ||||
|         return (features) => ClosestNObjectFunc.GetClosestNFeatures(params, feature, features)?.[0]?.feat | ||||
|         return (features) => | ||||
|             ClosestNObjectFunc.GetClosestNFeatures(params, feature, features)?.[0]?.feat | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class ClosestNObjectFunc implements ExtraFunction { | ||||
|     _name = "closestn" | ||||
|     _doc = "Given either a list of geojson features or a single layer name, gives the n closest objects which are nearest to the feature (excluding the feature itself). In the case of ways/polygons, only the centerpoint is considered. " + | ||||
|     _doc = | ||||
|         "Given either a list of geojson features or a single layer name, gives the n closest objects which are nearest to the feature (excluding the feature itself). In the case of ways/polygons, only the centerpoint is considered. " + | ||||
|         "Returns a list of `{feat: geojson, distance:number}` the empty list if nothing is found (or not yet loaded)\n\n" + | ||||
|         "If a 'unique tag key' is given, the tag with this key will only appear once (e.g. if 'name' is given, all features will have a different name)" | ||||
|     _args = ["list of features or layer name or '*' to get all features", "amount of features", "unique tag key (optional)", "maxDistanceInMeters (optional)"] | ||||
|     _args = [ | ||||
|         "list of features or layer name or '*' to get all features", | ||||
|         "amount of features", | ||||
|         "unique tag key (optional)", | ||||
|         "maxDistanceInMeters (optional)", | ||||
|     ] | ||||
| 
 | ||||
|     /** | ||||
|      * Gets the closes N features, sorted by ascending distance. | ||||
|  | @ -223,45 +244,61 @@ class ClosestNObjectFunc implements ExtraFunction { | |||
|      * @constructor | ||||
|      * @private | ||||
|      */ | ||||
|     static GetClosestNFeatures(params: ExtraFuncParams, | ||||
|                                feature: any, | ||||
|                                features: string | any[], | ||||
|                                options?: { maxFeatures?: number, uniqueTag?: string | undefined, maxDistance?: number }): { feat: any, distance: number }[] { | ||||
|     static GetClosestNFeatures( | ||||
|         params: ExtraFuncParams, | ||||
|         feature: any, | ||||
|         features: string | any[], | ||||
|         options?: { maxFeatures?: number; uniqueTag?: string | undefined; maxDistance?: number } | ||||
|     ): { feat: any; distance: number }[] { | ||||
|         const maxFeatures = options?.maxFeatures ?? 1 | ||||
|         const maxDistance = options?.maxDistance ?? 500 | ||||
|         const uniqueTag: string | undefined = options?.uniqueTag | ||||
|         if (typeof features === "string") { | ||||
|             const name = features | ||||
|             const bbox = GeoOperations.bbox(GeoOperations.buffer(GeoOperations.bbox(feature), maxDistance)) | ||||
|             const bbox = GeoOperations.bbox( | ||||
|                 GeoOperations.buffer(GeoOperations.bbox(feature), maxDistance) | ||||
|             ) | ||||
|             features = params.getFeaturesWithin(name, new BBox(bbox.geometry.coordinates)) | ||||
|         } else { | ||||
|             features = [features] | ||||
|         } | ||||
|         if (features === undefined) { | ||||
|             return; | ||||
|             return | ||||
|         } | ||||
| 
 | ||||
|         const selfCenter = GeoOperations.centerpointCoordinates(feature) | ||||
|         let closestFeatures: { feat: any, distance: number }[] = []; | ||||
|         let closestFeatures: { feat: any; distance: number }[] = [] | ||||
| 
 | ||||
|         for (const featureList of features) { | ||||
|             // Features is provided by 'getFeaturesWithin' which returns a list of lists of features, hence the double loop here
 | ||||
|             for (const otherFeature of featureList) { | ||||
| 
 | ||||
|                 if (otherFeature === feature || otherFeature.properties.id === feature.properties.id) { | ||||
|                     continue; // We ignore self
 | ||||
|                 if ( | ||||
|                     otherFeature === feature || | ||||
|                     otherFeature.properties.id === feature.properties.id | ||||
|                 ) { | ||||
|                     continue // We ignore self
 | ||||
|                 } | ||||
|                 const distance = GeoOperations.distanceBetween( | ||||
|                     GeoOperations.centerpointCoordinates(otherFeature), | ||||
|                     selfCenter | ||||
|                 ) | ||||
|                 if (distance === undefined || distance === null || isNaN(distance)) { | ||||
|                     console.error("Could not calculate the distance between", feature, "and", otherFeature) | ||||
|                     console.error( | ||||
|                         "Could not calculate the distance between", | ||||
|                         feature, | ||||
|                         "and", | ||||
|                         otherFeature | ||||
|                     ) | ||||
|                     throw "Undefined distance!" | ||||
|                 } | ||||
| 
 | ||||
|                 if (distance === 0) { | ||||
|                     console.trace("Got a suspiciously zero distance between", otherFeature, "and self-feature", feature) | ||||
|                     console.trace( | ||||
|                         "Got a suspiciously zero distance between", | ||||
|                         otherFeature, | ||||
|                         "and self-feature", | ||||
|                         feature | ||||
|                     ) | ||||
|                 } | ||||
| 
 | ||||
|                 if (distance > maxDistance) { | ||||
|  | @ -272,13 +309,15 @@ class ClosestNObjectFunc implements ExtraFunction { | |||
|                     // This is the first matching feature we find - always add it
 | ||||
|                     closestFeatures.push({ | ||||
|                         feat: otherFeature, | ||||
|                         distance: distance | ||||
|                         distance: distance, | ||||
|                     }) | ||||
|                     continue; | ||||
|                     continue | ||||
|                 } | ||||
| 
 | ||||
| 
 | ||||
|                 if (closestFeatures.length >= maxFeatures && closestFeatures[maxFeatures - 1].distance < distance) { | ||||
|                 if ( | ||||
|                     closestFeatures.length >= maxFeatures && | ||||
|                     closestFeatures[maxFeatures - 1].distance < distance | ||||
|                 ) { | ||||
|                     // The last feature of the list (and thus the furthest away is still closer
 | ||||
|                     // No use for checking, as we already have plenty of features!
 | ||||
|                     continue | ||||
|  | @ -286,11 +325,13 @@ class ClosestNObjectFunc implements ExtraFunction { | |||
| 
 | ||||
|                 let targetIndex = closestFeatures.length | ||||
|                 for (let i = 0; i < closestFeatures.length; i++) { | ||||
|                     const closestFeature = closestFeatures[i]; | ||||
|                     const closestFeature = closestFeatures[i] | ||||
| 
 | ||||
|                     if (uniqueTag !== undefined) { | ||||
|                         const uniqueTagsMatch = otherFeature.properties[uniqueTag] !== undefined && | ||||
|                             closestFeature.feat.properties[uniqueTag] === otherFeature.properties[uniqueTag] | ||||
|                         const uniqueTagsMatch = | ||||
|                             otherFeature.properties[uniqueTag] !== undefined && | ||||
|                             closestFeature.feat.properties[uniqueTag] === | ||||
|                                 otherFeature.properties[uniqueTag] | ||||
|                         if (uniqueTagsMatch) { | ||||
|                             targetIndex = -1 | ||||
|                             if (closestFeature.distance > distance) { | ||||
|  | @ -298,9 +339,9 @@ class ClosestNObjectFunc implements ExtraFunction { | |||
|                                 // We want to see the tag `uniquetag=some_value` only once in the entire list (e.g. to prevent road segements of identical names to fill up the list of 'names of nearby roads')
 | ||||
|                                 // AT this point, we have found a closer segment with the same, identical tag
 | ||||
|                                 // so we replace directly
 | ||||
|                                 closestFeatures[i] = {feat: otherFeature, distance: distance} | ||||
|                                 closestFeatures[i] = { feat: otherFeature, distance: distance } | ||||
|                             } | ||||
|                             break; | ||||
|                             break | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|  | @ -316,19 +357,19 @@ class ClosestNObjectFunc implements ExtraFunction { | |||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         break; | ||||
|                         break | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (targetIndex == -1) { | ||||
|                     continue; // value is already swapped by the unique tag
 | ||||
|                     continue // value is already swapped by the unique tag
 | ||||
|                 } | ||||
| 
 | ||||
|                 if (targetIndex < maxFeatures) { | ||||
|                     // insert and drop one
 | ||||
|                     closestFeatures.splice(targetIndex, 0, { | ||||
|                         feat: otherFeature, | ||||
|                         distance: distance | ||||
|                         distance: distance, | ||||
|                     }) | ||||
|                     if (closestFeatures.length >= maxFeatures) { | ||||
|                         closestFeatures.splice(maxFeatures, 1) | ||||
|  | @ -337,19 +378,15 @@ class ClosestNObjectFunc implements ExtraFunction { | |||
|                     // Overwrite the last element
 | ||||
|                     closestFeatures[targetIndex] = { | ||||
|                         feat: otherFeature, | ||||
|                         distance: distance | ||||
|                         distance: distance, | ||||
|                     } | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
|         return closestFeatures; | ||||
|         return closestFeatures | ||||
|     } | ||||
| 
 | ||||
|     _f(params, feature) { | ||||
| 
 | ||||
|         return (features, amount, uniqueTag, maxDistanceInMeters) => { | ||||
|             let distance: number = Number(maxDistanceInMeters) | ||||
|             if (isNaN(distance)) { | ||||
|  | @ -358,60 +395,54 @@ class ClosestNObjectFunc implements ExtraFunction { | |||
|             return ClosestNObjectFunc.GetClosestNFeatures(params, feature, features, { | ||||
|                 maxFeatures: Number(amount), | ||||
|                 uniqueTag: uniqueTag, | ||||
|                 maxDistance: distance | ||||
|             }); | ||||
|                 maxDistance: distance, | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class Memberships implements ExtraFunction { | ||||
|     _name = "memberships" | ||||
|     _doc = "Gives a list of `{role: string, relation: Relation}`-objects, containing all the relations that this feature is part of. " + | ||||
|     _doc = | ||||
|         "Gives a list of `{role: string, relation: Relation}`-objects, containing all the relations that this feature is part of. " + | ||||
|         "\n\n" + | ||||
|         "For example: `_part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')`" | ||||
|     _args = [] | ||||
| 
 | ||||
|     _f(params, feat) { | ||||
|         return () => | ||||
|             params.memberships.knownRelations.data.get(feat.properties.id) ?? [] | ||||
| 
 | ||||
|         return () => params.memberships.knownRelations.data.get(feat.properties.id) ?? [] | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class GetParsed implements ExtraFunction { | ||||
|     _name = "get" | ||||
|     _doc = "Gets the property of the feature, parses it (as JSON) and returns it. Might return 'undefined' if not defined, null, ..." | ||||
|     _doc = | ||||
|         "Gets the property of the feature, parses it (as JSON) and returns it. Might return 'undefined' if not defined, null, ..." | ||||
|     _args = ["key"] | ||||
| 
 | ||||
|     _f(params, feat) { | ||||
|         return key => { | ||||
|         return (key) => { | ||||
|             const value = feat.properties[key] | ||||
|             if (value === undefined) { | ||||
|                 return undefined; | ||||
|                 return undefined | ||||
|             } | ||||
|             try { | ||||
|                 const parsed = JSON.parse(value) | ||||
|                 if (parsed === null) { | ||||
|                     return undefined; | ||||
|                     return undefined | ||||
|                 } | ||||
|                 return parsed; | ||||
|                 return parsed | ||||
|             } catch (e) { | ||||
|                 console.warn("Could not parse property " + key + " due to: " + e + ", the value is " + value) | ||||
|                 return undefined; | ||||
|                 console.warn( | ||||
|                     "Could not parse property " + key + " due to: " + e + ", the value is " + value | ||||
|                 ) | ||||
|                 return undefined | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export class ExtraFunctions { | ||||
| 
 | ||||
| 
 | ||||
|     static readonly intro = new Combine([ | ||||
|         new Title("Calculating tags with Javascript", 2), | ||||
|         "In some cases, it is useful to have some tags calculated based on other properties. Some useful tags are available by default (e.g. `lat`, `lon`, `_country`), as detailed above.", | ||||
|  | @ -421,13 +452,13 @@ export class ExtraFunctions { | |||
|         new List([ | ||||
|             "DO NOT DO THIS AS BEGINNER", | ||||
|             "**Only do this if all other techniques fail**  This should _not_ be done to create a rendering effect, only to calculate a specific value", | ||||
|             "**THIS MIGHT BE DISABLED WITHOUT ANY NOTICE ON UNOFFICIAL THEMES** As unofficial themes might be loaded from the internet, this is the equivalent of injecting arbitrary code into the client. It'll be disabled if abuse occurs." | ||||
|             "**THIS MIGHT BE DISABLED WITHOUT ANY NOTICE ON UNOFFICIAL THEMES** As unofficial themes might be loaded from the internet, this is the equivalent of injecting arbitrary code into the client. It'll be disabled if abuse occurs.", | ||||
|         ]), | ||||
|         "To enable this feature,  add a field `calculatedTags` in the layer object, e.g.:", | ||||
|         "````", | ||||
|         "\"calculatedTags\": [", | ||||
|         "    \"_someKey=javascript-expression\",", | ||||
|         "    \"name=feat.properties.name ?? feat.properties.ref ?? feat.properties.operator\",", | ||||
|         '"calculatedTags": [', | ||||
|         '    "_someKey=javascript-expression",', | ||||
|         '    "name=feat.properties.name ?? feat.properties.ref ?? feat.properties.operator",', | ||||
|         "    \"_distanceCloserThen3Km=feat.distanceTo( some_lon, some_lat) < 3 ? 'yes' : 'no'\" ", | ||||
|         "  ]", | ||||
|         "````", | ||||
|  | @ -436,11 +467,12 @@ export class ExtraFunctions { | |||
| 
 | ||||
|         new List([ | ||||
|             "`area` contains the surface area (in square meters) of the object", | ||||
|             "`lat` and `lon` contain the latitude and longitude" | ||||
|             "`lat` and `lon` contain the latitude and longitude", | ||||
|         ]), | ||||
|         "Some advanced functions are available on **feat** as well:" | ||||
|     ]).SetClass("flex-col").AsMarkdown(); | ||||
| 
 | ||||
|         "Some advanced functions are available on **feat** as well:", | ||||
|     ]) | ||||
|         .SetClass("flex-col") | ||||
|         .AsMarkdown() | ||||
| 
 | ||||
|     private static readonly allFuncs: ExtraFunction[] = [ | ||||
|         new DistanceToFunc(), | ||||
|  | @ -450,8 +482,8 @@ export class ExtraFunctions { | |||
|         new ClosestObjectFunc(), | ||||
|         new ClosestNObjectFunc(), | ||||
|         new Memberships(), | ||||
|         new GetParsed() | ||||
|     ]; | ||||
|         new GetParsed(), | ||||
|     ] | ||||
| 
 | ||||
|     public static FullPatchFeature(params: ExtraFuncParams, feature) { | ||||
|         if (feature._is_patched) { | ||||
|  | @ -464,20 +496,15 @@ export class ExtraFunctions { | |||
|     } | ||||
| 
 | ||||
|     public static HelpText(): BaseUIElement { | ||||
| 
 | ||||
|         const elems = [] | ||||
|         for (const func of ExtraFunctions.allFuncs) { | ||||
|             elems.push(new Title(func._name, 3), | ||||
|                 func._doc, | ||||
|                 new List(func._args ?? [], true)) | ||||
|             elems.push(new Title(func._name, 3), func._doc, new List(func._args ?? [], true)) | ||||
|         } | ||||
| 
 | ||||
|         return new Combine([ | ||||
|             ExtraFunctions.intro, | ||||
|             new List(ExtraFunctions.allFuncs.map(func => `[${func._name}](#${func._name})`)), | ||||
|             ...elems | ||||
|         ]); | ||||
|             new List(ExtraFunctions.allFuncs.map((func) => `[${func._name}](#${func._name})`)), | ||||
|             ...elems, | ||||
|         ]) | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue