, imagePrefix = "image", loadSpecial = true): ImageSearcher {
+ const key = tags["id"] + " "+imagePrefix+loadSpecial;
+ if(ImageSearcher._cache.has(key)){
+ return ImageSearcher._cache.get(key)
+ }
+
+ const searcher = new ImageSearcher(tags, imagePrefix, loadSpecial);
+ ImageSearcher._cache.set(key, searcher)
+ return searcher;
+ }
}
\ No newline at end of file
diff --git a/Logic/Actors/UpdateFromOverpass.ts b/Logic/Actors/UpdateFromOverpass.ts
index c2ac6e85b4..d7b470a210 100644
--- a/Logic/Actors/UpdateFromOverpass.ts
+++ b/Logic/Actors/UpdateFromOverpass.ts
@@ -158,7 +158,7 @@ export default class UpdateFromOverpass implements FeatureSource {
self.retries.data++;
self.ForceRefresh();
self.timeout.setData(self.retries.data * 5);
- console.log(`QUERY FAILED (retrying in ${5 * self.retries.data} sec)`, reason);
+ console.log(`QUERY FAILED (retrying in ${5 * self.retries.data} sec)`);
self.retries.ping();
self.runningQuery.setData(false);
diff --git a/Logic/ExtraFunction.ts b/Logic/ExtraFunction.ts
index deb66bbfcd..3969b9434a 100644
--- a/Logic/ExtraFunction.ts
+++ b/Logic/ExtraFunction.ts
@@ -5,59 +5,9 @@ import Combine from "../UI/Base/Combine";
export class ExtraFunction {
- private static DistanceToFunc = new ExtraFunction(
- "distanceTo",
- "Calculates the distance between the feature and a specified point",
- ["longitude", "latitude"],
- (feature) => {
- return (lon, lat) => {
- // Feature._lon and ._lat is conveniently place by one of the other metatags
- return GeoOperations.distanceBetween([lon, lat], [feature._lon, feature._lat]);
- }
- }
- )
- private static readonly allFuncs: ExtraFunction[] = [ExtraFunction.DistanceToFunc];
- private readonly _name: string;
- private readonly _args: string[];
- private readonly _doc: string;
- private readonly _f: (feat: any) => any;
-
- constructor(name: string, doc: string, args: string[], f: ((feat: any) => any)) {
- this._name = name;
- this._doc = doc;
- this._args = args;
- this._f = f;
-
- }
-
- public static FullPatchFeature(feature) {
- for (const func of ExtraFunction.allFuncs) {
- func.PatchFeature(feature);
- }
- }
-
- public static HelpText(): UIElement {
- return new Combine([
- ExtraFunction.intro,
- ...ExtraFunction.allFuncs.map(func =>
- new Combine([
- "" + func._name + "
",
- func._doc,
- "",
- ...func._args.map(arg => "- " + arg + "
"),
- "
"
- ])
- )
- ]);
- }
-
- public PatchFeature(feature: any) {
- feature[this._name] = this._f(feature);
- }
-
static readonly intro = `Calculating tags with Javascript
-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.
+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.
It is also possible to calculate your own tags - but this requires some javascript knowledge.
@@ -71,11 +21,97 @@ Before proceeding, some warnings:
In the layer object, add a field calculatedTags, e.g.:
- "calculatedTags": {
- "_someKey": "javascript-expression",
- "name": "feat.properties.name ?? feat.properties.ref ?? feat.properties.operator",
- "_distanceCloserThen3Km": "feat.distanceTo( some_lon, some_lat) < 3 ? 'yes' : 'no'"
- }
+ "calculatedTags": [
+ "_someKey=javascript-expression",
+ "name=feat.properties.name ?? feat.properties.ref ?? feat.properties.operator",
+ "_distanceCloserThen3Km=feat.distanceTo( some_lon, some_lat) < 3 ? 'yes' : 'no'"
+ ]
+
+The above code will be executed for every feature in the layer. The feature is accessible as feat and is an amended geojson object:
+- area contains the surface area (in square meters) of the object
+- lat and lon contain the latitude and longitude
+
+Some advanced functions are available on feat as well:
+
`
+ private static OverlapFunc = new ExtraFunction(
+ "overlapWith",
+ "Gives a list of features from the specified layer which this feature overlaps with, the amount of overlap in m². The returned value is { feat: GeoJSONFeature, overlap: number}",
+ ["...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)"],
+ (featuresPerLayer, feat) => {
+ return (...layerIds: string[]) => {
+ const result = []
+ for (const layerId of layerIds) {
+ const otherLayer = featuresPerLayer.get(layerId);
+ if (otherLayer === undefined) {
+ console.error(`Trying to calculate 'overlapWith' with specified layer ${layerId}, but such layer is found`);
+ continue;
+ }
+
+ if (otherLayer.length === 0) {
+ continue;
+ }
+ result.push(...GeoOperations.calculateOverlap(feat, otherLayer));
+ }
+ return result;
+ }
+ }
+ )
+ private static DistanceToFunc = new ExtraFunction(
+ "distanceTo",
+ "Calculates the distance between the feature and a specified point",
+ ["longitude", "latitude"],
+ (featuresPerLayer, feature) => {
+ return (lon, lat) => {
+ // Feature._lon and ._lat is conveniently place by one of the other metatags
+ return GeoOperations.distanceBetween([lon, lat], [feature._lon, feature._lat]);
+ }
+ }
+ )
+ private static readonly allFuncs: ExtraFunction[] = [ExtraFunction.DistanceToFunc, ExtraFunction.OverlapFunc];
+ private readonly _name: string;
+ private readonly _args: string[];
+ private readonly _doc: string;
+ private readonly _f: (featuresPerLayer: Map, feat: any) => any;
+
+ constructor(name: string, doc: string, args: string[], f: ((featuresPerLayer: Map, feat: any) => any)) {
+ this._name = name;
+ this._doc = doc;
+ this._args = args;
+ this._f = f;
+
+ }
+
+ public static FullPatchFeature(featuresPerLayer: Map, feature) {
+ for (const func of ExtraFunction.allFuncs) {
+ func.PatchFeature(featuresPerLayer, feature);
+ }
+ }
+
+ public static HelpText(): UIElement {
+ return new Combine([
+ ExtraFunction.intro,
+ "",
+ ...ExtraFunction.allFuncs.map(func =>
+ new Combine([
+ "- ", func._name, "
"
+ ])
+ ),
+ "
",
+ ...ExtraFunction.allFuncs.map(func =>
+ new Combine([
+ "" + func._name + "
",
+ func._doc,
+ "",
+ ...func._args.map(arg => "- " + arg + "
"),
+ "
"
+ ])
+ )
+ ]);
+ }
+
+ public PatchFeature(featuresPerLayer: Map, feature: any) {
+ feature[this._name] = this._f(featuresPerLayer, feature);
+ }
}
\ No newline at end of file
diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts
index fb8d21f7eb..f6cca66ff3 100644
--- a/Logic/FeatureSource/FeaturePipeline.ts
+++ b/Logic/FeatureSource/FeaturePipeline.ts
@@ -2,7 +2,6 @@ import FilteringFeatureSource from "../FeatureSource/FilteringFeatureSource";
import FeatureSourceMerger from "../FeatureSource/FeatureSourceMerger";
import RememberingSource from "../FeatureSource/RememberingSource";
import WayHandlingApplyingFeatureSource from "../FeatureSource/WayHandlingApplyingFeatureSource";
-import NoOverlapSource from "../FeatureSource/NoOverlapSource";
import FeatureDuplicatorPerLayer from "../FeatureSource/FeatureDuplicatorPerLayer";
import FeatureSource from "../FeatureSource/FeatureSource";
import {UIEventSource} from "../UIEventSource";
@@ -25,9 +24,8 @@ export default class FeaturePipeline implements FeatureSource {
locationControl: UIEventSource) {
const amendedOverpassSource =
- new RememberingSource(
- new NoOverlapSource(flayers, new FeatureDuplicatorPerLayer(flayers,
- new LocalStorageSaver(updater, layout)))
+ new RememberingSource(new FeatureDuplicatorPerLayer(flayers,
+ new LocalStorageSaver(updater, layout))
);
const geojsonSources: GeoJsonSource [] = []
@@ -40,8 +38,7 @@ export default class FeaturePipeline implements FeatureSource {
}
const amendedLocalStorageSource =
- new RememberingSource(
- new NoOverlapSource(flayers, new FeatureDuplicatorPerLayer(flayers, new LocalStorageSource(layout)))
+ new RememberingSource(new FeatureDuplicatorPerLayer(flayers, new LocalStorageSource(layout))
);
newPoints = new FeatureDuplicatorPerLayer(flayers, newPoints);
diff --git a/Logic/FeatureSource/NoOverlapSource.ts b/Logic/FeatureSource/NoOverlapSource.ts
deleted file mode 100644
index c2af365328..0000000000
--- a/Logic/FeatureSource/NoOverlapSource.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import LayerConfig from "../../Customizations/JSON/LayerConfig";
-import FeatureSource from "./FeatureSource";
-import {UIEventSource} from "../UIEventSource";
-import {GeoOperations} from "../GeoOperations";
-
-/**
- * The no overlap source takes a featureSource and applies a filter on it.
- * First, it'll figure out for each feature to which layer it belongs
- * Then, it'll check any feature of any 'lower' layer
- */
-export default class NoOverlapSource {
-
- features: UIEventSource<{ feature: any, freshness: Date }[]> = new UIEventSource<{ feature: any, freshness: Date }[]>([]);
-
- constructor(layers: UIEventSource<{
- layerDef: LayerConfig
- }[]>,
- upstream: FeatureSource) {
- let noOverlapRemoval = true;
- for (const layer of layers.data) {
- if ((layer.layerDef.hideUnderlayingFeaturesMinPercentage ?? 0) !== 0) {
- noOverlapRemoval = false;
- }
- }
- if (noOverlapRemoval) {
- this.features = upstream.features;
- return;
- }
-
- this.features = upstream.features.map(
- features => {
- if (features === undefined) {
- return;
- }
-
- const layerIds = []
- const layerDict = {};
- for (const layer of layers.data) {
- layerDict[layer.layerDef.id] = layer;
- layerIds.push(layer.layerDef.id);
- if ((layer.layerDef.hideUnderlayingFeaturesMinPercentage ?? 0) !== 0) {
- noOverlapRemoval = false;
- }
- }
-
- // There is overlap removal active
- // We partition all the features with their respective layerIDs
- const partitions = {};
- for (const layerId of layerIds) {
- partitions[layerId] = []
- }
- for (const feature of features) {
- partitions[feature.feature._matching_layer_id].push(feature);
- }
-
- // With this partitioning in hand, we run over every layer and remove every underlying feature if needed
- for (let i = 0; i < layerIds.length; i++) {
- let layerId = layerIds[i];
- const percentage = layerDict[layerId].layerDef.hideUnderlayingFeaturesMinPercentage ?? 0;
- if (percentage === 0) {
- // We don't have to remove underlying features!
- continue;
- }
- const guardPartition = partitions[layerId];
- for (let j = i + 1; j < layerIds.length; j++) {
- let layerJd = layerIds[j];
- let partitionToShrink: { feature: any, freshness: Date }[] = partitions[layerJd];
- let newPartition = [];
- for (const mightBeDeleted of partitionToShrink) {
- const doesOverlap = GeoOperations.featureIsContainedInAny(
- mightBeDeleted.feature,
- guardPartition.map(f => f.feature),
- percentage
- );
- if (!doesOverlap) {
- newPartition.push(mightBeDeleted);
- }
- }
- partitions[layerJd] = newPartition;
- }
- }
-
- // At last, we create the actual new features
- let newFeatures: { feature: any, freshness: Date }[] = [];
- for (const layerId of layerIds) {
- newFeatures = newFeatures.concat(partitions[layerId]);
- }
- return newFeatures;
- });
- }
-}
\ No newline at end of file
diff --git a/Logic/GeoOperations.ts b/Logic/GeoOperations.ts
index 4011b5c2ec..e239951cb1 100644
--- a/Logic/GeoOperations.ts
+++ b/Logic/GeoOperations.ts
@@ -30,67 +30,61 @@ export class GeoOperations {
return turf.distance(lonlat0, lonlat1)
}
- static featureIsContainedInAny(feature: any,
- shouldNotContain: any[],
- maxOverlapPercentage: number): boolean {
- // Returns 'false' if no problematic intersection is found
+ /**
+ * Calculates the overlap of 'feature' with every other specified feature.
+ * The features with which 'feature' overlaps, are returned together with their overlap area in m²
+ *
+ * If 'feature' is a point, it will return every feature the point is embedded in. Overlap will be undefined
+ */
+ static calculateOverlap(feature: any,
+ otherFeatures: any[]): { feat: any, overlap: number }[] {
+ const featureBBox = BBox.get(feature);
+ const result : { feat: any, overlap: number }[] = [];
if (feature.geometry.type === "Point") {
const coor = feature.geometry.coordinates;
- for (const shouldNotContainElement of shouldNotContain) {
+ for (const otherFeature of otherFeatures) {
- let shouldNotContainBBox = BBox.get(shouldNotContainElement);
- let featureBBox = BBox.get(feature);
- if (!featureBBox.overlapsWith(shouldNotContainBBox)) {
+ let otherFeatureBBox = BBox.get(otherFeature);
+ if (!featureBBox.overlapsWith(otherFeatureBBox)) {
continue;
}
- if (this.inside(coor, shouldNotContainElement)) {
- return true
+ if (this.inside(coor, otherFeatures)) {
+ result.push({ feat: otherFeatures, overlap: undefined })
}
}
- return false;
+ return result;
}
if (feature.geometry.type === "Polygon" || feature.geometry.type === "MultiPolygon") {
- const poly = feature;
- let featureBBox = BBox.get(feature);
- const featureSurface = GeoOperations.surfaceAreaInSqMeters(poly);
- for (const shouldNotContainElement of shouldNotContain) {
-
- const shouldNotContainBBox = BBox.get(shouldNotContainElement);
- const overlaps = featureBBox.overlapsWith(shouldNotContainBBox)
+ for (const otherFeature of otherFeatures) {
+ const otherFeatureBBox = BBox.get(otherFeature);
+ const overlaps = featureBBox.overlapsWith(otherFeatureBBox)
if (!overlaps) {
continue;
}
// Calculate the surface area of the intersection
- // If it is too big, refuse
try {
- const intersection = turf.intersect(poly, shouldNotContainElement);
+ const intersection = turf.intersect(feature, otherFeature);
if (intersection == null) {
continue;
}
- const intersectionSize = turf.area(intersection);
- const ratio = intersectionSize / featureSurface;
-
- if (ratio * 100 >= maxOverlapPercentage) {
- console.log("Refused", poly.id, " due to ", shouldNotContainElement.id, "intersection ratio is ", ratio, "which is bigger then the target ratio of ", (maxOverlapPercentage / 100))
- return true;
- }
+ const intersectionSize = turf.area(intersection); // in m²
+ result.push({feat: otherFeature, overlap: intersectionSize})
} catch (exception) {
console.log("EXCEPTION CAUGHT WHILE INTERSECTING: ", exception);
- // We assume that this failed due to an intersection
- return true;
}
}
- return false; // No problematic intersections found
+ return result;
}
-
- return false;
+ console.error("Could not correctly calculate the overlap of ", feature, ": unsupported type")
+ return result;
}
+
public static inside(pointCoordinate, feature): boolean {
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
diff --git a/Logic/MetaTagging.ts b/Logic/MetaTagging.ts
index 46cf5bbe4e..b405947f20 100644
--- a/Logic/MetaTagging.ts
+++ b/Logic/MetaTagging.ts
@@ -26,11 +26,21 @@ export default class MetaTagging {
}
// The functions - per layer - which add the new keys
- const layerFuncs = new Map void)>();
+ const layerFuncs = new Map, feature: any) => void)>();
for (const layer of layers) {
layerFuncs.set(layer.id, this.createRetaggingFunc(layer));
}
+ const featuresPerLayer = new Map();
+ for (const feature of features) {
+
+ const key = feature.feature._matching_layer_id;
+ if (!featuresPerLayer.has(key)) {
+ featuresPerLayer.set(key, [])
+ }
+ featuresPerLayer.get(key).push(feature.feature)
+ }
+
for (const feature of features) {
// @ts-ignore
const key = feature.feature._matching_layer_id;
@@ -39,19 +49,19 @@ export default class MetaTagging {
continue;
}
- f(feature.feature)
+ f(featuresPerLayer, feature.feature)
}
}
- private static createRetaggingFunc(layer: LayerConfig): ((feature: any) => void) {
+ private static createRetaggingFunc(layer: LayerConfig): ((featuresPerLayer: Map, feature: any) => void) {
const calculatedTags: [string, string][] = layer.calculatedTags;
if (calculatedTags === undefined) {
return undefined;
}
- const functions: ((feature: any) => void)[] = [];
+ const functions: ((featuresPerLayer: Map, feature: any) => void)[] = [];
for (const entry of calculatedTags) {
const key = entry[0]
const code = entry[1];
@@ -61,26 +71,24 @@ export default class MetaTagging {
const func = new Function("feat", "return " + code + ";");
- const f = (feature: any) => {
+ const f = (featuresPerLayer, feature: any) => {
feature.properties[key] = func(feature);
}
functions.push(f)
}
- return (feature) => {
+ return (featuresPerLayer: Map, feature) => {
const tags = feature.properties
if (tags === undefined) {
return;
}
- ExtraFunction.FullPatchFeature(feature);
-
- for (const f of functions) {
- try {
- f(feature);
- } catch (e) {
- console.error("While calculating a tag value: ", e)
+ ExtraFunction.FullPatchFeature(featuresPerLayer, feature);
+ try {
+ for (const f of functions) {
+ f(featuresPerLayer, feature);
}
-
+ } catch (e) {
+ console.error("While calculating a tag value: ", e)
}
}
}
diff --git a/Logic/SimpleMetaTagger.ts b/Logic/SimpleMetaTagger.ts
index b9f0b304f1..460993982b 100644
--- a/Logic/SimpleMetaTagger.ts
+++ b/Logic/SimpleMetaTagger.ts
@@ -49,7 +49,7 @@ export default class SimpleMetaTagger {
const sqMeters = GeoOperations.surfaceAreaInSqMeters(feature);
feature.properties["_surface"] = "" + sqMeters;
feature.properties["_surface:ha"] = "" + Math.floor(sqMeters / 1000) / 10;
-
+ feature.area = sqMeters;
})
);
private static country = new SimpleMetaTagger(
diff --git a/Logic/Web/Wikimedia.ts b/Logic/Web/Wikimedia.ts
index 37be85dd95..bf68d22557 100644
--- a/Logic/Web/Wikimedia.ts
+++ b/Logic/Web/Wikimedia.ts
@@ -5,13 +5,13 @@ import * as $ from "jquery"
*/
export class Wikimedia {
+ private static knownLicenses = {};
+
static ImageNameToUrl(filename: string, width: number = 500, height: number = 200): string {
filename = encodeURIComponent(filename);
return "https://commons.wikimedia.org/wiki/Special:FilePath/" + filename + "?width=" + width + "&height=" + height;
}
- private static knownLicenses = {};
-
static LicenseData(filename: string, handle: ((LicenseInfo) => void)): void {
if (filename in this.knownLicenses) {
return this.knownLicenses[filename];
@@ -42,8 +42,9 @@ export class Wikimedia {
}
- static GetCategoryFiles(categoryName: string, handleCategory: ((ImagesInCategory) => void),
- alreadyLoaded = 0, continueParameter: { k: string, param: string } = undefined) {
+ static GetCategoryFiles(categoryName: string, handleCategory: ((ImagesInCategory: ImagesInCategory) => void),
+ alreadyLoaded = 0,
+ continueParameter: { k: string, param: string } = undefined) {
if (categoryName === undefined || categoryName === null || categoryName === "") {
return;
}
@@ -58,7 +59,8 @@ export class Wikimedia {
if (continueParameter !== undefined) {
url = url + "&" + continueParameter.k + "=" + continueParameter.param;
}
-
+ const self = this;
+ console.log("Loading a wikimedia category: ", url)
$.getJSON(url, (response) => {
let imageOverview = new ImagesInCategory();
let members = response.query?.categorymembers;
@@ -67,21 +69,27 @@ export class Wikimedia {
}
for (const member of members) {
-
imageOverview.images.push(member.title);
}
- if (response.continue === undefined || alreadyLoaded > 30) {
+ console.log("Got images! ", imageOverview)
+ if (response.continue === undefined) {
handleCategory(imageOverview);
- } else {
- console.log("Recursive load for ", categoryName)
- this.GetCategoryFiles(categoryName, (recursiveImages) => {
- for (const image of imageOverview.images) {
- recursiveImages.images.push(image);
- }
+ return;
+ }
+
+ if (alreadyLoaded > 10) {
+ console.log(`Recursive wikimedia category load stopped for ${categoryName} - got already enough images now (${alreadyLoaded})`)
+ handleCategory(imageOverview)
+ return;
+ }
+
+ self.GetCategoryFiles(categoryName,
+ (recursiveImages) => {
+ recursiveImages.images.push(...imageOverview.images);
handleCategory(recursiveImages);
},
- alreadyLoaded + 10, {k: "cmcontinue", param: response.continue.cmcontinue})
- }
+ alreadyLoaded + 10,
+ {k: "cmcontinue", param: response.continue.cmcontinue})
});
}
@@ -102,8 +110,7 @@ export class Wikimedia {
handleWikidata(wd);
});
}
-
-
+
}
diff --git a/UI/CustomGenerator/LayerPanel.ts b/UI/CustomGenerator/LayerPanel.ts
index 5375eb60b9..18eb8ec73f 100644
--- a/UI/CustomGenerator/LayerPanel.ts
+++ b/UI/CustomGenerator/LayerPanel.ts
@@ -98,10 +98,6 @@ export default class LayerPanel extends UIElement {
{value: 2, shown: "Show both the ways/areas and the centerpoints"},
{value: 1, shown: "Show everything as centerpoint"}]), "wayHandling", "Way handling",
"Describes how ways and areas are represented on the map: areas can be represented as the area itself, or it can be converted into the centerpoint"),
- setting(ValidatedTextField.NumberInput("int", n => n <= 100), "hideUnderlayingFeaturesMinPercentage", "Max allowed overlap percentage",
- "Consider that we want to show 'Nature Reserves' and 'Forests'. Now, ofter, there are pieces of forest mapped _in_ the nature reserve.
" +
- "Now, showing those pieces of forest overlapping with the nature reserve truly clutters the map and is very user-unfriendly.
" +
- "The features are placed layer by layer. If a feature below a feature on this layer overlaps for more then 'x'-percent, the underlying feature is hidden."),
setting(new AndOrTagInput(), ["osmSource","overpassTags"], "Overpass query",
"The tags of the objects to load from overpass"),
diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts
index 72772e107b..0307fa7d14 100644
--- a/UI/SpecialVisualizations.ts
+++ b/UI/SpecialVisualizations.ts
@@ -59,7 +59,7 @@ export default class SpecialVisualizations {
constr: (state: State, tags, args) => {
const imagePrefix = args[0];
const loadSpecial = args[1].toLowerCase() === "true";
- const searcher: UIEventSource<{ key: string, url: string }[]> = new ImageSearcher(tags, imagePrefix, loadSpecial);
+ const searcher: UIEventSource<{ key: string, url: string }[]> = ImageSearcher.construct(tags, imagePrefix, loadSpecial);
return new ImageCarousel(searcher, tags);
}
diff --git a/assets/themes/buurtnatuur/buurtnatuur.json b/assets/themes/buurtnatuur/buurtnatuur.json
index 8e610ed2d6..a6e6cc9e4d 100644
--- a/assets/themes/buurtnatuur/buurtnatuur.json
+++ b/assets/themes/buurtnatuur/buurtnatuur.json
@@ -25,7 +25,7 @@
"startLat": 50.8435,
"startLon": 4.3688,
"startZoom": 16,
- "widenFactor": 0.05,
+ "widenFactor": 0.01,
"socialImage": "./assets/themes/buurtnatuur/social_image.jpg",
"layers": [
{
@@ -75,7 +75,6 @@
"tagRenderings": [
"images"
],
- "hideUnderlayingFeaturesMinPercentage": 10,
"icon": {
"render": "circle:#ffffff;./assets/themes/buurtnatuur/nature_reserve.svg"
},
@@ -141,6 +140,19 @@
]
}
},
+ "calculatedTags": [
+ "_overlapWithUpperLayers=Math.max(...feat.overlapWith('nature_reserve').map(o => o.overlap))/feat.area",
+ "_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' :'no'"
+ ],
+ "isShown": {
+ "render": "yes",
+ "mappings": [
+ {
+ "if": "_tooMuchOverlap=yes",
+ "then": "no"
+ }
+ ]
+ },
"title": {
"render": {
"nl": "Park"
@@ -149,7 +161,7 @@
{
"if": {
"and": [
- "name:nl~"
+ "name:nl~*"
]
},
"then": {
@@ -174,7 +186,6 @@
"tagRenderings": [
"images"
],
- "hideUnderlayingFeaturesMinPercentage": 10,
"icon": {
"render": "circle:#ffffff;./assets/themes/buurtnatuur/park.svg"
},
@@ -228,6 +239,19 @@
]
}
},
+ "calculatedTags": [
+ "_overlapWithUpperLayers=Math.max(...feat.overlapWith('parks','nature_reserve').map(o => o.overlap))/feat.area",
+ "_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' : 'no'"
+ ],
+ "isShown": {
+ "render": "yes",
+ "mappings": [
+ {
+ "if": "_tooMuchOverlap=yes",
+ "then": "no"
+ }
+ ]
+ },
"title": {
"render": {
"nl": "Bos"
@@ -236,7 +260,7 @@
{
"if": {
"and": [
- "name:nl~"
+ "name:nl~*"
]
},
"then": {
@@ -261,7 +285,6 @@
"tagRenderings": [
"images"
],
- "hideUnderlayingFeaturesMinPercentage": 0,
"icon": {
"render": "circle:#ffffff;./assets/themes/buurtnatuur/forest.svg"
},