From fc255c1a8b03a54cfa89df32f668cfcc7592e977 Mon Sep 17 00:00:00 2001 From: SC Date: Wed, 6 Oct 2021 15:21:34 +0000 Subject: [PATCH 01/29] Translated using Weblate (Portuguese) Currently translated at 100.0% (25 of 25 strings) Translation: MapComplete/shared-questions Translate-URL: https://hosted.weblate.org/projects/mapcomplete/shared-questions/pt/ --- langs/shared-questions/pt.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/langs/shared-questions/pt.json b/langs/shared-questions/pt.json index 9524e139d5..a1622b21a3 100644 --- a/langs/shared-questions/pt.json +++ b/langs/shared-questions/pt.json @@ -61,6 +61,23 @@ } }, "question": "Este lugar é acessível a utilizadores de cadeiras de rodas?" + }, + "dog-access": { + "mappings": { + "0": { + "then": "Os cães são permitidos" + }, + "1": { + "then": "Os cães não são permitidos" + }, + "2": { + "then": "Os cães são permitidos, mas têm de ser presos pela trela" + }, + "3": { + "then": "Os cães são permitidos e podem correr livremente" + } + }, + "question": "Os cães são permitidos neste estabelecimento?" } } -} \ No newline at end of file +} From cee8eafb83e1e0c3fc553bbc48965f55b8fec6ca Mon Sep 17 00:00:00 2001 From: SC Date: Wed, 6 Oct 2021 15:23:37 +0000 Subject: [PATCH 02/29] Translated using Weblate (Portuguese) Currently translated at 30.4% (60 of 197 strings) Translation: MapComplete/Core Translate-URL: https://hosted.weblate.org/projects/mapcomplete/core/pt/ --- langs/pt.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/langs/pt.json b/langs/pt.json index 577ee0f205..f489838b87 100644 --- a/langs/pt.json +++ b/langs/pt.json @@ -20,5 +20,9 @@ "uploadingMultiple": "A enviar {count} imagens…", "uploadingPicture": "A enviar a sua imagem…", "addPicture": "Adicionar imagem" + }, + "index": { + "#": "Estes textos são mostrados acima dos botões do tema quando nenhum tema é carregado", + "title": "Bem-vindo(a) ao MapComplete" } } From 0dd483baf5a2fad5cb42e0dd647037be5272ffd4 Mon Sep 17 00:00:00 2001 From: SC Date: Thu, 7 Oct 2021 17:41:58 +0000 Subject: [PATCH 03/29] Translated using Weblate (Portuguese) Currently translated at 32.9% (65 of 197 strings) Translation: MapComplete/Core Translate-URL: https://hosted.weblate.org/projects/mapcomplete/core/pt/ --- langs/pt.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/langs/pt.json b/langs/pt.json index f489838b87..92db819cb1 100644 --- a/langs/pt.json +++ b/langs/pt.json @@ -23,6 +23,17 @@ }, "index": { "#": "Estes textos são mostrados acima dos botões do tema quando nenhum tema é carregado", - "title": "Bem-vindo(a) ao MapComplete" + "title": "Bem-vindo(a) ao MapComplete", + "intro": "O MapComplete é um visualizador e editor do OpenStreetMap, que mostra informações sobre um tema específico.", + "pickTheme": "Escolha um tema abaixo para começar." + }, + "delete": { + "reasons": { + "notFound": "Não foi possível encontrar este elemento" + }, + "explanations": { + "selectReason": "Por favor, selecione a razão porque este elemento deve ser eliminado", + "hardDelete": "Este ponto será eliminado no OpenStreetMap. Pode ser recuperado por um contribuidor com experiência" + } } } From 72e42c1e1db6defcb50c1573b2e1713054e6190c Mon Sep 17 00:00:00 2001 From: nicole_s <15011784+nicolelaine@users.noreply.github.com> Date: Sun, 10 Oct 2021 13:57:37 +0200 Subject: [PATCH 04/29] Added postboxes_postoffices theme and components --- .../postboxes_postoffices/license_info.json | 15 ++ .../postboxes_postoffices/post_office.svg | 1 + .../themes/postboxes_postoffices/postbox.svg | 143 ++++++++++++++++++ .../postboxes_postoffices.json | 138 +++++++++++++++++ 4 files changed, 297 insertions(+) create mode 100644 assets/themes/postboxes_postoffices/license_info.json create mode 100644 assets/themes/postboxes_postoffices/post_office.svg create mode 100644 assets/themes/postboxes_postoffices/postbox.svg create mode 100644 assets/themes/postboxes_postoffices/postboxes_postoffices.json diff --git a/assets/themes/postboxes_postoffices/license_info.json b/assets/themes/postboxes_postoffices/license_info.json new file mode 100644 index 0000000000..869dda32ca --- /dev/null +++ b/assets/themes/postboxes_postoffices/license_info.json @@ -0,0 +1,15 @@ +[ + { + "path": "postbox.svg", + "license": "CC BY 4.0", + "authors": ["Vincent Le Moign","https://twitter.com/webalys"], + "sources": ["https://upload.wikimedia.org/wikipedia/commons/6/6d/726-postbox.svg", "http://emoji.streamlineicons.com"] + }, + + { + "path": "post_office.svg", + "license": "CC BY-SA 4.0", + "authors": ["https://github.com/emojione/emojione/graphs/contributors"], + "sources": ["https://commons.wikimedia.org/wiki/File:Emojione_BW_1F3E4.svg", "https://github.com/emojione/emojione/blob/2.2.7/assets/svg_bw/1f3e4.svg"] + } + ] \ No newline at end of file diff --git a/assets/themes/postboxes_postoffices/post_office.svg b/assets/themes/postboxes_postoffices/post_office.svg new file mode 100644 index 0000000000..ebdd76b493 --- /dev/null +++ b/assets/themes/postboxes_postoffices/post_office.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/postboxes_postoffices/postbox.svg b/assets/themes/postboxes_postoffices/postbox.svg new file mode 100644 index 0000000000..05e6d95d4d --- /dev/null +++ b/assets/themes/postboxes_postoffices/postbox.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/postboxes_postoffices/postboxes_postoffices.json b/assets/themes/postboxes_postoffices/postboxes_postoffices.json new file mode 100644 index 0000000000..8d7aa81ed8 --- /dev/null +++ b/assets/themes/postboxes_postoffices/postboxes_postoffices.json @@ -0,0 +1,138 @@ +{ + "id": "postboxes", + "title": { + "en": "Postbox and Post Office Map" + }, + "shortDescription": { + "en": "A map showing postboxes and post offices" + }, + "description": { + "en": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :) " + }, + "language": [ + "en" + ], + "maintainer": "", + "icon": "./assets/themes/postboxes_postoffices/postbox.svg", + "version": "0", + "startLat": 53.5511, + "startLon": 9.9937, + "startZoom": 13, + "widenFactor": 0.05, + "socialImage": "", + "layers": [{ + "id": "postboxes", + "name": { + "en": "Postbox" + }, + "minzoom": 12, + "overpassTags": { + "and": [ + "amenity=post_box" + ] + }, + "title": { + "render": { + "en": "Postbox" + } + }, + "description": { + "en": "The layer showing postboxes." + }, + "tagRenderings": [ + "images", + { + "render": "{minimap(18): height: 5rem; overflow: hidden; border-radius:3rem; }" + } + ], + "icon": { + "render": "./assets/themes/postboxes_postoffices/postbox.svg" + }, + "width": { + "render": "1" + }, + "iconSize": { + "render": "40,40,bottom" + }, + "color": { + "render": "#DADADA" + }, + "presets": [{ + "tags": [ + "amenity=post_box" + ], + "title": { + "en": "Postbox" + } + }], + "wayHandling": "both outline and center" + }, + { + "id": "postoffices", + "name": { + "en": "A layer containing post offices" + }, + "minzoom": 12, + "overpassTags": { + "and": [ + "amenity=post_office" + ] + }, + "title": { + "render": { + "en": "Post Office" + } + }, + "description": { + "en": "A layer showing post offices." + }, + "tagRenderings": [ + "images", + { + "render": "{minimap(18): height: 5rem; overflow: hidden; border-radius:3rem; }" + }, + { + "#": "OH", + "render": { + "en": "Opening Hours: {opening_hours}" + }, + "freeform": { + "key": "opening_hours", + "type": "opening_hours" + }, + "question": { + "en": "What are the opening hours for this post office?" + }, + "mappings": [{ + "if": "opening_hours=24/7", + "then": { + "en": "24/7 opened (including holidays)" + } + }] + } + ], + "icon": { + "render": "./assets/themes/postboxes_postoffices/post_office.svg" + }, + "width": { + "render": "1" + }, + "iconSize": { + "render": "40,40,bottom" + }, + "color": { + "render": "#DADADA" + }, + "presets": [{ + "tags": [ + "amenity=post_office" + ], + "title": { + "en": "Post Office" + } + }], + "wayHandling": 2 + } + ], + "roamingRenderings": [] +} \ No newline at end of file From afc8bc86448504d7f68d505b602f31ef09d99ecf Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 00:55:13 +0200 Subject: [PATCH 05/29] Translation reset --- langs/themes/en.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/langs/themes/en.json b/langs/themes/en.json index 9dcb4b54af..e1d8f67241 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -1362,11 +1362,6 @@ "title": { "render": "Known address" } - }, - "2": { - "title": { - "render": "{name}" - } } }, "shortDescription": "Help to build an open dataset of UK addresses", From 4f4203f670fba799bbf15ac82e7dfbc13f532e20 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 12:51:54 +0200 Subject: [PATCH 06/29] Add minzoom for charging stations --- Models/ThemeConfig/LayoutConfig.ts | 2 +- assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Models/ThemeConfig/LayoutConfig.ts b/Models/ThemeConfig/LayoutConfig.ts index 51cf19d759..9add1c7f92 100644 --- a/Models/ThemeConfig/LayoutConfig.ts +++ b/Models/ThemeConfig/LayoutConfig.ts @@ -92,7 +92,7 @@ export default class LayoutConfig { throw "Widenfactor too small" }else{ // Unofficial themes get away with this - console.warn("Detected a very small widenfactor, bumping this above 1.") + console.warn("Detected a very small widenfactor for theme ", this.id ,", bumping this above 1.") json.widenFactor = json.widenFactor + 1 } } diff --git a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json index 2b303ea145..0a2eaa9e2f 100644 --- a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json +++ b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json @@ -31,7 +31,12 @@ "minzoom": 16 } }, - "charging_station", + { + "builtin": "charging_station", + "override": { + "minzoom": 16 + } + }, "toilet", "bench", "waste_basket", From 7576f7069bd7462e5179e10aa374e863a3d7d374 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 13:28:12 +0200 Subject: [PATCH 07/29] Fix broken layer selection --- .gitignore | 4 +++- InitUiElements.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5d39c4885c..b2ad34580d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,6 @@ Docs/Tools/stats.csv missing_translations.txt *.swp .DS_Store -Svg.ts \ No newline at end of file +Svg.ts +data/ +Folder.DotSettings.user diff --git a/InitUiElements.ts b/InitUiElements.ts index 8fafd7677d..dfd5b44396 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -489,7 +489,7 @@ export class InitUiElements { } return true - }, [State.state.currentBounds] + }, [State.state.currentBounds, source.layer.isDisplayed] ) new ShowDataLayer( From c010fb5271cc944b37ec9e6b07bd34a1234677c1 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 21:23:14 +0200 Subject: [PATCH 08/29] Change padding method, add max bounds, fix zoomlevels on toerisme vlaanderen theme --- Logic/Actors/OverpassFeatureSource.ts | 11 ++++-- Logic/BBox.ts | 17 ++++---- Logic/FeatureSource/FeaturePipeline.ts | 7 ++-- UI/BigComponents/ThemeIntroductionPanel.ts | 10 ++--- .../toerisme_vlaanderen.json | 39 ++++++++++++++----- 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/Logic/Actors/OverpassFeatureSource.ts b/Logic/Actors/OverpassFeatureSource.ts index 4f4f7a77f8..e27e0665d9 100644 --- a/Logic/Actors/OverpassFeatureSource.ts +++ b/Logic/Actors/OverpassFeatureSource.ts @@ -39,7 +39,7 @@ export default class OverpassFeatureSource implements FeatureSource { } private readonly _isActive: UIEventSource; private readonly onBboxLoaded: (bbox: BBox, date: Date, layers: LayerConfig[]) => void; - + private readonly padToTiles : number constructor( state: { readonly locationControl: UIEventSource, @@ -49,7 +49,8 @@ export default class OverpassFeatureSource implements FeatureSource { readonly overpassMaxZoom: UIEventSource, readonly currentBounds: UIEventSource }, - options?: { + options: { + padToTiles: number, isActive?: UIEventSource, relationTracker: RelationsTracker, onBboxLoaded?: (bbox: BBox, date: Date, layers: LayerConfig[]) => void @@ -57,6 +58,7 @@ export default class OverpassFeatureSource implements FeatureSource { this.state = state this._isActive = options.isActive; + this.padToTiles = options.padToTiles; this.onBboxLoaded = options.onBboxLoaded this.relationsTracker = options.relationTracker const self = this; @@ -109,11 +111,14 @@ export default class OverpassFeatureSource implements FeatureSource { return undefined; } - const bounds = this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(14); + const bounds = this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(this.padToTiles); if (bounds === undefined) { return undefined; } + console.log("Current bounds are", this.state.currentBounds.data," padded with",this.state.layoutToUse.widenFactor+":", + this.state.currentBounds.data.pad(this.state.layoutToUse.widenFactor), + "Tileexpanded: ",this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(this.padToTiles) ) const self = this; diff --git a/Logic/BBox.ts b/Logic/BBox.ts index a6f350cf83..0205b15337 100644 --- a/Logic/BBox.ts +++ b/Logic/BBox.ts @@ -116,16 +116,15 @@ export class BBox { return this.minLat } - pad(factor: number): BBox { - const latDiff = this.maxLat - this.minLat - const lat = (this.maxLat + this.minLat) / 2 - const lonDiff = this.maxLon - this.minLon - const lon = (this.maxLon + this.minLon) / 2 + pad(factor: number, maxIncrease = 2): BBox { + + const latDiff = Math.min(maxIncrease / 2, Math.abs(this.maxLat - this.minLat) * factor) + const lonDiff =Math.min(maxIncrease / 2, Math.abs(this.maxLon - this.minLon) * factor) return new BBox([[ - lon - lonDiff * factor, - lat - latDiff * factor - ], [lon + lonDiff * factor, - lat + latDiff * factor]]) + this.minLon - lonDiff, + this.minLat - latDiff + ], [this.maxLon + lonDiff, + this.maxLat + latDiff]]) } toLeaflet() { diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index 3aa0af3562..ea33827f60 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -58,7 +58,7 @@ export default class FeaturePipeline { private readonly freshnesses = new Map(); private readonly oldestAllowedDate: Date = new Date(new Date().getTime() - 60 * 60 * 24 * 30 * 1000); - private readonly osmSourceZoomLevel = 14 + private readonly osmSourceZoomLevel = 15 constructor( handleFeatureSource: (source: FeatureSourceForLayer & Tiled) => void, @@ -147,7 +147,7 @@ export default class FeaturePipeline { // We split them up into tiles anyway as it is an OSM source TiledFeatureSource.createHierarchy(src, { layer: src.layer, - minZoomLevel: 14, + minZoomLevel: this.osmSourceZoomLevel, dontEnforceMinZoom: true, registerTile: (tile) => { new RegisteringAllFromFeatureSourceActor(tile) @@ -200,7 +200,7 @@ export default class FeaturePipeline { new PerLayerFeatureSourceSplitter(state.filteredLayers, (source) => TiledFeatureSource.createHierarchy(source, { layer: source.layer, - minZoomLevel: 14, + minZoomLevel: this.osmSourceZoomLevel, dontEnforceMinZoom: true, maxFeatureCount: state.layoutToUse.clustering.minNeededElements, maxZoomLevel: state.layoutToUse.clustering.maxZoom, @@ -333,6 +333,7 @@ export default class FeaturePipeline { const self = this; const updater = new OverpassFeatureSource(state, { + padToTiles: this.osmSourceZoomLevel, relationTracker: this.relationTracker, isActive: useOsmApi.map(b => !b && overpassIsActive.data, [overpassIsActive]), onBboxLoaded: ((bbox, date, downloadedLayers) => { diff --git a/UI/BigComponents/ThemeIntroductionPanel.ts b/UI/BigComponents/ThemeIntroductionPanel.ts index fec58bb29f..c7c0964210 100644 --- a/UI/BigComponents/ThemeIntroductionPanel.ts +++ b/UI/BigComponents/ThemeIntroductionPanel.ts @@ -50,13 +50,11 @@ export default class ThemeIntroductionPanel extends Combine { ) super([ - layout.description.Clone(), - "

", + layout.description.Clone().SetClass("blcok mb-4"), toTheMap, - loginStatus, - layout.descriptionTail?.Clone(), - "
", - languagePicker, + loginStatus.SetClass("block"), + layout.descriptionTail?.Clone().SetClass("block mt-4"), + languagePicker.SetClass("block mt-4"), ...layout.CustomCodeSnippets() ]) diff --git a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json index 0a2eaa9e2f..7a401b0ab8 100644 --- a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json +++ b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json @@ -14,7 +14,10 @@ "nl": "Een kaart om toeristisch relevante info op aan te duiden" }, "description": { - "nl": "Op deze kaart kan je info zien die relevant is voor toerisme, zoals:
  • Eetgelegenheden
  • Cafés en bars
  • (Fiets)oplaadpunten
  • Fietspompen, fietserverhuur en fietswinkels
  • Uitkijktorens
  • ...
Zie je fouten op de kaart? Dan kan je zelf makkelijk aanpasingen maken, die zichtbaar zijn voor iedereen. Hiervoor dien je een gratis OpenStreetMap account voor te maken.

Met de steun van Toerisme Vlaanderen" + "nl": "Op deze kaart kan je info zien die relevant is voor toerisme, zoals:
  • Eetgelegenheden
  • Cafés en bars
  • (Fiets)oplaadpunten
  • Fietspompen, fietserverhuur en fietswinkels
  • Uitkijktorens
  • ...
Zie je fouten op de kaart? Dan kan je zelf makkelijk aanpasingen maken, die zichtbaar zijn voor iedereen. Hiervoor dien je een gratis OpenStreetMap account voor te maken." + }, + "descriptionTail": { + "nl": "Met de steun van Toerisme Vlaanderen" }, "icon": "./assets/svg/star.svg", "startZoom": 8, @@ -28,21 +31,37 @@ "cafe_pub" ], "override": { - "minzoom": 16 + "minzoom": 17 } }, { - "builtin": "charging_station", + "builtin": [ + "bench", + "waste_basket" + ], "override": { - "minzoom": 16 + "minzoom": 19 } }, - "toilet", - "bench", - "waste_basket", - "bike_repair_station", - "binocular", - "observation_tower" + { + "builtin": [ + "charging_station", + "toilet", + "bike_repair_station" + ], + "override": { + "minzoom": 14 + } + }, + { + "builtin": [ + "binocular", + "observation_tower" + ], + "override": { + "minzoom": 10 + } + } ], "hideFromOverview": true } \ No newline at end of file From 3157c35c62268ec54f4492fcf010ce47929937ed Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 21:23:31 +0200 Subject: [PATCH 09/29] Version bump --- Models/Constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Models/Constants.ts b/Models/Constants.ts index a45d19e9ed..2b266f4ad5 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.10.3"; + public static vNumber = "0.10.4"; public static ImgurApiKey = '7070e7167f0a25a' public static readonly mapillary_client_token_v3 = 'TXhLaWthQ1d4RUg0czVxaTVoRjFJZzowNDczNjUzNmIyNTQyYzI2' public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85" From 178cefceb41c854196356bad856d70eb728de2d7 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 22:30:22 +0200 Subject: [PATCH 10/29] Fix bounds and loading with overpass --- Logic/Actors/OverpassFeatureSource.ts | 23 ++-- .../Actors/SaveTileToLocalStorageActor.ts | 4 +- Logic/FeatureSource/FeaturePipeline.ts | 30 ++--- .../TiledFromLocalStorageSource.ts | 119 ++++++++---------- Models/Constants.ts | 2 +- Models/TileRange.ts | 2 +- .../toerisme_vlaanderen.json | 1 + 7 files changed, 78 insertions(+), 103 deletions(-) diff --git a/Logic/Actors/OverpassFeatureSource.ts b/Logic/Actors/OverpassFeatureSource.ts index e27e0665d9..62cf799988 100644 --- a/Logic/Actors/OverpassFeatureSource.ts +++ b/Logic/Actors/OverpassFeatureSource.ts @@ -38,8 +38,7 @@ export default class OverpassFeatureSource implements FeatureSource { readonly currentBounds: UIEventSource } private readonly _isActive: UIEventSource; - private readonly onBboxLoaded: (bbox: BBox, date: Date, layers: LayerConfig[]) => void; - private readonly padToTiles : number + private readonly onBboxLoaded: (bbox: BBox, date: Date, layers: LayerConfig[], zoomlevel: number) => void; constructor( state: { readonly locationControl: UIEventSource, @@ -50,20 +49,19 @@ export default class OverpassFeatureSource implements FeatureSource { readonly currentBounds: UIEventSource }, options: { - padToTiles: number, + padToTiles: UIEventSource, isActive?: UIEventSource, relationTracker: RelationsTracker, - onBboxLoaded?: (bbox: BBox, date: Date, layers: LayerConfig[]) => void + onBboxLoaded?: (bbox: BBox, date: Date, layers: LayerConfig[], zoomlevel: number) => void }) { this.state = state this._isActive = options.isActive; - this.padToTiles = options.padToTiles; this.onBboxLoaded = options.onBboxLoaded this.relationsTracker = options.relationTracker const self = this; state.currentBounds.addCallback(_ => { - self.update() + self.update(options.padToTiles.data) }) } @@ -86,21 +84,21 @@ export default class OverpassFeatureSource implements FeatureSource { return new Overpass(new Or(filters), extraScripts, interpreterUrl, this.state.overpassTimeout, this.relationsTracker); } - private update() { + private update(paddedZoomLevel: number) { if (!this._isActive.data) { return; } const self = this; - this.updateAsync().then(bboxDate => { + this.updateAsync(paddedZoomLevel).then(bboxDate => { if(bboxDate === undefined || self.onBboxLoaded === undefined){ return; } const [bbox, date, layers] = bboxDate - self.onBboxLoaded(bbox, date, layers) + self.onBboxLoaded(bbox, date, layers, paddedZoomLevel) }) } - private async updateAsync(): Promise<[BBox, Date, LayerConfig[]]> { + private async updateAsync(padToZoomLevel: number): Promise<[BBox, Date, LayerConfig[]]> { if (this.runningQuery.data) { console.log("Still running a query, not updating"); return undefined; @@ -111,14 +109,11 @@ export default class OverpassFeatureSource implements FeatureSource { return undefined; } - const bounds = this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(this.padToTiles); + const bounds = this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(padToZoomLevel); if (bounds === undefined) { return undefined; } - console.log("Current bounds are", this.state.currentBounds.data," padded with",this.state.layoutToUse.widenFactor+":", - this.state.currentBounds.data.pad(this.state.layoutToUse.widenFactor), - "Tileexpanded: ",this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(this.padToTiles) ) const self = this; diff --git a/Logic/FeatureSource/Actors/SaveTileToLocalStorageActor.ts b/Logic/FeatureSource/Actors/SaveTileToLocalStorageActor.ts index 2894d56b82..96e9938aac 100644 --- a/Logic/FeatureSource/Actors/SaveTileToLocalStorageActor.ts +++ b/Logic/FeatureSource/Actors/SaveTileToLocalStorageActor.ts @@ -7,7 +7,7 @@ import {FeatureSourceForLayer} from "../FeatureSource"; export default class SaveTileToLocalStorageActor { public static readonly storageKey: string = "cached-features"; - public static readonly formatVersion: string = "1" + public static readonly formatVersion: string = "2" constructor(source: FeatureSourceForLayer, tileIndex: number) { source.features.addCallbackAndRunD(features => { @@ -31,6 +31,6 @@ export default class SaveTileToLocalStorageActor { const key = `${SaveTileToLocalStorageActor.storageKey}-${layerId}-${tileId}` localStorage.setItem(key + "-time", JSON.stringify(freshness.getTime())) localStorage.setItem(key + "-format", SaveTileToLocalStorageActor.formatVersion) - + console.log("Marked ", key, "as visited") } } \ No newline at end of file diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index ea33827f60..6df7b87f4f 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -155,7 +155,7 @@ export default class FeaturePipeline { tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile)) } }) - }else{ + } else { new RegisteringAllFromFeatureSourceActor(src) perLayerHierarchy.get(id).registerTile(src) src.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(src)) @@ -200,7 +200,7 @@ export default class FeaturePipeline { new PerLayerFeatureSourceSplitter(state.filteredLayers, (source) => TiledFeatureSource.createHierarchy(source, { layer: source.layer, - minZoomLevel: this.osmSourceZoomLevel, + minZoomLevel: source.layer.layerDef.minzoom, dontEnforceMinZoom: true, maxFeatureCount: state.layoutToUse.clustering.minNeededElements, maxZoomLevel: state.layoutToUse.clustering.maxZoom, @@ -233,7 +233,7 @@ export default class FeaturePipeline { // Whenever fresh data comes in, we need to update the metatagging - self.newDataLoadedSignal.stabilized(1000).addCallback(src => { + self.newDataLoadedSignal.stabilized(1000).addCallback(_ => { self.updateAllMetaTagging() }) @@ -270,15 +270,15 @@ export default class FeaturePipeline { const self = this return this.state.currentBounds.map(bbox => { if (bbox === undefined) { - return + return undefined } if (!isSufficientlyZoomed.data) { - return; + return undefined; } const osmSourceZoomLevel = self.osmSourceZoomLevel const range = bbox.containingTileRange(osmSourceZoomLevel) const tileIndexes = [] - if (range.total > 100) { + if (range.total >= 100) { // Too much tiles! return [] } @@ -288,7 +288,7 @@ export default class FeaturePipeline { if (oldestDate !== undefined && oldestDate > this.oldestAllowedDate) { console.debug("Skipping tile", osmSourceZoomLevel, x, y, "as a decently fresh one is available") // The cached tiles contain decently fresh data - return; + return undefined; } tileIndexes.push(i) }) @@ -321,29 +321,30 @@ export default class FeaturePipeline { } const range = bbox.containingTileRange(zoom) - if (range.total > 100) { + if (range.total >= 5000) { return false } const self = this; const allFreshnesses = Tiles.MapRange(range, (x, y) => self.freshnessForVisibleLayers(zoom, x, y)) return allFreshnesses.some(freshness => freshness === undefined || freshness < this.oldestAllowedDate) - }, [state.locationControl]) const self = this; const updater = new OverpassFeatureSource(state, { - padToTiles: this.osmSourceZoomLevel, + padToTiles: state.locationControl.map(l => Math.min(15, l.zoom + 1)), relationTracker: this.relationTracker, isActive: useOsmApi.map(b => !b && overpassIsActive.data, [overpassIsActive]), - onBboxLoaded: ((bbox, date, downloadedLayers) => { - Tiles.MapRange(bbox.containingTileRange(self.osmSourceZoomLevel), (x, y) => { + onBboxLoaded: (bbox, date, downloadedLayers, paddedToZoomLevel) => { + Tiles.MapRange(bbox.containingTileRange(paddedToZoomLevel), (x, y) => { + const tileIndex = Tiles.tile_index(paddedToZoomLevel, x, y) downloadedLayers.forEach(layer => { - SaveTileToLocalStorageActor.MarkVisited(layer.id, Tiles.tile_index(this.osmSourceZoomLevel, x, y), date) + self.freshnesses.get(layer.id).addTileLoad(tileIndex, date) + SaveTileToLocalStorageActor.MarkVisited(layer.id, tileIndex, date) }) }) - }) + } }); @@ -379,7 +380,6 @@ export default class FeaturePipeline { private updateAllMetaTagging() { const self = this; - console.log("Reupdating all metatagging") this.perLayerHierarchy.forEach(hierarchy => { hierarchy.loadedTiles.forEach(src => { self.applyMetaTags(src) diff --git a/Logic/FeatureSource/TiledFeatureSource/TiledFromLocalStorageSource.ts b/Logic/FeatureSource/TiledFeatureSource/TiledFromLocalStorageSource.ts index 6f815f48d5..a2cd50be08 100644 --- a/Logic/FeatureSource/TiledFeatureSource/TiledFromLocalStorageSource.ts +++ b/Logic/FeatureSource/TiledFeatureSource/TiledFromLocalStorageSource.ts @@ -1,14 +1,16 @@ import FilteredLayer from "../../../Models/FilteredLayer"; import {FeatureSourceForLayer, Tiled} from "../FeatureSource"; import {UIEventSource} from "../../UIEventSource"; -import Loc from "../../../Models/Loc"; import TileHierarchy from "./TileHierarchy"; import SaveTileToLocalStorageActor from "../Actors/SaveTileToLocalStorageActor"; import {Tiles} from "../../../Models/TileRange"; import {BBox} from "../../BBox"; export default class TiledFromLocalStorageSource implements TileHierarchy { - public loadedTiles: Map = new Map(); + public readonly loadedTiles: Map = new Map(); + private readonly layer: FilteredLayer; + private readonly handleFeatureSource: (src: FeatureSourceForLayer & Tiled, index: number) => void; + private readonly undefinedTiles: Set; public static GetFreshnesses(layerId: string): Map { const prefix = SaveTileToLocalStorageActor.storageKey + "-" + layerId + "-" @@ -29,14 +31,15 @@ export default class TiledFromLocalStorageSource implements TileHierarchy void, state: { - locationControl: UIEventSource - leafletMap: any + currentBounds: UIEventSource }) { + this.layer = layer; + this.handleFeatureSource = handleFeatureSource; - const undefinedTiles = new Set() + + this.undefinedTiles = new Set() const prefix = SaveTileToLocalStorageActor.storageKey + "-" + layer.layerDef.id + "-" - // @ts-ignore - const indexes: number[] = Object.keys(localStorage) + const knownTiles: number[] = Object.keys(localStorage) .filter(key => { return key.startsWith(prefix) && !key.endsWith("-time") && !key.endsWith("-format"); }) @@ -45,8 +48,8 @@ export default class TiledFromLocalStorageSource implements TileHierarchy !isNaN(i)) - console.debug("Layer", layer.layerDef.id, "has following tiles in available in localstorage", indexes.map(i => Tiles.tile_from_index(i).join("/")).join(", ")) - for (const index of indexes) { + console.debug("Layer", layer.layerDef.id, "has following tiles in available in localstorage", knownTiles.map(i => Tiles.tile_from_index(i).join("/")).join(", ")) + for (const index of knownTiles) { const prefix = SaveTileToLocalStorageActor.storageKey + "-" + layer.layerDef.id + "-" + index; const version = localStorage.getItem(prefix + "-format") @@ -55,78 +58,54 @@ export default class TiledFromLocalStorageSource implements TileHierarchy i % 100) - const indexesSet = new Set(indexes) - const maxZoom = Math.max(...zLevels) - const minZoom = Math.min(...zLevels) - const self = this; + const self = this + state.currentBounds.map(bounds => { - const neededTiles = state.locationControl.map( - location => { - if (!layer.isDisplayed.data) { - // No need to download! - the layer is disabled - return undefined; - } - - if (location.zoom < layer.layerDef.minzoom) { - // No need to download! - the layer is disabled - return undefined; - } - - // Yup, this is cheating to just get the bounds here - const bounds = state.leafletMap.data?.getBounds() - if (bounds === undefined) { - // We'll retry later - return undefined - } - - const needed = [] - for (let z = minZoom; z <= maxZoom; z++) { - - const tileRange = Tiles.TileRangeBetween(z, bounds.getNorth(), bounds.getEast(), bounds.getSouth(), bounds.getWest()) - const neededZ = Tiles.MapRange(tileRange, (x, y) => Tiles.tile_index(z, x, y)) - .filter(i => !self.loadedTiles.has(i) && !undefinedTiles.has(i) && indexesSet.has(i)) - needed.push(...neededZ) - } - - if (needed.length === 0) { - return undefined - } - return needed + if(bounds === undefined){ + return; } - , [layer.isDisplayed, state.leafletMap]).stabilized(50); - - neededTiles.addCallbackAndRunD(neededIndexes => { - for (const neededIndex of neededIndexes) { - // We load the features from localStorage - try { - const key = SaveTileToLocalStorageActor.storageKey + "-" + layer.layerDef.id + "-" + neededIndex - const data = localStorage.getItem(key) - const features = JSON.parse(data) - const src = { - layer: layer, - features: new UIEventSource<{ feature: any; freshness: Date }[]>(features), - name: "FromLocalStorage(" + key + ")", - tileIndex: neededIndex, - bbox: BBox.fromTileIndex(neededIndex) - } - handleFeatureSource(src, neededIndex) - self.loadedTiles.set(neededIndex, src) - } catch (e) { - console.error("Could not load data tile from local storage due to", e) - undefinedTiles.add(neededIndex) + for (const knownTile of knownTiles) { + + if(this.loadedTiles.has(knownTile)){ + continue; } + if(this.undefinedTiles.has(knownTile)){ + continue; + } + + if(!bounds.overlapsWith(BBox.fromTileIndex(knownTile))){ + continue; + } + self.loadTile(knownTile) } - - }) } + + private loadTile( neededIndex: number){ + try { + const key = SaveTileToLocalStorageActor.storageKey + "-" + this.layer.layerDef.id + "-" + neededIndex + const data = localStorage.getItem(key) + const features = JSON.parse(data) + const src = { + layer: this.layer, + features: new UIEventSource<{ feature: any; freshness: Date }[]>(features), + name: "FromLocalStorage(" + key + ")", + tileIndex: neededIndex, + bbox: BBox.fromTileIndex(neededIndex) + } + this.handleFeatureSource(src, neededIndex) + this.loadedTiles.set(neededIndex, src) + } catch (e) { + console.error("Could not load data tile from local storage due to", e) + this.undefinedTiles.add(neededIndex) + } + } } \ No newline at end of file diff --git a/Models/Constants.ts b/Models/Constants.ts index 2b266f4ad5..c79773971a 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.10.4"; + public static vNumber = "0.10.5"; public static ImgurApiKey = '7070e7167f0a25a' public static readonly mapillary_client_token_v3 = 'TXhLaWthQ1d4RUg0czVxaTVoRjFJZzowNDczNjUzNmIyNTQyYzI2' public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85" diff --git a/Models/TileRange.ts b/Models/TileRange.ts index 7a542a2135..cccfe19643 100644 --- a/Models/TileRange.ts +++ b/Models/TileRange.ts @@ -15,7 +15,7 @@ export class Tiles { public static MapRange(tileRange: TileRange, f: (x: number, y: number) => T): T[] { const result: T[] = [] const total = tileRange.total - if(total > 5000){ + if(total > 100000){ throw "Tilerange too big" } for (let x = tileRange.xstart; x <= tileRange.xend; x++) { diff --git a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json index 7a401b0ab8..489c36ed7d 100644 --- a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json +++ b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json @@ -37,6 +37,7 @@ { "builtin": [ "bench", + "picnic_table", "waste_basket" ], "override": { From 6f0b951b3ac706bb5bd515dada20b6e919b044c6 Mon Sep 17 00:00:00 2001 From: Ahen Purwakarta Date: Fri, 8 Oct 2021 17:37:49 +0000 Subject: [PATCH 11/29] Translated using Weblate (Indonesian) Currently translated at 32.0% (8 of 25 strings) Translation: MapComplete/shared-questions Translate-URL: https://hosted.weblate.org/projects/mapcomplete/shared-questions/id/ --- langs/shared-questions/id.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/langs/shared-questions/id.json b/langs/shared-questions/id.json index 2af2d36ddc..3dc8ebac32 100644 --- a/langs/shared-questions/id.json +++ b/langs/shared-questions/id.json @@ -8,6 +8,17 @@ }, "website": { "question": "Apa situs web dari {name}?" + }, + "payment-options": { + "mappings": { + "1": { + "then": "Disini menerima pembayaran dengan kartu" + }, + "0": { + "then": "Disini menerima pembayaran tunai" + } + }, + "question": "Metode pembayaran manakah yang di terima disini?" } } -} \ No newline at end of file +} From af197d58f83f22f57c3487602586ac4f73690fb6 Mon Sep 17 00:00:00 2001 From: Andre Fajar N Date: Sat, 9 Oct 2021 09:41:06 +0000 Subject: [PATCH 12/29] Translated using Weblate (Indonesian) Currently translated at 32.0% (8 of 25 strings) Translation: MapComplete/shared-questions Translate-URL: https://hosted.weblate.org/projects/mapcomplete/shared-questions/id/ --- langs/shared-questions/id.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/langs/shared-questions/id.json b/langs/shared-questions/id.json index 3dc8ebac32..ba2382719a 100644 --- a/langs/shared-questions/id.json +++ b/langs/shared-questions/id.json @@ -19,6 +19,14 @@ } }, "question": "Metode pembayaran manakah yang di terima disini?" + }, + "level": { + "question": "Pada tingkat apa fitur ini diletakkan?", + "mappings": { + "3": { + "then": "Berlokasi di lantai pertama" + } + } } } } From 2d8b9a94810177ebae6337165e43e76ff20798b5 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 22:32:25 +0200 Subject: [PATCH 13/29] Linting of the postboxes theme --- .../Actors/SaveTileToLocalStorageActor.ts | 1 - .../postboxes_postoffices.json | 279 +++++++++--------- assets/themes/uk_addresses/uk_addresses.json | 4 +- 3 files changed, 146 insertions(+), 138 deletions(-) diff --git a/Logic/FeatureSource/Actors/SaveTileToLocalStorageActor.ts b/Logic/FeatureSource/Actors/SaveTileToLocalStorageActor.ts index 29086c9668..092c1a4023 100644 --- a/Logic/FeatureSource/Actors/SaveTileToLocalStorageActor.ts +++ b/Logic/FeatureSource/Actors/SaveTileToLocalStorageActor.ts @@ -4,7 +4,6 @@ * Technically, more an Actor then a featuresource, but it fits more neatly this ay */ import {FeatureSourceForLayer} from "../FeatureSource"; -import SimpleMetaTagger from "../../SimpleMetaTagger"; export default class SaveTileToLocalStorageActor { public static readonly storageKey: string = "cached-features"; diff --git a/assets/themes/postboxes_postoffices/postboxes_postoffices.json b/assets/themes/postboxes_postoffices/postboxes_postoffices.json index 8d7aa81ed8..7e9f6c8236 100644 --- a/assets/themes/postboxes_postoffices/postboxes_postoffices.json +++ b/assets/themes/postboxes_postoffices/postboxes_postoffices.json @@ -1,138 +1,145 @@ { - "id": "postboxes", - "title": { - "en": "Postbox and Post Office Map" - }, - "shortDescription": { - "en": "A map showing postboxes and post offices" - }, - "description": { - "en": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :) " - }, - "language": [ - "en" - ], - "maintainer": "", - "icon": "./assets/themes/postboxes_postoffices/postbox.svg", - "version": "0", - "startLat": 53.5511, - "startLon": 9.9937, - "startZoom": 13, - "widenFactor": 0.05, - "socialImage": "", - "layers": [{ - "id": "postboxes", - "name": { - "en": "Postbox" - }, - "minzoom": 12, - "overpassTags": { - "and": [ - "amenity=post_box" - ] - }, - "title": { - "render": { - "en": "Postbox" - } - }, - "description": { - "en": "The layer showing postboxes." - }, - "tagRenderings": [ - "images", - { - "render": "{minimap(18): height: 5rem; overflow: hidden; border-radius:3rem; }" - } - ], - "icon": { - "render": "./assets/themes/postboxes_postoffices/postbox.svg" - }, - "width": { - "render": "1" - }, - "iconSize": { - "render": "40,40,bottom" - }, - "color": { - "render": "#DADADA" - }, - "presets": [{ - "tags": [ - "amenity=post_box" - ], - "title": { - "en": "Postbox" - } - }], - "wayHandling": "both outline and center" - }, - { - "id": "postoffices", - "name": { - "en": "A layer containing post offices" - }, - "minzoom": 12, - "overpassTags": { - "and": [ - "amenity=post_office" - ] - }, - "title": { - "render": { - "en": "Post Office" - } - }, - "description": { - "en": "A layer showing post offices." - }, - "tagRenderings": [ - "images", - { - "render": "{minimap(18): height: 5rem; overflow: hidden; border-radius:3rem; }" - }, - { - "#": "OH", - "render": { - "en": "Opening Hours: {opening_hours}" - }, - "freeform": { - "key": "opening_hours", - "type": "opening_hours" - }, - "question": { - "en": "What are the opening hours for this post office?" - }, - "mappings": [{ - "if": "opening_hours=24/7", - "then": { - "en": "24/7 opened (including holidays)" - } - }] - } - ], - "icon": { - "render": "./assets/themes/postboxes_postoffices/post_office.svg" - }, - "width": { - "render": "1" - }, - "iconSize": { - "render": "40,40,bottom" - }, - "color": { - "render": "#DADADA" - }, - "presets": [{ - "tags": [ - "amenity=post_office" - ], - "title": { - "en": "Post Office" - } - }], - "wayHandling": 2 - } - ], - "roamingRenderings": [] + "id": "postboxes", + "title": { + "en": "Postbox and Post Office Map" + }, + "shortDescription": { + "en": "A map showing postboxes and post offices" + }, + "description": { + "en": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :) " + }, + "language": [ + "en" + ], + "maintainer": "", + "icon": "./assets/themes/postboxes_postoffices/postbox.svg", + "version": "0", + "startLat": 53.5511, + "startLon": 9.9937, + "startZoom": 13, + "widenFactor": 0.05, + "socialImage": "", + "layers": [ + { + "id": "postboxes", + "name": { + "en": "Postbox" + }, + "minzoom": 12, + "overpassTags": { + "and": [ + "amenity=post_box" + ] + }, + "title": { + "render": { + "en": "Postbox" + } + }, + "description": { + "en": "The layer showing postboxes." + }, + "tagRenderings": [ + "images", + { + "render": "{minimap(18): height: 5rem; overflow: hidden; border-radius:3rem; }" + } + ], + "icon": { + "render": "./assets/themes/postboxes_postoffices/postbox.svg" + }, + "width": { + "render": "1" + }, + "iconSize": { + "render": "40,40,bottom" + }, + "color": { + "render": "#DADADA" + }, + "presets": [ + { + "tags": [ + "amenity=post_box" + ], + "title": { + "en": "Postbox" + } + } + ], + "wayHandling": "both outline and center" + }, + { + "id": "postoffices", + "name": { + "en": "A layer containing post offices" + }, + "minzoom": 12, + "overpassTags": { + "and": [ + "amenity=post_office" + ] + }, + "title": { + "render": { + "en": "Post Office" + } + }, + "description": { + "en": "A layer showing post offices." + }, + "tagRenderings": [ + "images", + { + "render": "{minimap(18): height: 5rem; overflow: hidden; border-radius:3rem; }" + }, + { + "render": { + "en": "Opening Hours: {opening_hours}" + }, + "freeform": { + "key": "opening_hours", + "type": "opening_hours" + }, + "question": { + "en": "What are the opening hours for this post office?" + }, + "mappings": [ + { + "if": "opening_hours=24/7", + "then": { + "en": "24/7 opened (including holidays)" + } + } + ], + "id": "OH" + } + ], + "icon": { + "render": "./assets/themes/postboxes_postoffices/post_office.svg" + }, + "width": { + "render": "1" + }, + "iconSize": { + "render": "40,40,bottom" + }, + "color": { + "render": "#DADADA" + }, + "presets": [ + { + "tags": [ + "amenity=post_office" + ], + "title": { + "en": "Post Office" + } + } + ], + "wayHandling": 2 + } + ], + "roamingRenderings": [] } \ No newline at end of file diff --git a/assets/themes/uk_addresses/uk_addresses.json b/assets/themes/uk_addresses/uk_addresses.json index 296c125160..67cf0c6007 100644 --- a/assets/themes/uk_addresses/uk_addresses.json +++ b/assets/themes/uk_addresses/uk_addresses.json @@ -151,7 +151,9 @@ }, "freeform": { "key": "addr:housenumber", - "addExtraTags": ["nohousenumber="] + "addExtraTags": [ + "nohousenumber=" + ] }, "mappings": [ { From aa7a581faafa5fc6017f2b5aa36a8e75c072bdaa Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 22:43:32 +0200 Subject: [PATCH 14/29] Rename postboxes theme, small fixes to postboxes theme --- assets/themes/postboxes/license_info.json | 25 +++++++++++++ .../post_office.svg | 0 .../postbox.svg | 0 .../postboxes.json} | 35 ++++++++++--------- .../postboxes_postoffices/license_info.json | 15 -------- 5 files changed, 43 insertions(+), 32 deletions(-) create mode 100644 assets/themes/postboxes/license_info.json rename assets/themes/{postboxes_postoffices => postboxes}/post_office.svg (100%) rename assets/themes/{postboxes_postoffices => postboxes}/postbox.svg (100%) rename assets/themes/{postboxes_postoffices/postboxes_postoffices.json => postboxes/postboxes.json} (82%) delete mode 100644 assets/themes/postboxes_postoffices/license_info.json diff --git a/assets/themes/postboxes/license_info.json b/assets/themes/postboxes/license_info.json new file mode 100644 index 0000000000..0c50f7040e --- /dev/null +++ b/assets/themes/postboxes/license_info.json @@ -0,0 +1,25 @@ +[ + { + "path": "post_office.svg", + "license": "CC BY-SA 4.0", + "authors": [ + "https://github.com/emojione/emojione/graphs/contributors" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Emojione_BW_1F3E4.svg", + "https://github.com/emojione/emojione/blob/2.2.7/assets/svg_bw/1f3e4.svg" + ] + }, + { + "path": "postbox.svg", + "license": "CC BY 4.0", + "authors": [ + "Vincent Le Moign", + "https://twitter.com/webalys" + ], + "sources": [ + "https://upload.wikimedia.org/wikipedia/commons/6/6d/726-postbox.svg", + "http://emoji.streamlineicons.com" + ] + } +] \ No newline at end of file diff --git a/assets/themes/postboxes_postoffices/post_office.svg b/assets/themes/postboxes/post_office.svg similarity index 100% rename from assets/themes/postboxes_postoffices/post_office.svg rename to assets/themes/postboxes/post_office.svg diff --git a/assets/themes/postboxes_postoffices/postbox.svg b/assets/themes/postboxes/postbox.svg similarity index 100% rename from assets/themes/postboxes_postoffices/postbox.svg rename to assets/themes/postboxes/postbox.svg diff --git a/assets/themes/postboxes_postoffices/postboxes_postoffices.json b/assets/themes/postboxes/postboxes.json similarity index 82% rename from assets/themes/postboxes_postoffices/postboxes_postoffices.json rename to assets/themes/postboxes/postboxes.json index 7e9f6c8236..69425a32e0 100644 --- a/assets/themes/postboxes_postoffices/postboxes_postoffices.json +++ b/assets/themes/postboxes/postboxes.json @@ -13,13 +13,17 @@ "en" ], "maintainer": "", - "icon": "./assets/themes/postboxes_postoffices/postbox.svg", + "icon": "./assets/themes/postboxes/postbox.svg", "version": "0", "startLat": 53.5511, "startLon": 9.9937, "startZoom": 13, - "widenFactor": 0.05, + "widenFactor": 1.0, "socialImage": "", + "clustering": { + "minNeededFeatures": 100, + "maxZoom": 14 + }, "layers": [ { "id": "postboxes", @@ -27,10 +31,8 @@ "en": "Postbox" }, "minzoom": 12, - "overpassTags": { - "and": [ - "amenity=post_box" - ] + "source": { + "osmTags": "amenity=post_box" }, "title": { "render": { @@ -43,11 +45,12 @@ "tagRenderings": [ "images", { + "id": "minimap", "render": "{minimap(18): height: 5rem; overflow: hidden; border-radius:3rem; }" } ], "icon": { - "render": "./assets/themes/postboxes_postoffices/postbox.svg" + "render": "./assets/themes/postboxes/postbox.svg" }, "width": { "render": "1" @@ -64,11 +67,11 @@ "amenity=post_box" ], "title": { - "en": "Postbox" + "en": "postbox" } } ], - "wayHandling": "both outline and center" + "wayHandling": 2 }, { "id": "postoffices", @@ -76,10 +79,8 @@ "en": "A layer containing post offices" }, "minzoom": 12, - "overpassTags": { - "and": [ - "amenity=post_office" - ] + "source": { + "osmTags": "amenity=post_office" }, "title": { "render": { @@ -92,11 +93,12 @@ "tagRenderings": [ "images", { + "id": "minimap", "render": "{minimap(18): height: 5rem; overflow: hidden; border-radius:3rem; }" }, { "render": { - "en": "Opening Hours: {opening_hours}" + "en": "Opening Hours: {opening_hours_table()}" }, "freeform": { "key": "opening_hours", @@ -117,7 +119,7 @@ } ], "icon": { - "render": "./assets/themes/postboxes_postoffices/post_office.svg" + "render": "./assets/themes/postboxes/post_office.svg" }, "width": { "render": "1" @@ -140,6 +142,5 @@ ], "wayHandling": 2 } - ], - "roamingRenderings": [] + ] } \ No newline at end of file diff --git a/assets/themes/postboxes_postoffices/license_info.json b/assets/themes/postboxes_postoffices/license_info.json deleted file mode 100644 index 869dda32ca..0000000000 --- a/assets/themes/postboxes_postoffices/license_info.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "path": "postbox.svg", - "license": "CC BY 4.0", - "authors": ["Vincent Le Moign","https://twitter.com/webalys"], - "sources": ["https://upload.wikimedia.org/wikipedia/commons/6/6d/726-postbox.svg", "http://emoji.streamlineicons.com"] - }, - - { - "path": "post_office.svg", - "license": "CC BY-SA 4.0", - "authors": ["https://github.com/emojione/emojione/graphs/contributors"], - "sources": ["https://commons.wikimedia.org/wiki/File:Emojione_BW_1F3E4.svg", "https://github.com/emojione/emojione/blob/2.2.7/assets/svg_bw/1f3e4.svg"] - } - ] \ No newline at end of file From 92bbfa2279ea5a1eab065b62e60ccb7b2924801d Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 22:55:11 +0200 Subject: [PATCH 15/29] Small tweaks to the postboxes theme --- assets/themes/postboxes/postboxes.json | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/assets/themes/postboxes/postboxes.json b/assets/themes/postboxes/postboxes.json index 69425a32e0..ba7543274e 100644 --- a/assets/themes/postboxes/postboxes.json +++ b/assets/themes/postboxes/postboxes.json @@ -19,16 +19,16 @@ "startLon": 9.9937, "startZoom": 13, "widenFactor": 1.0, - "socialImage": "", + "defaultBackgroundId": "CartoDB.Voyager", "clustering": { - "minNeededFeatures": 100, - "maxZoom": 14 + "maxZoom": 14, + "minNeededObjects": 100 }, "layers": [ { "id": "postboxes", "name": { - "en": "Postbox" + "en": "Postboxes" }, "minzoom": 12, "source": { @@ -71,12 +71,20 @@ } } ], - "wayHandling": 2 + "wayHandling": 2, + "deletion": { + "softDeletion": { + "and": [ + "amenity=", + "razed:amenity=post_box" + ] + } + } }, { "id": "postoffices", "name": { - "en": "A layer containing post offices" + "en": "Post offices" }, "minzoom": 12, "source": { From f897022ba00a8d4677671fd01486f39ebd41841b Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 23:09:50 +0200 Subject: [PATCH 16/29] Add isOpen badge and filter, add square background to post offices --- assets/themes/postboxes/postboxes.json | 30 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/assets/themes/postboxes/postboxes.json b/assets/themes/postboxes/postboxes.json index ba7543274e..f19df492e6 100644 --- a/assets/themes/postboxes/postboxes.json +++ b/assets/themes/postboxes/postboxes.json @@ -7,7 +7,7 @@ "en": "A map showing postboxes and post offices" }, "description": { - "en": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :) " + "en": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :)
Spotted an error or is a post box missing? You can edit this map with a free OpenStreetMap account. " }, "language": [ "en" @@ -18,11 +18,11 @@ "startLat": 53.5511, "startLon": 9.9937, "startZoom": 13, - "widenFactor": 1.0, + "widenFactor": 1.5, "defaultBackgroundId": "CartoDB.Voyager", "clustering": { "maxZoom": 14, - "minNeededObjects": 100 + "minNeededElements": 100 }, "layers": [ { @@ -127,8 +127,15 @@ } ], "icon": { - "render": "./assets/themes/postboxes/post_office.svg" + "render": "square:white;./assets/themes/postboxes/post_office.svg" }, + "iconOverlays": [ + { + "if": "opening_hours~*", + "then": "isOpen", + "badge": true + } + ], "width": { "render": "1" }, @@ -148,7 +155,20 @@ } } ], - "wayHandling": 2 + "wayHandling": 2, + "filter": [ + { + "id": "is_open", + "options": [ + { + "question": { + "en": "Currently open" + }, + "osmTags": "_isOpen=yes" + } + ] + } + ] } ] } \ No newline at end of file From a38ab81356c28d34648cf2ac9fa1dce659a5d941 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 23:28:51 +0200 Subject: [PATCH 17/29] Fix metatag _isOpen, fix clustering zoom behaviour --- InitUiElements.ts | 2 +- Logic/SimpleMetaTagger.ts | 7 ++++--- UI/SpecialVisualizations.ts | 6 +++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/InitUiElements.ts b/InitUiElements.ts index dfd5b44396..e7113e2d68 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -454,7 +454,7 @@ export class InitUiElements { return false; } - if (z >= clustering.maxZoom) { + if (z > clustering.maxZoom) { return true } diff --git a/Logic/SimpleMetaTagger.ts b/Logic/SimpleMetaTagger.ts index 4cf5a8c471..b0e4d50bfb 100644 --- a/Logic/SimpleMetaTagger.ts +++ b/Logic/SimpleMetaTagger.ts @@ -209,7 +209,7 @@ export default class SimpleMetaTagger { configurable: true, get: () => { delete feature.properties._isOpen - feature.properties._isOpen = "" + feature.properties._isOpen = undefined const tagsSource = State.state.allElements.getEventSourceById(feature.properties.id); tagsSource.addCallbackAndRunD(tags => { if (tags.opening_hours === undefined || tags._country === undefined) { @@ -230,7 +230,8 @@ export default class SimpleMetaTagger { const oldNextChange = tags["_isOpen:nextTrigger"] ?? 0; if (oldNextChange > (new Date()).getTime() && - tags["_isOpen:oldvalue"] === tags["opening_hours"]) { + tags["_isOpen:oldvalue"] === tags["opening_hours"] + && tags["_isOpen"] !== undefined) { // Already calculated and should not yet be triggered return false; } @@ -267,7 +268,7 @@ export default class SimpleMetaTagger { } }) - return feature.properties["_isOpen"] + return undefined } }) diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index bc41f916c0..9cdadec046 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -55,7 +55,11 @@ export default class SpecialVisualizations { if (!tags.hasOwnProperty(key)) { continue } - parts.push([key, tags[key] ?? "undefined"]); + let v = tags[key] + if(v === ""){ + v = "empty string" + } + parts.push([key, v ?? "undefined"]); } for(const key of calculatedTags){ From e82f9290530c869973fb1d41bcf1d40e0c1cef3f Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 23:44:01 +0200 Subject: [PATCH 18/29] Translation regeneration --- assets/tagRenderings/questions.json | 30 +++++++++++------ langs/shared-questions/id.json | 40 +++++++++++----------- langs/shared-questions/pt.json | 36 ++++++++++---------- langs/themes/en.json | 51 +++++++++++++++++++++++++++++ langs/themes/nl.json | 1 + 5 files changed, 110 insertions(+), 48 deletions(-) diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index 509749aa03..30b6e90c6e 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -156,35 +156,40 @@ "dog-access": { "question": { "en": "Are dogs allowed in this business?", - "nl": "Zijn honden toegelaten in deze zaak?" + "nl": "Zijn honden toegelaten in deze zaak?", + "pt": "Os cães são permitidos neste estabelecimento?" }, "mappings": [ { "if": "dog=yes", "then": { "en": "Dogs are allowed", - "nl": "honden zijn toegelaten" + "nl": "honden zijn toegelaten", + "pt": "Os cães são permitidos" } }, { "if": "dog=no", "then": { "en": "Dogs are not allowed", - "nl": "honden zijn niet toegelaten" + "nl": "honden zijn niet toegelaten", + "pt": "Os cães não são permitidos" } }, { "if": "dog=leashed", "then": { "en": "Dogs are allowed, but they have to be leashed", - "nl": "honden zijn enkel aan de leiband welkom" + "nl": "honden zijn enkel aan de leiband welkom", + "pt": "Os cães são permitidos, mas têm de ser presos pela trela" } }, { "if": "dog=unleashed", "then": { "en": "Dogs are allowed and can run around freely", - "nl": "honden zijn welkom en mogen vrij rondlopen" + "nl": "honden zijn welkom en mogen vrij rondlopen", + "pt": "Os cães são permitidos e podem correr livremente" } } ] @@ -247,7 +252,8 @@ "en": "Which methods of payment are accepted here?", "nl": "Welke betaalmiddelen worden hier geaccepteerd?", "pt": "Que métodos de pagamento são aceites aqui?", - "pt_BR": "Quais métodos de pagamento são aceitos aqui?" + "pt_BR": "Quais métodos de pagamento são aceitos aqui?", + "id": "Metode pembayaran manakah yang di terima disini?" }, "multiAnswer": true, "mappings": [ @@ -258,7 +264,8 @@ "en": "Cash is accepted here", "nl": "Cash geld wordt hier aanvaard", "pt": "Aceitam pagamento com dinheiro aqui", - "pt_BR": "Dinheiro é aceito aqui" + "pt_BR": "Dinheiro é aceito aqui", + "id": "Disini menerima pembayaran tunai" } }, { @@ -268,7 +275,8 @@ "en": "Payment cards are accepted here", "nl": "Betalen met bankkaarten kan hier", "pt": "Aceitam pagamento com cartões bancários aqui", - "pt_BR": "Cartões de pagamento são aceitos aqui" + "pt_BR": "Cartões de pagamento são aceitos aqui", + "id": "Disini menerima pembayaran dengan kartu" } } ] @@ -292,7 +300,8 @@ "pl": "Na jakim poziomie znajduje się ta funkcja?", "pt_BR": "Em que nível esse recurso está localizado?", "ru": "На каком этаже находится этот объект?", - "pt": "Em que nível se encontra este elemento?" + "pt": "Em que nível se encontra este elemento?", + "id": "Pada tingkat apa fitur ini diletakkan?" }, "render": { "en": "Located on the {level}th floor", @@ -369,7 +378,8 @@ "fr": "Premier étage", "pl": "Znajduje się na pierwszym piętrze", "sv": "Ligger på första våningen", - "pt": "Está no primeiro andar" + "pt": "Está no primeiro andar", + "id": "Berlokasi di lantai pertama" } } ] diff --git a/langs/shared-questions/id.json b/langs/shared-questions/id.json index ba2382719a..7c29ed6e61 100644 --- a/langs/shared-questions/id.json +++ b/langs/shared-questions/id.json @@ -3,30 +3,30 @@ "email": { "question": "Apa alamat surel dari {name}?" }, + "level": { + "mappings": { + "3": { + "then": "Berlokasi di lantai pertama" + } + }, + "question": "Pada tingkat apa fitur ini diletakkan?" + }, + "payment-options": { + "mappings": { + "0": { + "then": "Disini menerima pembayaran tunai" + }, + "1": { + "then": "Disini menerima pembayaran dengan kartu" + } + }, + "question": "Metode pembayaran manakah yang di terima disini?" + }, "phone": { "question": "Nomor telepon dari {name|?" }, "website": { "question": "Apa situs web dari {name}?" - }, - "payment-options": { - "mappings": { - "1": { - "then": "Disini menerima pembayaran dengan kartu" - }, - "0": { - "then": "Disini menerima pembayaran tunai" - } - }, - "question": "Metode pembayaran manakah yang di terima disini?" - }, - "level": { - "question": "Pada tingkat apa fitur ini diletakkan?", - "mappings": { - "3": { - "then": "Berlokasi di lantai pertama" - } - } } } -} +} \ No newline at end of file diff --git a/langs/shared-questions/pt.json b/langs/shared-questions/pt.json index a1622b21a3..fbd7309863 100644 --- a/langs/shared-questions/pt.json +++ b/langs/shared-questions/pt.json @@ -3,6 +3,23 @@ "description": { "question": "Ainda há algo de relevante que não tenha podido dar nas perguntas anteriores? Adicione-o aqui.
Não repita factos já declarados" }, + "dog-access": { + "mappings": { + "0": { + "then": "Os cães são permitidos" + }, + "1": { + "then": "Os cães não são permitidos" + }, + "2": { + "then": "Os cães são permitidos, mas têm de ser presos pela trela" + }, + "3": { + "then": "Os cães são permitidos e podem correr livremente" + } + }, + "question": "Os cães são permitidos neste estabelecimento?" + }, "email": { "question": "Qual é o endereço de e-mail de {name}?" }, @@ -61,23 +78,6 @@ } }, "question": "Este lugar é acessível a utilizadores de cadeiras de rodas?" - }, - "dog-access": { - "mappings": { - "0": { - "then": "Os cães são permitidos" - }, - "1": { - "then": "Os cães não são permitidos" - }, - "2": { - "then": "Os cães são permitidos, mas têm de ser presos pela trela" - }, - "3": { - "then": "Os cães são permitidos e podem correr livremente" - } - }, - "question": "Os cães são permitidos neste estabelecimento?" } } -} +} \ No newline at end of file diff --git a/langs/themes/en.json b/langs/themes/en.json index e1d8f67241..ea1aecd5e9 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -1240,6 +1240,57 @@ "shortDescription": "A map with playgrounds", "title": "Playgrounds" }, + "postboxes": { + "description": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :)
Spotted an error or is a post box missing? You can edit this map with a free OpenStreetMap account. ", + "layers": { + "0": { + "description": "The layer showing postboxes.", + "name": "Postboxes", + "presets": { + "0": { + "title": "postbox" + } + }, + "title": { + "render": "Postbox" + } + }, + "1": { + "description": "A layer showing post offices.", + "filter": { + "0": { + "options": { + "0": { + "question": "Currently open" + } + } + } + }, + "name": "Post offices", + "presets": { + "0": { + "title": "Post Office" + } + }, + "tagRenderings": { + "OH": { + "mappings": { + "0": { + "then": "24/7 opened (including holidays)" + } + }, + "question": "What are the opening hours for this post office?", + "render": "Opening Hours: {opening_hours_table()}" + } + }, + "title": { + "render": "Post Office" + } + } + }, + "shortDescription": "A map showing postboxes and post offices", + "title": "Postbox and Post Office Map" + }, "shops": { "description": "On this map, one can mark basic information about shops, add opening hours and phone numbers", "layers": { diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 409d96feaa..991614fad2 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -1025,6 +1025,7 @@ }, "toerisme_vlaanderen": { "description": "Op deze kaart kan je info zien die relevant is voor toerisme, zoals:
  • Eetgelegenheden
  • Cafés en bars
  • (Fiets)oplaadpunten
  • Fietspompen, fietserverhuur en fietswinkels
  • Uitkijktorens
  • ...
Zie je fouten op de kaart? Dan kan je zelf makkelijk aanpasingen maken, die zichtbaar zijn voor iedereen. Hiervoor dien je een gratis OpenStreetMap account voor te maken.

Met de steun van Toerisme Vlaanderen", + "descriptionTail": "Met de steun van Toerisme Vlaanderen", "shortDescription": "Een kaart om toeristisch relevante info op aan te duiden", "title": "Toeristisch relevante info" }, From dce43b4556514e040c785fc583292b4c3d987a00 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 23:46:37 +0200 Subject: [PATCH 19/29] Use correct deletion configuration --- assets/themes/postboxes/postboxes.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/themes/postboxes/postboxes.json b/assets/themes/postboxes/postboxes.json index f19df492e6..d90c5a1c39 100644 --- a/assets/themes/postboxes/postboxes.json +++ b/assets/themes/postboxes/postboxes.json @@ -73,7 +73,7 @@ ], "wayHandling": 2, "deletion": { - "softDeletion": { + "softDeletionTags": { "and": [ "amenity=", "razed:amenity=post_box" From 28ed52d4a961e120180102d6842e91d0b64203cb Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 11 Oct 2021 23:46:58 +0200 Subject: [PATCH 20/29] Documentation regeneration --- Docs/CalculatedTags.md | 50 +++++++++++++++++++++++++-------------- Docs/SpecialRenderings.md | 38 +++++++++++++++++++---------- Docs/URL_Parameters.md | 2 +- 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/Docs/CalculatedTags.md b/Docs/CalculatedTags.md index 8d8973b7b7..08083a10f4 100644 --- a/Docs/CalculatedTags.md +++ b/Docs/CalculatedTags.md @@ -26,12 +26,16 @@ The following values are always calculated, by default, by MapComplete and are a The latitude and longitude of the point (or centerpoint in the case of a way/area) + + ### _surface, _surface:ha The surface area of the feature, in square meters and in hectare. Not set on points and ways +This is a lazy metatag and is only calculated when needed + ### _length, _length:km @@ -40,6 +44,8 @@ The surface area of the feature, in square meters and in hectare. Not set on poi The total length of a feature in meters (and in kilometers, rounded to one decimal for '_length:km'). For a surface, the length of the perimeter + + ### Theme-defined keys @@ -47,6 +53,8 @@ The total length of a feature in meters (and in kilometers, rounded to one decim If 'units' is defined in the layoutConfig, then this metatagger will rewrite the specified keys to have the canonical form (e.g. `1meter` will be rewritten to `1m`) + + ### _country @@ -54,18 +62,15 @@ If 'units' is defined in the layoutConfig, then this metatagger will rewrite the The country code of the property (with latlon2country) + + ### _isOpen, _isOpen:description If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no') - -### _width:needed, _width:needed:no_pedestrians, _width:difference - - - -Legacy for a specific project calculating the needed width for safe traffic on a road. Only activated if 'width:carriageway' is present +This is a lazy metatag and is only calculated when needed ### _direction:numerical, _direction:leftright @@ -75,6 +80,8 @@ Legacy for a specific project calculating the needed width for safe traffic on a _direction:numerical is a normalized, numerical direction based on 'camera:direction' or on 'direction'; it is only present if a valid direction is found (e.g. 38.5 or NE). _direction:leftright is either 'left' or 'right', which is left-looking on the map or 'right-looking' on the map + + ### _now:date, _now:datetime, _loaded:date, _loaded:_datetime @@ -82,6 +89,8 @@ _direction:numerical is a normalized, numerical direction based on 'camera:direc Adds the time that the data got loaded - pretty much the time of downloading from overpass. The format is YYYY-MM-DD hh:mm, aka 'sortable' aka ISO-8601-but-not-entirely + + ### _last_edit:contributor, _last_edit:contributor:uid, _last_edit:changeset, _last_edit:timestamp, _version_number @@ -89,6 +98,8 @@ Adds the time that the data got loaded - pretty much the time of downloading fro Information about the last edit of this object. + + Calculating tags with Javascript ---------------------------------- @@ -140,15 +151,15 @@ Some advanced functions are available on **feat** as well: - distanceTo - overlapWith - closest + - closestn - memberships - - score ### distanceTo 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 - 0. longitude - 1. latitude + 0. feature OR featureID OR longitude + 1. undefined OR latitude ### overlapWith @@ -160,10 +171,21 @@ For example to get all objects which overlap or embed from a layer, use `_contai ### closest - 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. + 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 laoded) 0. list of features +### closestn + + 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) + +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) + + 0. list of features or layer name + 1. amount of features + 2. unique tag key (optional) + 3. maxDistanceInMeters (optional) + ### memberships Gives a list of `{role: string, relation: Relation}`-objects, containing all the relations that this feature is part of. @@ -171,12 +193,4 @@ For example to get all objects which overlap or embed from a layer, use `_contai For example: `_part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')` - -### score - - Given the path of an aspected routing json file, will calculate the score. This score is wrapped in a UIEventSource, so for further calculations, use `.map(score => ...)` - -For example: `_comfort_score=feat.score('https://raw.githubusercontent.com/pietervdvn/AspectedRouting/master/Examples/bicycle/aspects/bicycle.comfort.json')` - - 0. path Generated from SimpleMetaTagger, ExtraFunction \ No newline at end of file diff --git a/Docs/SpecialRenderings.md b/Docs/SpecialRenderings.md index da4a4bc204..f5ca4d6e81 100644 --- a/Docs/SpecialRenderings.md +++ b/Docs/SpecialRenderings.md @@ -5,11 +5,6 @@ ### all_tags Prints all key-value pairs of the object - used for debugging - -name | default | description ------- | --------- | ------------- - - #### Example usage `{all_tags()}` @@ -20,11 +15,10 @@ name | default | description name | default | description ------ | --------- | ------------- image key/prefix | image | The keys given to the images, e.g. if image is given, the first picture URL will be added as image, the second as image:0, the third as image:1, etc... -smart search | true | Also include images given via 'Wikidata', 'wikimedia_commons' and 'mapillary #### Example usage - `{image_carousel(image,true)}` + `{image_carousel(image)}` ### image_upload Creates a button where a user can upload an image to IMGUR @@ -36,6 +30,17 @@ image-key | image | Image tag to add the URL to (or image-tag:0, image-tag:1 whe #### Example usage `{image_upload(image)}` +### wikipedia + + A box showing the corresponding wikipedia article - based on the wikidata tag + +name | default | description +------ | --------- | ------------- +keyToShowWikipediaFor | wikidata | Use the wikidata entry from this key to show the wikipedia article for + +#### Example usage + + `{wikipedia()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the wikipedia page of whom the feature was named after. Also remember that these can be styled, e.g. `{wikipedia():max-height: 10rem}` to limit the height ### minimap A small map showing the selected feature. Note that no styling is applied, wrap this in a div @@ -128,16 +133,25 @@ If you want to import a dataset, make sure that: 1. The dataset to import has a suitable license 2. The community has been informed of the import -3. The theme will filter out duplicate nodes4. All other requirements of the [import guidelines](https://wiki.openstreetmap.org/wiki/Import/Guidelines) have been followed +3. All other requirements of the [import guidelines](https://wiki.openstreetmap.org/wiki/Import/Guidelines) have been followed + +There are also some technicalities in your theme to keep in mind: + +1. The new point will be added and will flow through the program as any other new point as if it came from OSM. + This means that there should be a layer which will match the new tags and which will display it. +2. The original point from your geojson layer will gain the tag '_imported=yes'. + This should be used to change the appearance or even to hide it (eg by changing the icon size to zero) +3. There should be a way for the theme to detect previously imported points, even after reloading. + A reference number to the original dataset is an excellen way to do this + name | default | description ------ | --------- | ------------- -tags | undefined | Tags to copy-specification. This contains one or more pairs (seperated by a `;`), e.g. `amenity=fast_food; addr:housenumber={number}`. This new point will then have the tags `amenity=fast_food` and `addr:housenumber` with the value that was saved in `number` in the original feature. (Hint: prepare these values, e.g. with calculatedTags) +tags | undefined | Tags to copy-specification. This contains one or more pairs (seperated by a `;`), e.g. `amenity=fast_food; addr:housenumber=$number`. This new point will then have the tags `amenity=fast_food` and `addr:housenumber` with the value that was saved in `number` in the original feature. (Hint: prepare these values, e.g. with calculatedTags) text | Import this data into OpenStreetMap | The text to show on the button icon | ./assets/svg/addSmall.svg | A nice icon to show in the button +minzoom | 18 | How far the contributor must zoom in before being able to import the point #### Example usage - `{import_button(,Import this data into OpenStreetMap,./assets/svg/addSmall.svg)}` - -Generated from UI/SpecialVisualisations.ts \ No newline at end of file + `{import_button(,Import this data into OpenStreetMap,./assets/svg/addSmall.svg,18)}` Generated from UI/SpecialVisualisations.ts \ No newline at end of file diff --git a/Docs/URL_Parameters.md b/Docs/URL_Parameters.md index f353809015..bd363df9b7 100644 --- a/Docs/URL_Parameters.md +++ b/Docs/URL_Parameters.md @@ -161,7 +161,7 @@ Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case. overpassUrl ------------- - Point mapcomplete to a different overpass-instance. Example: https://overpass-api.de/api/interpreter The default value is _https://overpass-api.de/api/interpreter_ + Point mapcomplete to a different overpass-instance. Example: https://overpass-api.de/api/interpreter The default value is _https://overpass-api.de/api/interpreter,https://overpass.kumi.systems/api/interpreter,https://overpass.openstreetmap.ru/cgi/interpreter_ overpassTimeout From b7e5990aa906d076110712bee824a7ad5e5f86d4 Mon Sep 17 00:00:00 2001 From: Joost Date: Tue, 12 Oct 2021 09:10:49 +0200 Subject: [PATCH 21/29] Changed "quest" to "theme" Because nowhere else do we call themes quests --- langs/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/langs/en.json b/langs/en.json index 9282ad4465..5a4854db70 100644 --- a/langs/en.json +++ b/langs/en.json @@ -120,7 +120,7 @@ }, "morescreen": { "intro": "

More thematic maps?

Do you enjoy collecting geodata?
There are more themes available.", - "requestATheme": "If you want a custom-built quest, request it in the issue tracker", + "requestATheme": "If you want a custom-built theme, request it in the issue tracker", "streetcomplete": "Another, similar application is StreetComplete.", "createYourOwnTheme": "Create your own MapComplete theme from scratch" }, @@ -247,4 +247,4 @@ "attribution": "Reviews are powered by Mangrove Reviews and are available under CC-BY 4.0.", "plz_login": "Login to leave a review" } -} \ No newline at end of file +} From e67c3a2eec7e2673020ee42ca2d7799f6387aa72 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Tue, 12 Oct 2021 15:19:27 +0200 Subject: [PATCH 22/29] Fixed build for monolignual themes --- UI/BigComponents/ThemeIntroductionPanel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/BigComponents/ThemeIntroductionPanel.ts b/UI/BigComponents/ThemeIntroductionPanel.ts index c7c0964210..ae37813252 100644 --- a/UI/BigComponents/ThemeIntroductionPanel.ts +++ b/UI/BigComponents/ThemeIntroductionPanel.ts @@ -54,7 +54,7 @@ export default class ThemeIntroductionPanel extends Combine { toTheMap, loginStatus.SetClass("block"), layout.descriptionTail?.Clone().SetClass("block mt-4"), - languagePicker.SetClass("block mt-4"), + languagePicker?.SetClass("block mt-4"), ...layout.CustomCodeSnippets() ]) From e530eba55ab9c278d35a7f283d099cd556fc6efc Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Tue, 12 Oct 2021 16:39:36 +0200 Subject: [PATCH 23/29] Quickfix: disable optimazation which blocks loading dynamic tiles --- .../TiledFeatureSource/DynamicGeoJsonTileSource.ts | 3 ++- assets/themes/natuurpunt/natuurpunt.json | 2 +- index.ts | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Logic/FeatureSource/TiledFeatureSource/DynamicGeoJsonTileSource.ts b/Logic/FeatureSource/TiledFeatureSource/DynamicGeoJsonTileSource.ts index fcfdbea5a4..c2ccf518d8 100644 --- a/Logic/FeatureSource/TiledFeatureSource/DynamicGeoJsonTileSource.ts +++ b/Logic/FeatureSource/TiledFeatureSource/DynamicGeoJsonTileSource.ts @@ -46,7 +46,8 @@ export default class DynamicGeoJsonTileSource extends DynamicTileSource { if(whitelist !== undefined){ const isWhiteListed = whitelist.get(zxy[1])?.has(zxy[2]) if(!isWhiteListed){ - return undefined; + console.log("Not whitelisted:",zxy, isWhiteListed, whitelist) + // return undefined; } } diff --git a/assets/themes/natuurpunt/natuurpunt.json b/assets/themes/natuurpunt/natuurpunt.json index 4b49e7465f..fb45742cae 100644 --- a/assets/themes/natuurpunt/natuurpunt.json +++ b/assets/themes/natuurpunt/natuurpunt.json @@ -34,7 +34,7 @@ "hideFromOverview": true, "clustering": { "#": "Disable clustering for this theme", - "maxZoom": 0 + "maxZoom": 1 }, "layers": [ { diff --git a/index.ts b/index.ts index e5e58a6f0a..dc738eaf4f 100644 --- a/index.ts +++ b/index.ts @@ -63,6 +63,9 @@ if (path !== "index.html" && path !== "") { defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout, "The layout to load into MapComplete").data; let layoutToUse: LayoutConfig = AllKnownLayouts.allKnownLayouts.get(defaultLayout.toLowerCase()); +if(layoutToUse.id === "natuurpunt"){ + localStorage.clear() +} const userLayoutParam = QueryParameters.GetQueryParameter("userlayout", "false", "If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways: \n\n- The hash of the URL contains a base64-encoded .json-file containing the theme definition\n- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator\n- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme"); From e5a24ff499e04e874edd32b8da07359ac5f81294 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Tue, 12 Oct 2021 19:11:48 +0200 Subject: [PATCH 24/29] Fix build --- index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.ts b/index.ts index dc738eaf4f..3bfa4f28b9 100644 --- a/index.ts +++ b/index.ts @@ -63,7 +63,7 @@ if (path !== "index.html" && path !== "") { defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout, "The layout to load into MapComplete").data; let layoutToUse: LayoutConfig = AllKnownLayouts.allKnownLayouts.get(defaultLayout.toLowerCase()); -if(layoutToUse.id === "natuurpunt"){ +if(layoutToUse?.id === "natuurpunt"){ localStorage.clear() } From 2bcc573f2a148952b9c997ec7683956682da371f Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Tue, 12 Oct 2021 19:11:59 +0200 Subject: [PATCH 25/29] Fix build --- index.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/index.ts b/index.ts index 3bfa4f28b9..7126a0a7cc 100644 --- a/index.ts +++ b/index.ts @@ -63,10 +63,6 @@ if (path !== "index.html" && path !== "") { defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout, "The layout to load into MapComplete").data; let layoutToUse: LayoutConfig = AllKnownLayouts.allKnownLayouts.get(defaultLayout.toLowerCase()); -if(layoutToUse?.id === "natuurpunt"){ - localStorage.clear() -} - const userLayoutParam = QueryParameters.GetQueryParameter("userlayout", "false", "If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways: \n\n- The hash of the URL contains a base64-encoded .json-file containing the theme definition\n- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator\n- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme"); // Workaround/legacy to keep the old paramters working as I renamed some of them From 8bdabe5d73447a2e32208230e90917f588762af9 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 13 Oct 2021 00:08:41 +0200 Subject: [PATCH 26/29] Fixes to caching --- .../DynamicGeoJsonTileSource.ts | 4 +- scripts/generateCache.ts | 40 +++++++++++++------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/Logic/FeatureSource/TiledFeatureSource/DynamicGeoJsonTileSource.ts b/Logic/FeatureSource/TiledFeatureSource/DynamicGeoJsonTileSource.ts index c2ccf518d8..fc110e1c2c 100644 --- a/Logic/FeatureSource/TiledFeatureSource/DynamicGeoJsonTileSource.ts +++ b/Logic/FeatureSource/TiledFeatureSource/DynamicGeoJsonTileSource.ts @@ -21,7 +21,9 @@ export default class DynamicGeoJsonTileSource extends DynamicTileSource { throw "Invalid layer: geojsonSource expected" } - const whitelistUrl = source.geojsonSource.replace("{z}_{x}_{y}.geojson", "overview.json") + const whitelistUrl = source.geojsonSource + .replace("{z}", ""+source.geojsonZoomLevel) + .replace("{x}_{y}.geojson", "overview.json") .replace("{layer}",layer.layerDef.id) let whitelist = undefined diff --git a/scripts/generateCache.ts b/scripts/generateCache.ts index 1377b3153e..d92fc86288 100644 --- a/scripts/generateCache.ts +++ b/scripts/generateCache.ts @@ -20,6 +20,7 @@ import FeatureSource, {FeatureSourceForLayer} from "../Logic/FeatureSource/Featu import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource"; import TiledFeatureSource from "../Logic/FeatureSource/TiledFeatureSource/TiledFeatureSource"; import Constants from "../Models/Constants"; +import {GeoOperations} from "../Logic/GeoOperations"; ScriptUtils.fixUtils() @@ -170,11 +171,11 @@ function loadAllTiles(targetdir: string, r: TileRange, theme: LayoutConfig, extr /** * Load all the tiles into memory from disk */ -function postProcess(allFeatures: FeatureSource, theme: LayoutConfig, relationsTracker: RelationsTracker, targetdir: string) { - - +function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relationsTracker: RelationsTracker, targetdir: string, pointsOnlyLayers: string[]) { function handleLayer(source: FeatureSourceForLayer) { const layer = source.layer.layerDef; + const targetZoomLevel = layer.source.geojsonZoomLevel ?? 0 + const layerId = layer.id if (layer.source.isOsmCacheLayer !== true) { return; @@ -200,13 +201,10 @@ function postProcess(allFeatures: FeatureSource, theme: LayoutConfig, relationsT // At this point, we have all the features of the entire area. // However, we want to export them per tile of a fixed size, so we use a dynamicTileSOurce to split it up TiledFeatureSource.createHierarchy(source, { - minZoomLevel: 14, - maxZoomLevel: 14, + minZoomLevel: targetZoomLevel, + maxZoomLevel: targetZoomLevel, maxFeatureCount: undefined, registerTile: tile => { - if (tile.z < 12) { - return; - } if (tile.features.data.length === 0) { return } @@ -229,7 +227,7 @@ function postProcess(allFeatures: FeatureSource, theme: LayoutConfig, relationsT // All the tiles are written at this point // Only thing left to do is to create the index - const path = targetdir + "_" + layerId + "_overview.json" + const path = targetdir + "_" + layerId + "_" + targetZoomLevel + "_overview.json" const perX = {} createdTiles.map(i => Tiles.tile_from_index(i)).forEach(([z, x, y]) => { const key = "" + x @@ -240,7 +238,18 @@ function postProcess(allFeatures: FeatureSource, theme: LayoutConfig, relationsT }) writeFileSync(path, JSON.stringify(perX)) - + // And, if needed, to create a points-only layer + if(pointsOnlyLayers.indexOf(layer.id) >= 0){ + const features = source.features.data.map(f => f.feature) + const points = features.map(feature => GeoOperations.centerpoint(feature)) + console.log("Writing points overview for ", layerId) + const targetPath = targetdir+"_"+layerId+"_points.geojson" + // This is the geojson file containing all features for this tile + writeFileSync(targetPath, JSON.stringify({ + type: "FeatureCollection", + features: points + }, null, " ")) + } } new PerLayerFeatureSourceSplitter( @@ -255,10 +264,11 @@ function postProcess(allFeatures: FeatureSource, theme: LayoutConfig, relationsT } + async function main(args: string[]) { if (args.length == 0) { - console.error("Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name]") + console.error("Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...]") return; } const themeName = args[0] @@ -268,6 +278,12 @@ async function main(args: string[]) { const lon0 = Number(args[4]) const lat1 = Number(args[5]) const lon1 = Number(args[6]) + + let generatePointLayersFor = [] + if(args[7] == "--generate-point-overview"){ + generatePointLayersFor = args[8].split(",") + } + const tileRange = Tiles.TileRangeBetween(zoomlevel, lat0, lon0, lat1, lon1) @@ -293,7 +309,7 @@ async function main(args: string[]) { const extraFeatures = await downloadExtraData(theme); const allFeaturesSource = loadAllTiles(targetdir, tileRange, theme, extraFeatures) - postProcess(allFeaturesSource, theme, relationTracker, targetdir) + sliceToTiles(allFeaturesSource, theme, relationTracker, targetdir, generatePointLayersFor) } From 9e7dec010163d11c17ba4370ec8da119b34e21b8 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 13 Oct 2021 00:43:19 +0200 Subject: [PATCH 27/29] Add toggle to disable squares on low zoom levels, fix maxzoom property --- InitUiElements.ts | 32 ++++++++++++--------- Models/ThemeConfig/Json/LayoutConfigJson.ts | 8 +++++- Models/ThemeConfig/LayoutConfig.ts | 11 ++++--- UI/ShowDataLayer/TileHierarchyAggregator.ts | 11 +++++-- assets/themes/natuurpunt/natuurpunt.json | 5 ++-- 5 files changed, 43 insertions(+), 24 deletions(-) diff --git a/InitUiElements.ts b/InitUiElements.ts index e7113e2d68..59f56b849f 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -423,13 +423,13 @@ export class InitUiElements { flayers.push(flayer); } state.filteredLayers = new UIEventSource(flayers); - - + + const clustering = State.state.layoutToUse.clustering const clusterCounter = TileHierarchyAggregator.createHierarchy() new ShowDataLayer({ - features: clusterCounter.getCountsForZoom(State.state.locationControl, State.state.layoutToUse.clustering.minNeededElements), + features: clusterCounter.getCountsForZoom(clustering, State.state.locationControl, State.state.layoutToUse.clustering.minNeededElements), leafletMap: State.state.leafletMap, layerToShow: ShowTileInfo.styling, enablePopups: false @@ -440,7 +440,7 @@ export class InitUiElements { clusterCounter.addTile(source) - const clustering = State.state.layoutToUse.clustering + // Do show features indicates if the 'showDataLayer' should be shown const doShowFeatures = source.features.map( f => { const z = State.state.locationControl.data.zoom @@ -449,6 +449,18 @@ export class InitUiElements { return false; } + const bounds = State.state.currentBounds.data + if(bounds === undefined){ + // Map is not yet displayed + return false; + } + + if (!source.bbox.overlapsWith(bounds)) { + // Not within range -> features are hidden + return false + } + + if (z < source.layer.layerDef.minzoom) { // Layer is always hidden for this zoom level return false; @@ -473,21 +485,13 @@ export class InitUiElements { } if (clusterCounter.getTile(Tiles.tile_index(tileZ, tileX, tileY))?.totalValue > clustering.minNeededElements) { + // To much elements return false } } - const bounds = State.state.currentBounds.data - if(bounds === undefined){ - // Map is not yet displayed - return false; - } - if (!source.bbox.overlapsWith(bounds)) { - // Not within range - return false - } - + return true }, [State.state.currentBounds, source.layer.isDisplayed] ) diff --git a/Models/ThemeConfig/Json/LayoutConfigJson.ts b/Models/ThemeConfig/Json/LayoutConfigJson.ts index 89439f529b..64d6be83e2 100644 --- a/Models/ThemeConfig/Json/LayoutConfigJson.ts +++ b/Models/ThemeConfig/Json/LayoutConfigJson.ts @@ -237,6 +237,12 @@ export interface LayoutConfigJson { * If clustering is defined, defaults to 25 */ minNeededElements?: number + /** + * By default, a box is shown indicating the number of features even if the map is zoomed out beyond the minzoom of the layer. + * This flag switches this behaviour to not show these boxes. + */ + hideClustersAboveMinZoom?: boolean; + }, /** @@ -253,7 +259,7 @@ export interface LayoutConfigJson { * If set to [[lat0, lon0], [lat1, lon1]], the map will not scroll outside of those bounds. * Off by default, which will enable panning to the entire world */ - lockLocation?: boolean | [[number, number], [number, number]]; + lockLocation?: boolean | [[number, number], [number, number]] | number[][]; enableUserBadge?: boolean; enableShareScreen?: boolean; diff --git a/Models/ThemeConfig/LayoutConfig.ts b/Models/ThemeConfig/LayoutConfig.ts index 9add1c7f92..fbfc924f7c 100644 --- a/Models/ThemeConfig/LayoutConfig.ts +++ b/Models/ThemeConfig/LayoutConfig.ts @@ -30,7 +30,8 @@ export default class LayoutConfig { public layers: LayerConfig[]; public readonly clustering?: { maxZoom: number, - minNeededElements: number + minNeededElements: number, + hideClustersAboveMinzoom: boolean }; public readonly hideFromOverview: boolean; public lockLocation: boolean | [[number, number], [number, number]]; @@ -139,12 +140,14 @@ export default class LayoutConfig { this.clustering = { maxZoom: 16, - minNeededElements: 25 + minNeededElements: 25, + hideClustersAboveMinzoom: false }; if (json.clustering) { this.clustering = { maxZoom: json.clustering.maxZoom ?? 18, - minNeededElements: json.clustering.minNeededElements ?? 25 + minNeededElements: json.clustering.minNeededElements ?? 25, + hideClustersAboveMinzoom: json.clustering.hideClustersAboveMinZoom ?? false } } @@ -153,7 +156,7 @@ export default class LayoutConfig { if (json.hideInOverview) { throw "The json for " + this.id + " contains a 'hideInOverview'. Did you mean hideFromOverview instead?" } - this.lockLocation = json.lockLocation ?? undefined; + this.lockLocation = <[[number, number], [number, number]]> json.lockLocation ?? undefined; this.enableUserBadge = json.enableUserBadge ?? true; this.enableShareScreen = json.enableShareScreen ?? true; this.enableMoreQuests = json.enableMoreQuests ?? true; diff --git a/UI/ShowDataLayer/TileHierarchyAggregator.ts b/UI/ShowDataLayer/TileHierarchyAggregator.ts index 4b1685981d..e1d934a95e 100644 --- a/UI/ShowDataLayer/TileHierarchyAggregator.ts +++ b/UI/ShowDataLayer/TileHierarchyAggregator.ts @@ -153,13 +153,18 @@ export class TileHierarchyAggregator implements FeatureSource { } } - getCountsForZoom(locationControl: UIEventSource<{ zoom : number }>, cutoff: number = 0) : FeatureSource{ + getCountsForZoom(clusteringConfig: {maxZoom: number}, locationControl: UIEventSource<{ zoom : number }>, cutoff: number = 0) : FeatureSource{ const self = this - + const empty = [] return new StaticFeatureSource( locationControl.map(loc => { - const features = [] const targetZoom = loc.zoom + + if(targetZoom > clusteringConfig.maxZoom){ + return empty + } + + const features = [] self.visitSubTiles(aggr => { if(aggr.totalValue < cutoff) { return false diff --git a/assets/themes/natuurpunt/natuurpunt.json b/assets/themes/natuurpunt/natuurpunt.json index fb45742cae..0090eb2373 100644 --- a/assets/themes/natuurpunt/natuurpunt.json +++ b/assets/themes/natuurpunt/natuurpunt.json @@ -34,7 +34,8 @@ "hideFromOverview": true, "clustering": { "#": "Disable clustering for this theme", - "maxZoom": 1 + "maxZoom": 1, + "hideBoxesAboveMinZoom": true }, "layers": [ { @@ -109,7 +110,7 @@ ] }, "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", - "geoJsonZoomLevel": 12, + "geoJsonZoomLevel": 10, "isOsmCache": true }, "minzoom": "13", From 8f674b7976fca2b8db70040c93b2ec09d9a7255d Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 13 Oct 2021 01:28:20 +0200 Subject: [PATCH 28/29] Improvents to caching script --- scripts/generateCache.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/generateCache.ts b/scripts/generateCache.ts index d92fc86288..c7fc2f04be 100644 --- a/scripts/generateCache.ts +++ b/scripts/generateCache.ts @@ -74,6 +74,7 @@ async function downloadRaw(targetdir: string, r: TileRange, theme: LayoutConfig, let downloaded = 0 let failed = 0 let skipped = 0 + const startTime = new Date().getTime() for (let x = r.xstart; x <= r.xend; x++) { for (let y = r.ystart; y <= r.yend; y++) { downloaded++; @@ -83,7 +84,11 @@ async function downloadRaw(targetdir: string, r: TileRange, theme: LayoutConfig, skipped++ continue; } - console.log("x:", (x - r.xstart), "/", (r.xend - r.xstart), "; y:", (y - r.ystart), "/", (r.yend - r.ystart), "; total: ", downloaded, "/", r.total, "failed: ", failed, "skipped: ", skipped) + const runningSeconds = (new Date().getTime() - startTime) / 1000 + const resting = failed + (r.total - downloaded) + const perTile= (runningSeconds / (downloaded - skipped)) + const estimated =Math.floor(resting * perTile) + console.log("total: ", downloaded, "/", r.total, "failed: ", failed, "skipped: ", skipped, "running time: ",Utils.toHumanTime(runningSeconds)+"s", "estimated left: ", Utils.toHumanTime(estimated), "("+Math.floor(perTile)+"s/tile)") const boundsArr = Tiles.tile_bounds(r.zoomlevel, x, y) const bounds = { @@ -92,7 +97,7 @@ async function downloadRaw(targetdir: string, r: TileRange, theme: LayoutConfig, east: Math.max(boundsArr[0][1], boundsArr[1][1]), west: Math.min(boundsArr[0][1], boundsArr[1][1]) } - const overpass = createOverpassObject(theme, relationTracker, Constants.defaultOverpassUrls[(downloaded + failed) % Constants.defaultOverpassUrls.length]) + const overpass = createOverpassObject(theme, relationTracker, Constants.defaultOverpassUrls[(failed) % Constants.defaultOverpassUrls.length]) const url = overpass.buildQuery("[bbox:" + bounds.south + "," + bounds.west + "," + bounds.north + "," + bounds.east + "]") try { From adb36c2ffe2509784e484ab1d08a573595ed4d76 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 13 Oct 2021 01:28:46 +0200 Subject: [PATCH 29/29] Cluster styling tweaks, tweaks to NP --- Models/ThemeConfig/Json/LayoutConfigJson.ts | 7 ----- Models/ThemeConfig/LayoutConfig.ts | 10 ++++--- UI/ShowDataLayer/TileHierarchyAggregator.ts | 6 +++-- Utils.ts | 26 ++++++++++--------- .../layers/cluster_style/cluster_style.json | 4 +-- assets/themes/natuurpunt/natuurpunt.json | 9 +++---- 6 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Models/ThemeConfig/Json/LayoutConfigJson.ts b/Models/ThemeConfig/Json/LayoutConfigJson.ts index 64d6be83e2..408bc10098 100644 --- a/Models/ThemeConfig/Json/LayoutConfigJson.ts +++ b/Models/ThemeConfig/Json/LayoutConfigJson.ts @@ -1,6 +1,5 @@ import {TagRenderingConfigJson} from "./TagRenderingConfigJson"; import {LayerConfigJson} from "./LayerConfigJson"; -import UnitConfigJson from "./UnitConfigJson"; /** * Defines the entire theme. @@ -237,12 +236,6 @@ export interface LayoutConfigJson { * If clustering is defined, defaults to 25 */ minNeededElements?: number - /** - * By default, a box is shown indicating the number of features even if the map is zoomed out beyond the minzoom of the layer. - * This flag switches this behaviour to not show these boxes. - */ - hideClustersAboveMinZoom?: boolean; - }, /** diff --git a/Models/ThemeConfig/LayoutConfig.ts b/Models/ThemeConfig/LayoutConfig.ts index fbfc924f7c..a06e329523 100644 --- a/Models/ThemeConfig/LayoutConfig.ts +++ b/Models/ThemeConfig/LayoutConfig.ts @@ -31,7 +31,6 @@ export default class LayoutConfig { public readonly clustering?: { maxZoom: number, minNeededElements: number, - hideClustersAboveMinzoom: boolean }; public readonly hideFromOverview: boolean; public lockLocation: boolean | [[number, number], [number, number]]; @@ -141,13 +140,16 @@ export default class LayoutConfig { this.clustering = { maxZoom: 16, minNeededElements: 25, - hideClustersAboveMinzoom: false }; - if (json.clustering) { + if(json.clustering === false){ + this.clustering = { + maxZoom: 0, + minNeededElements: 100000, + }; + }else if (json.clustering) { this.clustering = { maxZoom: json.clustering.maxZoom ?? 18, minNeededElements: json.clustering.minNeededElements ?? 25, - hideClustersAboveMinzoom: json.clustering.hideClustersAboveMinZoom ?? false } } diff --git a/UI/ShowDataLayer/TileHierarchyAggregator.ts b/UI/ShowDataLayer/TileHierarchyAggregator.ts index e1d934a95e..cdaa5e4206 100644 --- a/UI/ShowDataLayer/TileHierarchyAggregator.ts +++ b/UI/ShowDataLayer/TileHierarchyAggregator.ts @@ -22,7 +22,7 @@ export class TileHierarchyAggregator implements FeatureSource { public readonly name; private readonly featuresStatic = [] - private readonly featureProperties: { count: string, tileId: string, id: string }; + private readonly featureProperties: { count: string, kilocount: string, tileId: string, id: string }; private constructor(parent: TileHierarchyAggregator, z: number, x: number, y: number) { this._parent = parent; @@ -36,7 +36,8 @@ export class TileHierarchyAggregator implements FeatureSource { const totals = { id: ""+this._tileIndex, tileId: ""+this._tileIndex, - count: ""+0 + count: `0`, + kilocount: "0" } this.featureProperties = totals @@ -108,6 +109,7 @@ export class TileHierarchyAggregator implements FeatureSource { this.features.setData(TileHierarchyAggregator.empty) } else { this.featureProperties.count = "" + total; + this.featureProperties.kilocount = "" +Math.floor(total/1000); this.features.data = this.featuresStatic this.features.ping() } diff --git a/Utils.ts b/Utils.ts index 5c04c95472..0d88048c46 100644 --- a/Utils.ts +++ b/Utils.ts @@ -78,18 +78,6 @@ export class Utils { return res; } - static DoEvery(millis: number, f: (() => void)) { - if (Utils.runningFromConsole) { - return; - } - window.setTimeout( - function () { - f(); - Utils.DoEvery(millis, f); - } - , millis) - } - public static NoNull(array: T[]): T[] { const ls: T[] = []; for (const t of array) { @@ -440,5 +428,19 @@ export class Utils { window.setTimeout(resolve, timeMillis); }) } + + public static toHumanTime(seconds): string{ + seconds = Math.floor(seconds) + let minutes = Math.floor(seconds / 60) + seconds = seconds % 60 + let hours = Math.floor(minutes / 60) + minutes = minutes % 60 + let days = Math.floor(hours / 24) + hours = hours % 24 + if(days > 0){ + return days+"days"+" "+hours+"h" + } + return hours+":"+Utils.TwoDigits(minutes)+":"+Utils.TwoDigits(seconds) + } } diff --git a/assets/layers/cluster_style/cluster_style.json b/assets/layers/cluster_style/cluster_style.json index d6b68d1133..982baa79bb 100644 --- a/assets/layers/cluster_style/cluster_style.json +++ b/assets/layers/cluster_style/cluster_style.json @@ -28,8 +28,8 @@ "render": "
{count}
", "mappings": [ { - "if": "count>99", - "then": "
>99
" + "if": "count>1000", + "then": "
{kilocount}K
" } ] } diff --git a/assets/themes/natuurpunt/natuurpunt.json b/assets/themes/natuurpunt/natuurpunt.json index 0090eb2373..54effec905 100644 --- a/assets/themes/natuurpunt/natuurpunt.json +++ b/assets/themes/natuurpunt/natuurpunt.json @@ -32,10 +32,9 @@ "enablePdfDownload": true, "enableDownload": true, "hideFromOverview": true, - "clustering": { "#": "Disable clustering for this theme", - "maxZoom": 1, - "hideBoxesAboveMinZoom": true + "clustering": { + "maxZoom": 0 }, "layers": [ { @@ -110,10 +109,10 @@ ] }, "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", - "geoJsonZoomLevel": 10, + "geoJsonZoomLevel": 12, "isOsmCache": true }, - "minzoom": "13", + "minzoom": 10, "icon": { "render": "circle:#FE6F32;./assets/themes/natuurpunt/trail.svg", "mappings": [